@semiont/event-sourcing 0.2.34-build.91 → 0.2.34-build.92
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +17 -10
- package/dist/index.js +57 -44
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ResourceId, components, ResourceAnnotations, ResourceUri, AnnotationId, AnnotationUri, ResourceEvent, StoredEvent, EventQuery as EventQuery$1, EventBus as EventBus$1 } from '@semiont/core';
|
|
1
|
+
import { ResourceId, components, ResourceAnnotations, Logger, ResourceUri, AnnotationId, AnnotationUri, ResourceEvent, StoredEvent, EventQuery as EventQuery$1, EventBus as EventBus$1 } from '@semiont/core';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* View Storage - Materialized Views
|
|
@@ -23,7 +23,8 @@ interface ViewStorage {
|
|
|
23
23
|
}
|
|
24
24
|
declare class FilesystemViewStorage implements ViewStorage {
|
|
25
25
|
private basePath;
|
|
26
|
-
|
|
26
|
+
private logger?;
|
|
27
|
+
constructor(basePath: string, projectRoot?: string, logger?: Logger);
|
|
27
28
|
private getProjectionPath;
|
|
28
29
|
save(resourceId: ResourceId, projection: ResourceView): Promise<void>;
|
|
29
30
|
get(resourceId: ResourceId): Promise<ResourceView | null>;
|
|
@@ -88,9 +89,10 @@ interface EventStorageConfig {
|
|
|
88
89
|
*/
|
|
89
90
|
declare class EventStorage {
|
|
90
91
|
private config;
|
|
92
|
+
private logger?;
|
|
91
93
|
private resourceSequences;
|
|
92
94
|
private resourceLastHash;
|
|
93
|
-
constructor(config: EventStorageConfig);
|
|
95
|
+
constructor(config: EventStorageConfig, logger?: Logger);
|
|
94
96
|
/**
|
|
95
97
|
* Calculate shard path for a resource ID
|
|
96
98
|
* Uses jump consistent hash for uniform distribution
|
|
@@ -187,7 +189,7 @@ interface EventLogConfig {
|
|
|
187
189
|
}
|
|
188
190
|
declare class EventLog {
|
|
189
191
|
readonly storage: EventStorage;
|
|
190
|
-
constructor(config: EventLogConfig);
|
|
192
|
+
constructor(config: EventLogConfig, logger?: Logger);
|
|
191
193
|
/**
|
|
192
194
|
* Append event to log
|
|
193
195
|
* @param event - Resource event (from @semiont/core)
|
|
@@ -241,6 +243,8 @@ interface EventSubscription {
|
|
|
241
243
|
declare class EventSubscriptions {
|
|
242
244
|
private subscriptions;
|
|
243
245
|
private globalSubscriptions;
|
|
246
|
+
private logger?;
|
|
247
|
+
constructor(logger?: Logger);
|
|
244
248
|
/**
|
|
245
249
|
* Subscribe to events for a specific resource using full URI
|
|
246
250
|
* Returns an EventSubscription with unsubscribe function
|
|
@@ -277,7 +281,7 @@ declare class EventSubscriptions {
|
|
|
277
281
|
*/
|
|
278
282
|
getGlobalSubscriptionCount(): number;
|
|
279
283
|
}
|
|
280
|
-
declare function getEventSubscriptions(): EventSubscriptions;
|
|
284
|
+
declare function getEventSubscriptions(logger?: Logger): EventSubscriptions;
|
|
281
285
|
|
|
282
286
|
/**
|
|
283
287
|
* EventBus - Event Pub/Sub Layer
|
|
@@ -302,7 +306,8 @@ interface EventBusConfig {
|
|
|
302
306
|
declare class EventBus {
|
|
303
307
|
readonly subscriptions: EventSubscriptions;
|
|
304
308
|
private identifierConfig;
|
|
305
|
-
|
|
309
|
+
private logger?;
|
|
310
|
+
constructor(config: EventBusConfig, logger?: Logger);
|
|
306
311
|
/**
|
|
307
312
|
* Publish event to subscribers
|
|
308
313
|
* - Resource events: notifies BOTH resource-scoped AND global subscribers
|
|
@@ -371,7 +376,8 @@ interface ViewMaterializerConfig {
|
|
|
371
376
|
declare class ViewMaterializer {
|
|
372
377
|
private viewStorage;
|
|
373
378
|
private config;
|
|
374
|
-
|
|
379
|
+
private logger?;
|
|
380
|
+
constructor(viewStorage: ViewStorage, config: ViewMaterializerConfig, logger?: Logger);
|
|
375
381
|
/**
|
|
376
382
|
* Materialize resource view from events
|
|
377
383
|
* Loads existing view if cached, otherwise rebuilds from events
|
|
@@ -423,7 +429,7 @@ interface ViewManagerConfig {
|
|
|
423
429
|
*/
|
|
424
430
|
declare class ViewManager {
|
|
425
431
|
readonly materializer: ViewMaterializer;
|
|
426
|
-
constructor(viewStorage: ViewStorage, config: ViewManagerConfig);
|
|
432
|
+
constructor(viewStorage: ViewStorage, config: ViewManagerConfig, logger?: Logger);
|
|
427
433
|
/**
|
|
428
434
|
* Update resource view with a new event
|
|
429
435
|
* Falls back to full rebuild if view doesn't exist
|
|
@@ -471,7 +477,7 @@ declare class EventStore {
|
|
|
471
477
|
readonly views: ViewManager;
|
|
472
478
|
readonly viewStorage: ViewStorage;
|
|
473
479
|
readonly coreEventBus?: EventBus$1;
|
|
474
|
-
constructor(config: EventStorageConfig, viewStorage: ViewStorage, identifierConfig: IdentifierConfig, coreEventBus?: EventBus$1);
|
|
480
|
+
constructor(config: EventStorageConfig, viewStorage: ViewStorage, identifierConfig: IdentifierConfig, coreEventBus?: EventBus$1, logger?: Logger);
|
|
475
481
|
/**
|
|
476
482
|
* Append an event to the store
|
|
477
483
|
* Coordinates: persistence → view → notification
|
|
@@ -493,6 +499,7 @@ declare class EventStore {
|
|
|
493
499
|
* @param baseUrl - Base URL for generating identifiers (e.g., "http://localhost:8080")
|
|
494
500
|
* @param config - Optional additional storage configuration
|
|
495
501
|
* @param eventBus - Optional @semiont/core EventBus for publishing domain events
|
|
502
|
+
* @param logger - Optional logger for structured logging
|
|
496
503
|
* @returns Configured EventStore instance ready for use
|
|
497
504
|
*
|
|
498
505
|
* @example
|
|
@@ -510,7 +517,7 @@ declare class EventStore {
|
|
|
510
517
|
* });
|
|
511
518
|
* ```
|
|
512
519
|
*/
|
|
513
|
-
declare function createEventStore(basePath: string, baseUrl: string, config?: Partial<EventStorageConfig>, eventBus?: EventBus$1): EventStore;
|
|
520
|
+
declare function createEventStore(basePath: string, baseUrl: string, config?: Partial<EventStorageConfig>, eventBus?: EventBus$1, logger?: Logger): EventStore;
|
|
514
521
|
|
|
515
522
|
/**
|
|
516
523
|
* Sharding Utilities
|
package/dist/index.js
CHANGED
|
@@ -88,11 +88,13 @@ function sha256(data) {
|
|
|
88
88
|
// src/storage/event-storage.ts
|
|
89
89
|
var EventStorage = class {
|
|
90
90
|
config;
|
|
91
|
+
logger;
|
|
91
92
|
// Per-resource sequence tracking: resourceId -> sequence number
|
|
92
93
|
resourceSequences = /* @__PURE__ */ new Map();
|
|
93
94
|
// Per-resource last event hash: resourceId -> hash
|
|
94
95
|
resourceLastHash = /* @__PURE__ */ new Map();
|
|
95
|
-
constructor(config) {
|
|
96
|
+
constructor(config, logger) {
|
|
97
|
+
this.logger = logger;
|
|
96
98
|
this.config = {
|
|
97
99
|
basePath: config.basePath,
|
|
98
100
|
dataDir: config.dataDir,
|
|
@@ -141,7 +143,7 @@ var EventStorage = class {
|
|
|
141
143
|
const filePath = path.join(docPath, filename);
|
|
142
144
|
await promises.writeFile(filePath, "", "utf-8");
|
|
143
145
|
this.resourceSequences.set(resourceId, 0);
|
|
144
|
-
|
|
146
|
+
this.logger?.info("[EventStorage] Initialized event stream", { resourceId, path: docPath });
|
|
145
147
|
} else {
|
|
146
148
|
const files = await this.getEventFiles(resourceId);
|
|
147
149
|
if (files.length > 0) {
|
|
@@ -255,7 +257,7 @@ var EventStorage = class {
|
|
|
255
257
|
const event = JSON.parse(trimmed);
|
|
256
258
|
events.push(event);
|
|
257
259
|
} catch (parseError) {
|
|
258
|
-
|
|
260
|
+
this.logger?.error("[EventStorage] Failed to parse event", { filePath, error: parseError });
|
|
259
261
|
}
|
|
260
262
|
}
|
|
261
263
|
} catch (error) {
|
|
@@ -298,7 +300,7 @@ var EventStorage = class {
|
|
|
298
300
|
const docPath = this.getResourcePath(resourceId);
|
|
299
301
|
const filePath = path.join(docPath, filename);
|
|
300
302
|
await promises.writeFile(filePath, "", "utf-8");
|
|
301
|
-
|
|
303
|
+
this.logger?.info("[EventStorage] Created new event file", { filename, resourceId });
|
|
302
304
|
return filename;
|
|
303
305
|
}
|
|
304
306
|
/**
|
|
@@ -390,13 +392,13 @@ var EventStorage = class {
|
|
|
390
392
|
var EventLog = class {
|
|
391
393
|
// Expose storage for EventQuery (read operations)
|
|
392
394
|
storage;
|
|
393
|
-
constructor(config) {
|
|
395
|
+
constructor(config, logger) {
|
|
394
396
|
this.storage = new EventStorage({
|
|
395
397
|
basePath: config.basePath,
|
|
396
398
|
dataDir: config.dataDir,
|
|
397
399
|
enableSharding: config.enableSharding ?? true,
|
|
398
400
|
maxEventsPerFile: config.maxEventsPerFile ?? 1e4
|
|
399
|
-
});
|
|
401
|
+
}, logger?.child({ component: "EventStorage" }));
|
|
400
402
|
}
|
|
401
403
|
/**
|
|
402
404
|
* Append event to log
|
|
@@ -465,6 +467,10 @@ var EventSubscriptions = class {
|
|
|
465
467
|
subscriptions = /* @__PURE__ */ new Map();
|
|
466
468
|
// Global subscriptions for system-level events (no resourceId)
|
|
467
469
|
globalSubscriptions = /* @__PURE__ */ new Set();
|
|
470
|
+
logger;
|
|
471
|
+
constructor(logger) {
|
|
472
|
+
this.logger = logger;
|
|
473
|
+
}
|
|
468
474
|
/**
|
|
469
475
|
* Subscribe to events for a specific resource using full URI
|
|
470
476
|
* Returns an EventSubscription with unsubscribe function
|
|
@@ -475,16 +481,16 @@ var EventSubscriptions = class {
|
|
|
475
481
|
}
|
|
476
482
|
const callbacks = this.subscriptions.get(resourceUri2);
|
|
477
483
|
callbacks.add(callback);
|
|
478
|
-
|
|
484
|
+
this.logger?.info("[EventSubscriptions] Subscription added for resource", { resourceUri: resourceUri2, totalSubscribers: callbacks.size });
|
|
479
485
|
return {
|
|
480
486
|
resourceUri: resourceUri2,
|
|
481
487
|
callback,
|
|
482
488
|
unsubscribe: () => {
|
|
483
489
|
callbacks.delete(callback);
|
|
484
|
-
|
|
490
|
+
this.logger?.info("[EventSubscriptions] Subscription removed for resource", { resourceUri: resourceUri2, remainingSubscribers: callbacks.size });
|
|
485
491
|
if (callbacks.size === 0) {
|
|
486
492
|
this.subscriptions.delete(resourceUri2);
|
|
487
|
-
|
|
493
|
+
this.logger?.info("[EventSubscriptions] No more subscribers for resource, removed from subscriptions map", { resourceUri: resourceUri2 });
|
|
488
494
|
}
|
|
489
495
|
}
|
|
490
496
|
};
|
|
@@ -499,14 +505,14 @@ var EventSubscriptions = class {
|
|
|
499
505
|
*/
|
|
500
506
|
subscribeGlobal(callback) {
|
|
501
507
|
this.globalSubscriptions.add(callback);
|
|
502
|
-
|
|
508
|
+
this.logger?.info("[EventSubscriptions] Global subscription added", { totalSubscribers: this.globalSubscriptions.size });
|
|
503
509
|
return {
|
|
504
510
|
resourceUri: "__global__",
|
|
505
511
|
// Special marker for global subscriptions
|
|
506
512
|
callback,
|
|
507
513
|
unsubscribe: () => {
|
|
508
514
|
this.globalSubscriptions.delete(callback);
|
|
509
|
-
|
|
515
|
+
this.logger?.info("[EventSubscriptions] Global subscription removed", { remainingSubscribers: this.globalSubscriptions.size });
|
|
510
516
|
}
|
|
511
517
|
};
|
|
512
518
|
}
|
|
@@ -517,15 +523,15 @@ var EventSubscriptions = class {
|
|
|
517
523
|
async notifySubscribers(resourceUri2, event) {
|
|
518
524
|
const callbacks = this.subscriptions.get(resourceUri2);
|
|
519
525
|
if (!callbacks || callbacks.size === 0) {
|
|
520
|
-
|
|
526
|
+
this.logger?.info("[EventSubscriptions] Event - no subscribers to notify", { eventType: event.event.type, resourceUri: resourceUri2 });
|
|
521
527
|
return;
|
|
522
528
|
}
|
|
523
|
-
|
|
529
|
+
this.logger?.info("[EventSubscriptions] Notifying subscribers of event", { subscriberCount: callbacks.size, eventType: event.event.type, resourceUri: resourceUri2 });
|
|
524
530
|
Array.from(callbacks).forEach((callback, index) => {
|
|
525
531
|
Promise.resolve(callback(event)).then(() => {
|
|
526
|
-
|
|
532
|
+
this.logger?.info("[EventSubscriptions] Subscriber successfully notified", { subscriberIndex: index + 1, eventType: event.event.type });
|
|
527
533
|
}).catch((error) => {
|
|
528
|
-
|
|
534
|
+
this.logger?.error("[EventSubscriptions] Error in subscriber", { subscriberIndex: index + 1, resourceUri: resourceUri2, eventType: event.event.type, error });
|
|
529
535
|
});
|
|
530
536
|
});
|
|
531
537
|
}
|
|
@@ -534,15 +540,15 @@ var EventSubscriptions = class {
|
|
|
534
540
|
*/
|
|
535
541
|
async notifyGlobalSubscribers(event) {
|
|
536
542
|
if (this.globalSubscriptions.size === 0) {
|
|
537
|
-
|
|
543
|
+
this.logger?.info("[EventSubscriptions] System event - no global subscribers to notify", { eventType: event.event.type });
|
|
538
544
|
return;
|
|
539
545
|
}
|
|
540
|
-
|
|
546
|
+
this.logger?.info("[EventSubscriptions] Notifying global subscribers of system event", { subscriberCount: this.globalSubscriptions.size, eventType: event.event.type });
|
|
541
547
|
Array.from(this.globalSubscriptions).forEach((callback, index) => {
|
|
542
548
|
Promise.resolve(callback(event)).then(() => {
|
|
543
|
-
|
|
549
|
+
this.logger?.info("[EventSubscriptions] Global subscriber successfully notified", { subscriberIndex: index + 1, eventType: event.event.type });
|
|
544
550
|
}).catch((error) => {
|
|
545
|
-
|
|
551
|
+
this.logger?.error("[EventSubscriptions] Error in global subscriber", { subscriberIndex: index + 1, eventType: event.event.type, error });
|
|
546
552
|
});
|
|
547
553
|
});
|
|
548
554
|
}
|
|
@@ -570,10 +576,10 @@ var EventSubscriptions = class {
|
|
|
570
576
|
}
|
|
571
577
|
};
|
|
572
578
|
var globalEventSubscriptions = null;
|
|
573
|
-
function getEventSubscriptions() {
|
|
579
|
+
function getEventSubscriptions(logger) {
|
|
574
580
|
if (!globalEventSubscriptions) {
|
|
575
|
-
globalEventSubscriptions = new EventSubscriptions();
|
|
576
|
-
|
|
581
|
+
globalEventSubscriptions = new EventSubscriptions(logger);
|
|
582
|
+
logger?.info("[EventSubscriptions] Created global singleton instance");
|
|
577
583
|
}
|
|
578
584
|
return globalEventSubscriptions;
|
|
579
585
|
}
|
|
@@ -583,9 +589,11 @@ var EventBus = class {
|
|
|
583
589
|
// Expose subscriptions for direct access (legacy compatibility)
|
|
584
590
|
subscriptions;
|
|
585
591
|
identifierConfig;
|
|
586
|
-
|
|
592
|
+
logger;
|
|
593
|
+
constructor(config, logger) {
|
|
587
594
|
this.identifierConfig = config.identifierConfig;
|
|
588
|
-
this.
|
|
595
|
+
this.logger = logger;
|
|
596
|
+
this.subscriptions = getEventSubscriptions(logger?.child({ component: "EventSubscriptions" }));
|
|
589
597
|
}
|
|
590
598
|
/**
|
|
591
599
|
* Publish event to subscribers
|
|
@@ -602,7 +610,7 @@ var EventBus = class {
|
|
|
602
610
|
await this.subscriptions.notifySubscribers(resourceUri2, event);
|
|
603
611
|
await this.subscriptions.notifyGlobalSubscribers(event);
|
|
604
612
|
} else {
|
|
605
|
-
|
|
613
|
+
this.logger?.warn("[EventBus] Event is neither resource nor system event", { eventType: event.event.type });
|
|
606
614
|
}
|
|
607
615
|
}
|
|
608
616
|
/**
|
|
@@ -668,10 +676,12 @@ var EventBus = class {
|
|
|
668
676
|
}
|
|
669
677
|
};
|
|
670
678
|
var ViewMaterializer = class {
|
|
671
|
-
constructor(viewStorage, config) {
|
|
679
|
+
constructor(viewStorage, config, logger) {
|
|
672
680
|
this.viewStorage = viewStorage;
|
|
673
681
|
this.config = config;
|
|
682
|
+
this.logger = logger;
|
|
674
683
|
}
|
|
684
|
+
logger;
|
|
675
685
|
/**
|
|
676
686
|
* Materialize resource view from events
|
|
677
687
|
* Loads existing view if cached, otherwise rebuilds from events
|
|
@@ -691,21 +701,21 @@ var ViewMaterializer = class {
|
|
|
691
701
|
* Falls back to full rebuild if view doesn't exist
|
|
692
702
|
*/
|
|
693
703
|
async materializeIncremental(resourceId, event, getAllEvents) {
|
|
694
|
-
|
|
704
|
+
this.logger?.info("[ViewMaterializer] Updating view for resource with event", { resourceId, eventType: event.type });
|
|
695
705
|
let view = await this.viewStorage.get(resourceId);
|
|
696
706
|
if (!view) {
|
|
697
|
-
|
|
707
|
+
this.logger?.info("[ViewMaterializer] No view found, rebuilding from scratch", { resourceId });
|
|
698
708
|
const events = await getAllEvents();
|
|
699
709
|
view = this.materializeFromEvents(events, resourceId);
|
|
700
710
|
} else {
|
|
701
|
-
|
|
711
|
+
this.logger?.info("[ViewMaterializer] Applying event incrementally to existing view", { resourceId, version: view.annotations.version });
|
|
702
712
|
this.applyEventToResource(view.resource, event);
|
|
703
713
|
this.applyEventToAnnotations(view.annotations, event);
|
|
704
714
|
view.annotations.version++;
|
|
705
715
|
view.annotations.updatedAt = event.timestamp;
|
|
706
716
|
}
|
|
707
717
|
await this.viewStorage.save(resourceId, view);
|
|
708
|
-
|
|
718
|
+
this.logger?.info("[ViewMaterializer] View saved", { resourceId, version: view.annotations.version, annotationCount: view.annotations.annotations.length });
|
|
709
719
|
}
|
|
710
720
|
/**
|
|
711
721
|
* Materialize view from event list (full rebuild)
|
|
@@ -897,12 +907,12 @@ var ViewMaterializer = class {
|
|
|
897
907
|
var ViewManager = class {
|
|
898
908
|
// Expose materializer for direct access to view methods
|
|
899
909
|
materializer;
|
|
900
|
-
constructor(viewStorage, config) {
|
|
910
|
+
constructor(viewStorage, config, logger) {
|
|
901
911
|
const materializerConfig = {
|
|
902
912
|
basePath: config.basePath,
|
|
903
913
|
backendUrl: config.backendUrl
|
|
904
914
|
};
|
|
905
|
-
this.materializer = new ViewMaterializer(viewStorage, materializerConfig);
|
|
915
|
+
this.materializer = new ViewMaterializer(viewStorage, materializerConfig, logger?.child({ component: "ViewMaterializer" }));
|
|
906
916
|
}
|
|
907
917
|
/**
|
|
908
918
|
* Update resource view with a new event
|
|
@@ -943,7 +953,7 @@ var EventStore = class {
|
|
|
943
953
|
views;
|
|
944
954
|
viewStorage;
|
|
945
955
|
coreEventBus;
|
|
946
|
-
constructor(config, viewStorage, identifierConfig, coreEventBus) {
|
|
956
|
+
constructor(config, viewStorage, identifierConfig, coreEventBus, logger) {
|
|
947
957
|
this.viewStorage = viewStorage;
|
|
948
958
|
this.coreEventBus = coreEventBus;
|
|
949
959
|
const logConfig = {
|
|
@@ -952,16 +962,16 @@ var EventStore = class {
|
|
|
952
962
|
enableSharding: config.enableSharding,
|
|
953
963
|
maxEventsPerFile: config.maxEventsPerFile
|
|
954
964
|
};
|
|
955
|
-
this.log = new EventLog(logConfig);
|
|
965
|
+
this.log = new EventLog(logConfig, logger?.child({ component: "EventLog" }));
|
|
956
966
|
const busConfig = {
|
|
957
967
|
identifierConfig
|
|
958
968
|
};
|
|
959
|
-
this.bus = new EventBus(busConfig);
|
|
969
|
+
this.bus = new EventBus(busConfig, logger?.child({ component: "EventBus" }));
|
|
960
970
|
const viewConfig = {
|
|
961
971
|
basePath: config.basePath,
|
|
962
972
|
backendUrl: identifierConfig.baseUrl
|
|
963
973
|
};
|
|
964
|
-
this.views = new ViewManager(viewStorage, viewConfig);
|
|
974
|
+
this.views = new ViewManager(viewStorage, viewConfig, logger?.child({ component: "ViewManager" }));
|
|
965
975
|
}
|
|
966
976
|
/**
|
|
967
977
|
* Append an event to the store
|
|
@@ -992,7 +1002,9 @@ var EventStore = class {
|
|
|
992
1002
|
};
|
|
993
1003
|
var FilesystemViewStorage = class {
|
|
994
1004
|
basePath;
|
|
995
|
-
|
|
1005
|
+
logger;
|
|
1006
|
+
constructor(basePath, projectRoot, logger) {
|
|
1007
|
+
this.logger = logger;
|
|
996
1008
|
if (path.isAbsolute(basePath)) {
|
|
997
1009
|
this.basePath = basePath;
|
|
998
1010
|
} else if (projectRoot) {
|
|
@@ -1021,12 +1033,12 @@ var FilesystemViewStorage = class {
|
|
|
1021
1033
|
return null;
|
|
1022
1034
|
}
|
|
1023
1035
|
if (error instanceof SyntaxError) {
|
|
1024
|
-
|
|
1025
|
-
|
|
1036
|
+
this.logger?.error("[ViewStorage] Corrupted view file detected", { resourceId, error: error.message });
|
|
1037
|
+
this.logger?.error("[ViewStorage] Deleting corrupted view file", { path: projPath });
|
|
1026
1038
|
try {
|
|
1027
1039
|
await promises.unlink(projPath);
|
|
1028
1040
|
} catch (unlinkError) {
|
|
1029
|
-
|
|
1041
|
+
this.logger?.error("[ViewStorage] Failed to delete corrupted file", { error: unlinkError });
|
|
1030
1042
|
}
|
|
1031
1043
|
return null;
|
|
1032
1044
|
}
|
|
@@ -1068,7 +1080,7 @@ var FilesystemViewStorage = class {
|
|
|
1068
1080
|
const view = JSON.parse(content);
|
|
1069
1081
|
views.push(view);
|
|
1070
1082
|
} catch (error) {
|
|
1071
|
-
|
|
1083
|
+
this.logger?.error("[ViewStorage] Failed to read view", { path: fullPath, error });
|
|
1072
1084
|
}
|
|
1073
1085
|
}
|
|
1074
1086
|
}
|
|
@@ -1085,7 +1097,7 @@ var FilesystemViewStorage = class {
|
|
|
1085
1097
|
};
|
|
1086
1098
|
|
|
1087
1099
|
// src/event-store-factory.ts
|
|
1088
|
-
function createEventStore(basePath, baseUrl, config, eventBus) {
|
|
1100
|
+
function createEventStore(basePath, baseUrl, config, eventBus, logger) {
|
|
1089
1101
|
if (!basePath) {
|
|
1090
1102
|
throw new Error("basePath is required to create EventStore");
|
|
1091
1103
|
}
|
|
@@ -1098,7 +1110,7 @@ function createEventStore(basePath, baseUrl, config, eventBus) {
|
|
|
1098
1110
|
const identifierConfig = {
|
|
1099
1111
|
baseUrl
|
|
1100
1112
|
};
|
|
1101
|
-
const viewStorage = new FilesystemViewStorage(basePath);
|
|
1113
|
+
const viewStorage = new FilesystemViewStorage(basePath, void 0, logger?.child({ component: "view-storage" }));
|
|
1102
1114
|
const dataDir = path.join(basePath, "events");
|
|
1103
1115
|
const eventStore = new EventStore(
|
|
1104
1116
|
{
|
|
@@ -1111,7 +1123,8 @@ function createEventStore(basePath, baseUrl, config, eventBus) {
|
|
|
1111
1123
|
},
|
|
1112
1124
|
viewStorage,
|
|
1113
1125
|
identifierConfig,
|
|
1114
|
-
eventBus
|
|
1126
|
+
eventBus,
|
|
1127
|
+
logger
|
|
1115
1128
|
);
|
|
1116
1129
|
return eventStore;
|
|
1117
1130
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../node_modules/uuid/dist/esm-node/rng.js","../../../node_modules/uuid/dist/esm-node/regex.js","../../../node_modules/uuid/dist/esm-node/validate.js","../../../node_modules/uuid/dist/esm-node/stringify.js","../../../node_modules/uuid/dist/esm-node/v4.js","../src/storage/shard-utils.ts","../src/storage/event-storage.ts","../src/event-log.ts","../src/identifier-utils.ts","../src/subscriptions/event-subscriptions.ts","../src/event-bus.ts","../src/views/view-materializer.ts","../src/view-manager.ts","../src/event-store.ts","../src/storage/view-storage.ts","../src/event-store-factory.ts","../src/query/event-query.ts","../src/validation/event-validator.ts"],"names":["fs","resourceId","makeResourceId","resourceUri","path2","path3","path4"],"mappings":"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","file":"index.js","sourcesContent":["import crypto from 'crypto';\nconst rnds8Pool = new Uint8Array(256); // # of random values to pre-allocate\n\nlet poolPtr = rnds8Pool.length;\nexport default function rng() {\n if (poolPtr > rnds8Pool.length - 16) {\n crypto.randomFillSync(rnds8Pool);\n poolPtr = 0;\n }\n\n return rnds8Pool.slice(poolPtr, poolPtr += 16);\n}","export default /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;","import REGEX from './regex.js';\n\nfunction validate(uuid) {\n return typeof uuid === 'string' && REGEX.test(uuid);\n}\n\nexport default validate;","import validate from './validate.js';\n/**\n * Convert array of 16 byte values to UUID string format of the form:\n * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX\n */\n\nconst byteToHex = [];\n\nfor (let i = 0; i < 256; ++i) {\n byteToHex.push((i + 0x100).toString(16).substr(1));\n}\n\nfunction stringify(arr, offset = 0) {\n // Note: Be careful editing this code! It's been tuned for performance\n // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434\n const uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); // Consistency check for valid UUID. If this throws, it's likely due to one\n // of the following:\n // - One or more input array values don't map to a hex octet (leading to\n // \"undefined\" in the uuid)\n // - Invalid input values for the RFC `version` or `variant` fields\n\n if (!validate(uuid)) {\n throw TypeError('Stringified UUID is invalid');\n }\n\n return uuid;\n}\n\nexport default stringify;","import rng from './rng.js';\nimport stringify from './stringify.js';\n\nfunction v4(options, buf, offset) {\n options = options || {};\n const rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`\n\n rnds[6] = rnds[6] & 0x0f | 0x40;\n rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided\n\n if (buf) {\n offset = offset || 0;\n\n for (let i = 0; i < 16; ++i) {\n buf[offset + i] = rnds[i];\n }\n\n return buf;\n }\n\n return stringify(rnds);\n}\n\nexport default v4;","/**\n * Sharding Utilities\n *\n * Shared utilities for consistent sharding across all storage layers\n * Uses Google's Jump Consistent Hash algorithm for even distribution\n */\n\nimport { createHash } from 'crypto';\n\n/**\n * TEMPORARY: Simple modulo-based hash sharding\n *\n * ⚠️ TODO: Replace with proper Jump Consistent Hash implementation\n *\n * This is a TEMPORARY implementation using simple modulo. It works and provides\n * good distribution, but does NOT provide the minimal reshuffling property of\n * Jump Consistent Hash when changing bucket counts.\n *\n * The proper implementation should use Google's Jump Consistent Hash algorithm:\n * Reference: \"A Fast, Minimal Memory, Consistent Hash Algorithm\" by Lamping & Veach (2014)\n * https://arxiv.org/abs/1406.2294\n *\n * Working implementations exist in npm packages like:\n * - jumphash (https://www.npmjs.com/package/jumphash)\n * - jump-gouache (https://github.com/bhoudu/jump-gouache)\n *\n * The algorithm requires proper 64-bit integer handling with BigInt to avoid\n * precision loss in JavaScript. The previous attempt failed due to incorrect\n * BigInt arithmetic in the while loop condition.\n *\n * Until replaced, this modulo approach will cause ALL data to be reshuffled\n * if bucket count changes, rather than the optimal O(n/k) reshuffling that\n * Jump Consistent Hash provides.\n *\n * @param key - The key to hash (typically a resource ID)\n * @param numBuckets - Number of shards/buckets (default: 65536 for 4-hex sharding)\n * @returns Shard number (0 to numBuckets-1)\n */\nexport function jumpConsistentHash(key: string, numBuckets: number = 65536): number {\n const hash = hashToUint32(key);\n return hash % numBuckets;\n}\n\n/**\n * Hash string to 32-bit unsigned integer\n */\nfunction hashToUint32(str: string): number {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n hash = ((hash << 5) - hash) + str.charCodeAt(i);\n hash = hash & 0xFFFFFFFF;\n }\n return Math.abs(hash);\n}\n\n/**\n * Convert shard number to 4-hex directory path (ab/cd)\n *\n * @param shardId - Shard number (0-65535)\n * @returns Path segments like ['ab', 'cd']\n */\nexport function shardIdToPath(shardId: number): [string, string] {\n if (shardId < 0 || shardId >= 65536) {\n throw new Error(`Invalid shard ID: ${shardId}. Must be 0-65535 for 4-hex sharding.`);\n }\n\n const shardHex = shardId.toString(16).padStart(4, '0');\n const ab = shardHex.substring(0, 2);\n const cd = shardHex.substring(2, 4);\n\n return [ab, cd];\n}\n\n/**\n * Get 4-hex shard path for a key\n *\n * @param key - The key to hash (typically a resource ID)\n * @param numBuckets - Number of shards (default: 65536)\n * @returns Path segments like ['ab', 'cd']\n */\nexport function getShardPath(key: string, numBuckets: number = 65536): [string, string] {\n const shardId = jumpConsistentHash(key, numBuckets);\n return shardIdToPath(shardId);\n}\n\n/**\n * Calculate SHA-256 hash of data\n */\nexport function sha256(data: string | object): string {\n const content = typeof data === 'string' ? data : JSON.stringify(data);\n return createHash('sha256').update(content).digest('hex');\n}","/**\n * Event Storage - Physical Storage Layer\n *\n * Handles file I/O operations for event storage:\n * - JSONL file writing/reading\n * - 4-hex sharding (65,536 shards)\n * - File rotation\n * - Event stream initialization\n *\n * @see docs/EVENT-STORE.md#eventstorage for architecture details\n */\n\nimport { promises as fs } from 'fs';\nimport * as path from 'path';\nimport { createReadStream } from 'fs';\nimport * as readline from 'readline';\nimport { v4 as uuidv4 } from 'uuid';\nimport type { StoredEvent, ResourceEvent, EventMetadata, ResourceId } from '@semiont/core';\nimport { resourceId as makeResourceId } from '@semiont/core';\nimport { jumpConsistentHash, sha256 } from './shard-utils';\n\nexport interface EventStorageConfig {\n basePath: string; // Base path (e.g., /data/uploads)\n dataDir: string; // Events directory (e.g., /data/uploads/events)\n maxEventsPerFile?: number; // File rotation threshold (default: 10000)\n enableSharding?: boolean; // Enable 4-hex sharding (default: true)\n numShards?: number; // Number of shards (default: 65536)\n enableCompression?: boolean; // Gzip rotated files (default: true)\n}\n\n/**\n * EventStorage handles physical storage of events\n * Owns: file I/O, sharding, AND sequence/hash tracking\n */\nexport class EventStorage {\n private config: Required<EventStorageConfig>;\n\n // Per-resource sequence tracking: resourceId -> sequence number\n private resourceSequences: Map<string, number> = new Map();\n // Per-resource last event hash: resourceId -> hash\n private resourceLastHash: Map<string, string> = new Map();\n\n constructor(config: EventStorageConfig) {\n this.config = {\n basePath: config.basePath,\n dataDir: config.dataDir,\n maxEventsPerFile: config.maxEventsPerFile || 10000,\n enableSharding: config.enableSharding ?? true,\n numShards: config.numShards || 65536,\n enableCompression: config.enableCompression ?? true,\n };\n }\n\n /**\n * Calculate shard path for a resource ID\n * Uses jump consistent hash for uniform distribution\n * Special case: __system__ events bypass sharding\n */\n getShardPath(resourceId: ResourceId): string {\n // System events don't get sharded\n if (resourceId === '__system__' || !this.config.enableSharding) {\n return '';\n }\n\n // Jump consistent hash for uniform shard distribution\n const shardIndex = jumpConsistentHash(resourceId, this.config.numShards);\n\n // Convert to 4-hex format (e.g., 0000, 0001, ..., ffff)\n const hex = shardIndex.toString(16).padStart(4, '0');\n const [ab, cd] = [hex.substring(0, 2), hex.substring(2, 4)];\n\n return path.join(ab, cd);\n }\n\n /**\n * Get full path to resource's event directory\n */\n getResourcePath(resourceId: ResourceId): string {\n const shardPath = this.getShardPath(resourceId);\n return path.join(this.config.dataDir, 'events', shardPath, resourceId);\n }\n\n /**\n * Initialize directory structure for a resource's event stream\n * Also loads sequence number and last hash if stream exists\n */\n async initializeResourceStream(resourceId: ResourceId): Promise<void> {\n const docPath = this.getResourcePath(resourceId);\n\n // Check if already initialized\n let exists = false;\n try {\n await fs.access(docPath);\n exists = true;\n } catch {\n // Doesn't exist, create it\n }\n\n if (!exists) {\n // Create directory structure\n await fs.mkdir(docPath, { recursive: true });\n\n // Create initial empty events file\n const filename = this.createEventFilename(1);\n const filePath = path.join(docPath, filename);\n await fs.writeFile(filePath, '', 'utf-8');\n\n // Initialize sequence number\n this.resourceSequences.set(resourceId, 0);\n\n console.log(`[EventStorage] Initialized event stream for ${resourceId} at ${docPath}`);\n } else {\n // Load existing sequence number and last hash\n const files = await this.getEventFiles(resourceId);\n if (files.length > 0) {\n const lastFile = files[files.length - 1];\n if (lastFile) {\n const lastEvent = await this.getLastEvent(resourceId, lastFile);\n if (lastEvent) {\n this.resourceSequences.set(resourceId, lastEvent.metadata.sequenceNumber);\n if (lastEvent.metadata.checksum) {\n this.resourceLastHash.set(resourceId, lastEvent.metadata.checksum);\n }\n }\n }\n } else {\n this.resourceSequences.set(resourceId, 0);\n }\n }\n }\n\n /**\n * Append an event - handles EVERYTHING for event creation\n * Creates ID, timestamp, metadata, checksum, sequence tracking, and writes to disk\n */\n async appendEvent(event: Omit<ResourceEvent, 'id' | 'timestamp'>, resourceId: ResourceId): Promise<StoredEvent> {\n // Ensure resource stream is initialized\n if (this.getSequenceNumber(resourceId) === 0) {\n await this.initializeResourceStream(resourceId);\n }\n\n // Create complete event with ID and timestamp\n const completeEvent: ResourceEvent = {\n ...event,\n id: uuidv4(),\n timestamp: new Date().toISOString(),\n } as ResourceEvent;\n\n // Calculate metadata\n const sequenceNumber = this.getNextSequenceNumber(resourceId);\n const prevEventHash = this.getLastEventHash(resourceId);\n\n const metadata: EventMetadata = {\n sequenceNumber,\n streamPosition: 0, // Will be set during write\n timestamp: new Date().toISOString(),\n prevEventHash: prevEventHash || undefined,\n checksum: sha256(completeEvent),\n };\n\n const storedEvent: StoredEvent = {\n event: completeEvent,\n metadata,\n };\n\n // Write to disk\n await this.writeEvent(storedEvent, resourceId);\n\n // Update last hash\n this.setLastEventHash(resourceId, metadata.checksum!);\n\n return storedEvent;\n }\n\n /**\n * Write an event to storage (append to JSONL)\n * Internal method - use appendEvent() instead\n */\n private async writeEvent(event: StoredEvent, resourceId: ResourceId): Promise<void> {\n const docPath = this.getResourcePath(resourceId);\n\n // Get current event files\n const files = await this.getEventFiles(resourceId);\n\n // Determine target file (rotate if needed)\n let targetFile: string;\n if (files.length === 0) {\n // No files yet - create first one\n targetFile = await this.createNewEventFile(resourceId);\n } else {\n const currentFile = files[files.length - 1];\n if (!currentFile) {\n // Shouldn't happen, but handle it\n targetFile = await this.createNewEventFile(resourceId);\n } else {\n const eventCount = await this.countEventsInFile(resourceId, currentFile);\n\n if (eventCount >= this.config.maxEventsPerFile) {\n // Rotate to new file\n targetFile = await this.createNewEventFile(resourceId);\n } else {\n targetFile = currentFile;\n }\n }\n }\n\n // Append event to file (JSONL format)\n const targetPath = path.join(docPath, targetFile);\n const eventLine = JSON.stringify(event) + '\\n';\n await fs.appendFile(targetPath, eventLine, 'utf-8');\n }\n\n /**\n * Count events in a specific file\n */\n async countEventsInFile(resourceId: ResourceId, filename: string): Promise<number> {\n const docPath = this.getResourcePath(resourceId);\n const filePath = path.join(docPath, filename);\n\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const lines = content.trim().split('\\n').filter(line => line.trim() !== '');\n return lines.length;\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n return 0;\n }\n throw error;\n }\n }\n\n /**\n * Read all events from a specific file\n */\n async readEventsFromFile(resourceId: ResourceId, filename: string): Promise<StoredEvent[]> {\n const docPath = this.getResourcePath(resourceId);\n const filePath = path.join(docPath, filename);\n\n const events: StoredEvent[] = [];\n\n try {\n const fileStream = createReadStream(filePath, { encoding: 'utf-8' });\n const rl = readline.createInterface({\n input: fileStream,\n crlfDelay: Infinity,\n });\n\n for await (const line of rl) {\n const trimmed = line.trim();\n if (trimmed === '') continue;\n\n try {\n const event = JSON.parse(trimmed) as StoredEvent;\n events.push(event);\n } catch (parseError) {\n console.error(`[EventStorage] Failed to parse event in ${filePath}:`, parseError);\n // Skip malformed lines\n }\n }\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n return []; // File doesn't exist\n }\n throw error;\n }\n\n return events;\n }\n\n /**\n * Get list of event files for a resource (sorted by sequence)\n */\n async getEventFiles(resourceId: ResourceId): Promise<string[]> {\n const docPath = this.getResourcePath(makeResourceId(resourceId));\n\n try {\n const files = await fs.readdir(docPath);\n\n // Filter to .jsonl files and sort by sequence number\n const eventFiles = files\n .filter(f => f.startsWith('events-') && f.endsWith('.jsonl'))\n .sort((a, b) => {\n const seqA = parseInt(a.match(/events-(\\d+)\\.jsonl/)?.[1] || '0');\n const seqB = parseInt(b.match(/events-(\\d+)\\.jsonl/)?.[1] || '0');\n return seqA - seqB;\n });\n\n return eventFiles;\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n return []; // Directory doesn't exist\n }\n throw error;\n }\n }\n\n /**\n * Create a new event file for rotation\n */\n async createNewEventFile(resourceId: ResourceId): Promise<string> {\n const files = await this.getEventFiles(resourceId);\n\n // Determine next sequence number\n const lastFile = files[files.length - 1];\n const lastSeq = lastFile ? parseInt(lastFile.match(/events-(\\d+)\\.jsonl/)?.[1] || '1') : 1;\n const newSeq = lastSeq + 1;\n\n // Create new file\n const filename = this.createEventFilename(newSeq);\n const docPath = this.getResourcePath(resourceId);\n const filePath = path.join(docPath, filename);\n\n await fs.writeFile(filePath, '', 'utf-8');\n\n console.log(`[EventStorage] Created new event file: ${filename} for ${resourceId}`);\n\n return filename;\n }\n\n /**\n * Get the last event from a specific file\n */\n async getLastEvent(resourceId: ResourceId, filename: string): Promise<StoredEvent | null> {\n const events = await this.readEventsFromFile(resourceId, filename);\n const lastEvent = events.length > 0 ? events[events.length - 1] : undefined;\n return lastEvent ?? null;\n }\n\n /**\n * Get all events for a resource across all files\n */\n async getAllEvents(resourceId: ResourceId): Promise<StoredEvent[]> {\n const files = await this.getEventFiles(resourceId);\n const allEvents: StoredEvent[] = [];\n\n for (const file of files) {\n const events = await this.readEventsFromFile(resourceId, file);\n allEvents.push(...events);\n }\n\n return allEvents;\n }\n\n /**\n * Get all resource IDs by scanning shard directories\n */\n async getAllResourceIds(): Promise<ResourceId[]> {\n const eventsDir = path.join(this.config.dataDir, 'events');\n const resourceIds: ResourceId[] = [];\n\n try {\n await fs.access(eventsDir);\n } catch {\n return []; // No events directory yet\n }\n\n // Recursively scan shard directories\n const scanDir = async (dir: string) => {\n const entries = await fs.readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n // Check if this looks like a resource ID (not a shard directory)\n // Shard directories are 2-char hex (00-ff), resource IDs are longer\n if (entry.name.length > 2) {\n resourceIds.push(makeResourceId(entry.name));\n } else {\n // Recurse into shard directory\n await scanDir(fullPath);\n }\n }\n }\n };\n\n await scanDir(eventsDir);\n return resourceIds;\n }\n\n /**\n * Create filename for event file\n */\n private createEventFilename(sequenceNumber: number): string {\n return `events-${sequenceNumber.toString().padStart(6, '0')}.jsonl`;\n }\n\n // ============================================================\n // Sequence/Hash Tracking\n // ============================================================\n\n /**\n * Get current sequence number for a resource\n */\n getSequenceNumber(resourceId: ResourceId): number {\n return this.resourceSequences.get(resourceId) || 0;\n }\n\n /**\n * Increment and return next sequence number for a resource\n */\n getNextSequenceNumber(resourceId: ResourceId): number {\n const current = this.getSequenceNumber(resourceId);\n const next = current + 1;\n this.resourceSequences.set(resourceId, next);\n return next;\n }\n\n /**\n * Get last event hash for a resource\n */\n getLastEventHash(resourceId: ResourceId): string | null {\n return this.resourceLastHash.get(resourceId) || null;\n }\n\n /**\n * Set last event hash for a resource\n */\n setLastEventHash(resourceId: ResourceId, hash: string): void {\n this.resourceLastHash.set(resourceId, hash);\n }\n}\n","/**\n * EventLog - Event Persistence Layer\n *\n * Single Responsibility: Event persistence only\n * - Appends events to storage (JSONL files)\n * - Retrieves events by resource\n * - Queries events with filters\n *\n * Does NOT handle:\n * - Pub/sub notifications (see EventBus)\n * - View updates (see ViewManager)\n */\n\nimport { type ResourceId, type StoredEvent, type ResourceEvent, type EventQuery } from '@semiont/core';\nimport { EventStorage } from './storage/event-storage';\n\nexport interface EventLogConfig {\n basePath: string;\n dataDir: string;\n enableSharding?: boolean;\n maxEventsPerFile?: number;\n}\n\nexport class EventLog {\n // Expose storage for EventQuery (read operations)\n readonly storage: EventStorage;\n\n constructor(config: EventLogConfig) {\n this.storage = new EventStorage({\n basePath: config.basePath,\n dataDir: config.dataDir,\n enableSharding: config.enableSharding ?? true,\n maxEventsPerFile: config.maxEventsPerFile ?? 10000,\n });\n }\n\n /**\n * Append event to log\n * @param event - Resource event (from @semiont/core)\n * @param resourceId - Branded ResourceId (from @semiont/core)\n * @returns Stored event with metadata (sequence number, timestamp, checksum)\n */\n async append(event: Omit<ResourceEvent, 'id' | 'timestamp'>, resourceId: ResourceId): Promise<StoredEvent> {\n return this.storage.appendEvent(event, resourceId);\n }\n\n /**\n * Get all events for a resource\n * @param resourceId - Branded ResourceId (from @semiont/core)\n */\n async getEvents(resourceId: ResourceId): Promise<StoredEvent[]> {\n return this.storage.getAllEvents(resourceId);\n }\n\n /**\n * Get all resource IDs\n * @returns Array of branded ResourceId types\n */\n async getAllResourceIds(): Promise<ResourceId[]> {\n return this.storage.getAllResourceIds();\n }\n\n /**\n * Query events with filter\n * @param resourceId - Branded ResourceId (from @semiont/core)\n * @param filter - Optional event filter\n */\n async queryEvents(resourceId: ResourceId, filter?: EventQuery): Promise<StoredEvent[]> {\n const events = await this.storage.getAllEvents(resourceId);\n if (!filter) return events;\n\n return events.filter(e => {\n if (filter.eventTypes && !filter.eventTypes.includes(e.event.type as any)) return false;\n if (filter.fromSequence && e.metadata.sequenceNumber < filter.fromSequence) return false;\n if (filter.fromTimestamp && e.event.timestamp < filter.fromTimestamp) return false;\n if (filter.toTimestamp && e.event.timestamp > filter.toTimestamp) return false;\n if (filter.userId && e.event.userId !== filter.userId) return false;\n return true;\n });\n }\n}\n","/**\n * Identifier conversion functions - Convert between short IDs and W3C-compliant HTTP URIs\n *\n * These functions handle the conversion between:\n * - Short IDs (e.g., \"abc123\") - used internally in events\n * - HTTP URIs (e.g., \"http://localhost:4000/resources/abc123\") - used in API responses\n *\n * The W3C Web Annotation Model requires HTTP(S) URIs for @id fields.\n *\n * All functions are pure - they take config explicitly as a parameter.\n */\n\nimport { nanoid } from 'nanoid';\nimport {\n type ResourceId,\n type AnnotationId,\n type ResourceUri,\n type AnnotationUri,\n resourceUri,\n annotationUri,\n} from '@semiont/core';\nimport type { IdentifierConfig } from './types';\n\n// Re-export IdentifierConfig for convenience\nexport type { IdentifierConfig };\n\n// Convert IDs to URIs\nexport function toResourceUri(\n config: IdentifierConfig,\n id: ResourceId\n): ResourceUri {\n if (!config.baseUrl) {\n throw new Error('baseUrl is required');\n }\n return resourceUri(`${config.baseUrl}/resources/${id}`);\n}\n\nexport function toAnnotationUri(\n config: IdentifierConfig,\n id: AnnotationId\n): AnnotationUri {\n if (!config.baseUrl) {\n throw new Error('baseUrl is required');\n }\n return annotationUri(`${config.baseUrl}/annotations/${id}`);\n}\n\n/**\n * Generate a unique annotation ID (W3C-compliant HTTP URI)\n * Moved from apps/backend/src/utils/id-generator.ts\n *\n * @param baseUrl - Base URL for the annotation service (e.g., \"http://localhost:8080\")\n * @returns A W3C-compliant annotation URI (e.g., \"http://localhost:8080/annotations/V1StGXR8_Z5jdHi6B-myT\")\n */\nexport function generateAnnotationId(baseUrl: string): string {\n if (!baseUrl) {\n throw new Error('baseUrl is required to generate annotation URIs');\n }\n // Remove trailing slash if present\n const normalizedBase = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;\n return `${normalizedBase}/annotations/${nanoid(21)}`;\n}\n","/**\n * Event Subscriptions - Real-time Event Pub/Sub\n *\n * Manages subscriptions for both resource-scoped and system-level events:\n * - Resource subscriptions: notifications for a specific resource's events\n * - Global subscriptions: notifications for all system-level events\n * - Fire-and-forget notification pattern (non-blocking)\n * - Automatic cleanup of empty subscription sets\n *\n * SINGLETON PATTERN: All EventStore instances share the same EventSubscriptions\n * to ensure SSE connections receive events from any EventStore instance.\n *\n * @see docs/EVENT-STORE.md#eventsubscriptions for architecture details\n */\n\nimport type { StoredEvent, ResourceUri } from '@semiont/core';\n\nexport type EventCallback = (event: StoredEvent) => void | Promise<void>;\n\nexport interface EventSubscription {\n resourceUri: ResourceUri;\n callback: EventCallback;\n unsubscribe: () => void;\n}\n\n/**\n * EventSubscriptions manages real-time event pub/sub\n * Supports both resource-scoped and global subscriptions\n */\nexport class EventSubscriptions {\n // Per-resource subscriptions: ResourceUri -> Set of callbacks\n private subscriptions: Map<ResourceUri, Set<EventCallback>> = new Map();\n // Global subscriptions for system-level events (no resourceId)\n private globalSubscriptions: Set<EventCallback> = new Set();\n\n /**\n * Subscribe to events for a specific resource using full URI\n * Returns an EventSubscription with unsubscribe function\n */\n subscribe(resourceUri: ResourceUri, callback: EventCallback): EventSubscription {\n if (!this.subscriptions.has(resourceUri)) {\n this.subscriptions.set(resourceUri, new Set());\n }\n\n const callbacks = this.subscriptions.get(resourceUri)!;\n callbacks.add(callback);\n\n console.log(`[EventSubscriptions] Subscription added for resource ${resourceUri} (total: ${callbacks.size} subscribers)`);\n\n return {\n resourceUri,\n callback,\n unsubscribe: () => {\n callbacks.delete(callback);\n console.log(`[EventSubscriptions] Subscription removed for resource ${resourceUri} (remaining: ${callbacks.size} subscribers)`);\n if (callbacks.size === 0) {\n this.subscriptions.delete(resourceUri);\n console.log(`[EventSubscriptions] No more subscribers for resource ${resourceUri}, removed from subscriptions map`);\n }\n }\n };\n }\n\n /**\n * Subscribe to all system-level events (no resourceId)\n * Returns an EventSubscription with unsubscribe function\n *\n * Use this for consumers that need to react to global events like:\n * - entitytype.added (global entity type collection changes)\n * - Future system-level events (user.created, workspace.created, etc.)\n */\n subscribeGlobal(callback: EventCallback): EventSubscription {\n this.globalSubscriptions.add(callback);\n\n console.log(`[EventSubscriptions] Global subscription added (total: ${this.globalSubscriptions.size} subscribers)`);\n\n return {\n resourceUri: '__global__' as ResourceUri, // Special marker for global subscriptions\n callback,\n unsubscribe: () => {\n this.globalSubscriptions.delete(callback);\n console.log(`[EventSubscriptions] Global subscription removed (remaining: ${this.globalSubscriptions.size} subscribers)`);\n }\n };\n }\n\n /**\n * Notify all subscribers for a resource when a new event is appended\n * @param resourceUri - Full resource URI (e.g., http://localhost:4000/resources/abc123)\n */\n async notifySubscribers(resourceUri: ResourceUri, event: StoredEvent): Promise<void> {\n const callbacks = this.subscriptions.get(resourceUri);\n if (!callbacks || callbacks.size === 0) {\n console.log(`[EventSubscriptions] Event ${event.event.type} for resource ${resourceUri} - no subscribers to notify`);\n return;\n }\n\n console.log(`[EventSubscriptions] Notifying ${callbacks.size} subscriber(s) of event ${event.event.type} for resource ${resourceUri}`);\n\n // Call all callbacks without waiting - fire and forget\n // Each callback handles its own errors and cleanup\n // This prevents slow/hanging callbacks from blocking event emission\n Array.from(callbacks).forEach((callback, index) => {\n Promise.resolve(callback(event))\n .then(() => {\n console.log(`[EventSubscriptions] Subscriber #${index + 1} successfully notified of ${event.event.type}`);\n })\n .catch((error: unknown) => {\n console.error(`[EventSubscriptions] Error in subscriber #${index + 1} for resource ${resourceUri}, event ${event.event.type}:`, error);\n });\n });\n }\n\n /**\n * Notify all global subscribers when a system-level event is appended\n */\n async notifyGlobalSubscribers(event: StoredEvent): Promise<void> {\n if (this.globalSubscriptions.size === 0) {\n console.log(`[EventSubscriptions] System event ${event.event.type} - no global subscribers to notify`);\n return;\n }\n\n console.log(`[EventSubscriptions] Notifying ${this.globalSubscriptions.size} global subscriber(s) of system event ${event.event.type}`);\n\n // Call all global callbacks without waiting - fire and forget\n // Each callback handles its own errors and cleanup\n // This prevents slow/hanging callbacks from blocking event emission\n Array.from(this.globalSubscriptions).forEach((callback, index) => {\n Promise.resolve(callback(event))\n .then(() => {\n console.log(`[EventSubscriptions] Global subscriber #${index + 1} successfully notified of ${event.event.type}`);\n })\n .catch((error: unknown) => {\n console.error(`[EventSubscriptions] Error in global subscriber #${index + 1} for system event ${event.event.type}:`, error);\n });\n });\n }\n\n /**\n * Get subscription count for a resource (useful for debugging)\n */\n getSubscriptionCount(resourceUri: ResourceUri): number {\n return this.subscriptions.get(resourceUri)?.size || 0;\n }\n\n /**\n * Get total number of active subscriptions across all resources\n */\n getTotalSubscriptions(): number {\n let total = 0;\n for (const callbacks of this.subscriptions.values()) {\n total += callbacks.size;\n }\n return total;\n }\n\n /**\n * Get total number of global subscriptions\n */\n getGlobalSubscriptionCount(): number {\n return this.globalSubscriptions.size;\n }\n}\n\n// Singleton instance - shared across all EventStore instances\n// This ensures SSE connections receive events from any EventStore instance\nlet globalEventSubscriptions: EventSubscriptions | null = null;\n\nexport function getEventSubscriptions(): EventSubscriptions {\n if (!globalEventSubscriptions) {\n globalEventSubscriptions = new EventSubscriptions();\n console.log('[EventSubscriptions] Created global singleton instance');\n }\n return globalEventSubscriptions;\n}\n","/**\n * EventBus - Event Pub/Sub Layer\n *\n * Single Responsibility: Event pub/sub only\n * - Publishes events to subscribers\n * - Manages subscriptions (resource-scoped and global)\n * - Converts ResourceId to ResourceUri internally\n *\n * Does NOT handle:\n * - Event persistence (see EventLog)\n * - View updates (see ViewManager)\n */\n\nimport { type StoredEvent, type ResourceId, isResourceEvent, isSystemEvent } from '@semiont/core';\nimport { toResourceUri, type IdentifierConfig } from './identifier-utils';\nimport { getEventSubscriptions, type EventSubscriptions, type EventCallback, type EventSubscription } from './subscriptions/event-subscriptions';\n\nexport interface EventBusConfig {\n identifierConfig: IdentifierConfig;\n}\n\n/**\n * EventBus wraps EventSubscriptions with a clean API\n * Handles ID-to-URI conversion internally for type safety\n */\nexport class EventBus {\n // Expose subscriptions for direct access (legacy compatibility)\n readonly subscriptions: EventSubscriptions;\n private identifierConfig: IdentifierConfig;\n\n constructor(config: EventBusConfig) {\n this.identifierConfig = config.identifierConfig;\n // Use global singleton EventSubscriptions to ensure all EventBus instances\n // share the same subscription registry (critical for SSE real-time events)\n this.subscriptions = getEventSubscriptions();\n }\n\n /**\n * Publish event to subscribers\n * - Resource events: notifies BOTH resource-scoped AND global subscribers\n * - System events: notifies global subscribers only\n * @param event - Stored event (from @semiont/core)\n */\n async publish(event: StoredEvent): Promise<void> {\n if (isSystemEvent(event.event)) {\n // System-level event - notify global subscribers\n await this.subscriptions.notifyGlobalSubscribers(event);\n } else if (isResourceEvent(event.event)) {\n // Resource event - notify BOTH resource-scoped AND global subscribers\n // This enables projections (graph, search, etc.) to use global subscription\n const resourceId = event.event.resourceId as ResourceId;\n const resourceUri = toResourceUri(this.identifierConfig, resourceId);\n await this.subscriptions.notifySubscribers(resourceUri, event);\n await this.subscriptions.notifyGlobalSubscribers(event);\n } else {\n // Shouldn't happen - events should be either resource or system\n console.warn('[EventBus] Event is neither resource nor system event:', (event.event as any).type);\n }\n }\n\n /**\n * Subscribe to events for a specific resource\n * @param resourceId - Branded ResourceId (from @semiont/core)\n * @param callback - Event callback function\n * @returns EventSubscription with unsubscribe function\n */\n subscribe(resourceId: ResourceId, callback: EventCallback): EventSubscription {\n const resourceUri = toResourceUri(this.identifierConfig, resourceId);\n return this.subscriptions.subscribe(resourceUri, callback);\n }\n\n /**\n * Subscribe to all system-level events\n * @param callback - Event callback function\n * @returns EventSubscription with unsubscribe function\n */\n subscribeGlobal(callback: EventCallback): EventSubscription {\n return this.subscriptions.subscribeGlobal(callback);\n }\n\n /**\n * Unsubscribe from resource events\n * @param resourceId - Branded ResourceId (from @semiont/core)\n * @param callback - Event callback function to remove\n */\n unsubscribe(resourceId: ResourceId, callback: EventCallback): void {\n const resourceUri = toResourceUri(this.identifierConfig, resourceId);\n const callbacks = (this.subscriptions as any).subscriptions.get(resourceUri);\n if (callbacks) {\n callbacks.delete(callback);\n if (callbacks.size === 0) {\n (this.subscriptions as any).subscriptions.delete(resourceUri);\n }\n }\n }\n\n /**\n * Unsubscribe from global events\n * @param callback - Event callback function to remove\n */\n unsubscribeGlobal(callback: EventCallback): void {\n (this.subscriptions as any).globalSubscriptions.delete(callback);\n }\n\n /**\n * Get subscriber count for a resource\n * @param resourceId - Branded ResourceId (from @semiont/core)\n * @returns Number of active subscribers\n */\n getSubscriberCount(resourceId: ResourceId): number {\n const resourceUri = toResourceUri(this.identifierConfig, resourceId);\n return this.subscriptions.getSubscriptionCount(resourceUri);\n }\n\n /**\n * Get total number of active subscriptions across all resources\n */\n getTotalSubscriptions(): number {\n return this.subscriptions.getTotalSubscriptions();\n }\n\n /**\n * Get total number of global subscriptions\n */\n getGlobalSubscriptionCount(): number {\n return this.subscriptions.getGlobalSubscriptionCount();\n }\n}\n","/**\n * View Materializer - Materialized View Management\n *\n * Materializes resource views from events:\n * - Full view materialization from scratch\n * - Incremental view updates\n * - System-level views (entity types)\n *\n * @see docs/EVENT-STORE.md#viewmaterializer for architecture details\n */\n\nimport { promises as fs } from 'fs';\nimport * as path from 'path';\nimport { didToAgent } from '@semiont/core';\nimport type { components } from '@semiont/core';\n\ntype Representation = components['schemas']['Representation'];\ntype Annotation = components['schemas']['Annotation'];\ntype ResourceDescriptor = components['schemas']['ResourceDescriptor'];\n\nimport type {\n ResourceEvent,\n StoredEvent,\n ResourceAnnotations,\n ResourceId,\n} from '@semiont/core';\nimport { findBodyItem } from '@semiont/core';\nimport type { ViewStorage, ResourceView } from '../storage/view-storage';\n\nexport interface ViewMaterializerConfig {\n basePath: string;\n backendUrl: string;\n}\n\n/**\n * ViewMaterializer builds and maintains materialized views from events\n */\nexport class ViewMaterializer {\n constructor(\n private viewStorage: ViewStorage,\n private config: ViewMaterializerConfig\n ) {}\n\n /**\n * Materialize resource view from events\n * Loads existing view if cached, otherwise rebuilds from events\n */\n async materialize(events: StoredEvent[], resourceId: ResourceId): Promise<ResourceView | null> {\n // Try to load existing view\n const existing = await this.viewStorage.get(resourceId);\n if (existing) {\n return existing;\n }\n\n // No view exists - rebuild from events\n if (events.length === 0) return null;\n\n const view = this.materializeFromEvents(events, resourceId);\n\n // Save rebuilt view\n await this.viewStorage.save(resourceId, view);\n\n return view;\n }\n\n /**\n * Materialize view incrementally with a single event\n * Falls back to full rebuild if view doesn't exist\n */\n async materializeIncremental(\n resourceId: ResourceId,\n event: ResourceEvent,\n getAllEvents: () => Promise<StoredEvent[]>\n ): Promise<void> {\n console.log(`[ViewMaterializer] Updating view for ${resourceId} with event ${event.type}`);\n\n // Try to load existing view\n let view = await this.viewStorage.get(resourceId);\n\n if (!view) {\n // No view exists - do full rebuild from all events\n console.log(`[ViewMaterializer] No view found, rebuilding from scratch`);\n const events = await getAllEvents();\n view = this.materializeFromEvents(events, resourceId);\n } else {\n // Apply single event incrementally to existing view\n console.log(`[ViewMaterializer] Applying event incrementally to existing view (version ${view.annotations.version})`);\n this.applyEventToResource(view.resource, event);\n this.applyEventToAnnotations(view.annotations, event);\n view.annotations.version++;\n view.annotations.updatedAt = event.timestamp;\n }\n\n // Save updated view\n await this.viewStorage.save(resourceId, view);\n console.log(`[ViewMaterializer] View saved (version ${view.annotations.version}, ${view.annotations.annotations.length} annotations)`);\n }\n\n /**\n * Materialize view from event list (full rebuild)\n */\n private materializeFromEvents(events: StoredEvent[], resourceId: ResourceId): ResourceView {\n // Build W3C-compliant HTTP URI for @id\n const backendUrl = this.config.backendUrl;\n const normalizedBase = backendUrl.endsWith('/') ? backendUrl.slice(0, -1) : backendUrl;\n\n // Start with empty ResourceDescriptor state\n const resource: ResourceDescriptor = {\n '@context': 'https://schema.org/',\n '@id': `${normalizedBase}/resources/${resourceId}`,\n name: '',\n representations: [],\n archived: false,\n entityTypes: [],\n creationMethod: 'api',\n };\n\n // Start with empty annotations\n const annotations: ResourceAnnotations = {\n resourceId,\n annotations: [],\n version: 0,\n updatedAt: '',\n };\n\n // Apply events in sequenceNumber order\n events.sort((a, b) => a.metadata.sequenceNumber - b.metadata.sequenceNumber);\n\n for (const storedEvent of events) {\n this.applyEventToResource(resource, storedEvent.event);\n this.applyEventToAnnotations(annotations, storedEvent.event);\n annotations.version++;\n annotations.updatedAt = storedEvent.event.timestamp;\n }\n\n return { resource, annotations };\n }\n\n /**\n * Apply an event to ResourceDescriptor state (metadata only)\n */\n private applyEventToResource(resource: ResourceDescriptor, event: ResourceEvent): void {\n switch (event.type) {\n case 'resource.created':\n resource.name = event.payload.name;\n resource.entityTypes = event.payload.entityTypes || [];\n resource.dateCreated = event.timestamp;\n resource.creationMethod = event.payload.creationMethod || 'api';\n resource.wasAttributedTo = didToAgent(event.userId);\n\n // Create representation from format and checksum\n if (!resource.representations) resource.representations = [];\n const reps = Array.isArray(resource.representations) ? resource.representations : [resource.representations];\n reps.push({\n mediaType: event.payload.format,\n checksum: event.payload.contentChecksum,\n byteSize: event.payload.contentByteSize,\n rel: 'original',\n language: event.payload.language,\n } as Representation);\n resource.representations = reps;\n\n // First-class fields\n resource.isDraft = event.payload.isDraft;\n resource.wasDerivedFrom = event.payload.generatedFrom;\n break;\n\n case 'resource.cloned':\n resource.name = event.payload.name;\n resource.entityTypes = event.payload.entityTypes || [];\n resource.dateCreated = event.timestamp;\n resource.creationMethod = 'clone';\n resource.sourceResourceId = event.payload.parentResourceId;\n resource.wasAttributedTo = didToAgent(event.userId);\n\n // Create representation from format and checksum\n if (!resource.representations) resource.representations = [];\n const reps2 = Array.isArray(resource.representations) ? resource.representations : [resource.representations];\n reps2.push({\n mediaType: event.payload.format,\n checksum: event.payload.contentChecksum,\n byteSize: event.payload.contentByteSize,\n rel: 'original',\n language: event.payload.language,\n } as Representation);\n resource.representations = reps2;\n break;\n\n case 'resource.archived':\n resource.archived = true;\n break;\n\n case 'resource.unarchived':\n resource.archived = false;\n break;\n\n case 'representation.added': {\n const { representation } = event.payload;\n\n // Add to representations array (avoid duplicates by checksum)\n if (!resource.representations) {\n resource.representations = [];\n }\n\n const repsArray = Array.isArray(resource.representations)\n ? resource.representations\n : [resource.representations];\n\n // Check if representation already exists\n const exists = repsArray.some(r => r.checksum === representation.checksum);\n if (!exists) {\n resource.representations = [...repsArray, representation];\n }\n break;\n }\n\n case 'representation.removed': {\n const { checksum } = event.payload;\n\n if (resource.representations) {\n const repsArray = Array.isArray(resource.representations)\n ? resource.representations\n : [resource.representations];\n\n resource.representations = repsArray.filter(r => r.checksum !== checksum);\n }\n break;\n }\n\n case 'entitytag.added':\n if (!resource.entityTypes) resource.entityTypes = [];\n if (!resource.entityTypes.includes(event.payload.entityType)) {\n resource.entityTypes.push(event.payload.entityType);\n }\n break;\n\n case 'entitytag.removed':\n if (resource.entityTypes) {\n resource.entityTypes = resource.entityTypes.filter(\n (t: string) => t !== event.payload.entityType\n );\n }\n break;\n\n // Annotation events don't affect resource metadata\n case 'annotation.added':\n case 'annotation.removed':\n case 'annotation.body.updated':\n break;\n\n // Job events don't affect resource metadata\n case 'job.started':\n case 'job.progress':\n case 'job.completed':\n case 'job.failed':\n break;\n\n // System events don't affect resource metadata\n case 'entitytype.added':\n break;\n }\n }\n\n /**\n * Apply an event to ResourceAnnotations (annotation collections only)\n */\n private applyEventToAnnotations(annotations: ResourceAnnotations, event: ResourceEvent): void {\n switch (event.type) {\n case 'annotation.added':\n // Event payload contains Omit<Annotation, 'creator' | 'created'> (includes @context and type)\n // Add creator/created from event metadata\n annotations.annotations.push({\n ...event.payload.annotation,\n creator: didToAgent(event.userId),\n created: new Date(event.timestamp).toISOString(),\n });\n break;\n\n case 'annotation.removed':\n // payload.annotationId is just the UUID, but a.id might be full URI or plain ID\n // Handle both: plain ID ('anno1') and full URI ('http://.../annotations/anno1')\n annotations.annotations = annotations.annotations.filter(\n (a: Annotation) => a.id !== event.payload.annotationId && !a.id.endsWith(`/annotations/${event.payload.annotationId}`)\n );\n break;\n\n case 'annotation.body.updated':\n // Find annotation by ID\n // payload.annotationId is just the UUID, but a.id might be full URI or plain ID\n // Handle both: plain ID ('anno1') and full URI ('http://.../annotations/anno1')\n const annotation = annotations.annotations.find((a: Annotation) =>\n a.id === event.payload.annotationId || a.id.endsWith(`/annotations/${event.payload.annotationId}`)\n );\n if (annotation) {\n // Ensure body is an array\n if (!Array.isArray(annotation.body)) {\n annotation.body = annotation.body ? [annotation.body] : [];\n }\n\n // Apply each operation\n for (const op of event.payload.operations) {\n if (op.op === 'add') {\n // Add item (idempotent - don't add if already exists)\n const exists = findBodyItem(annotation.body, op.item) !== -1;\n if (!exists) {\n annotation.body.push(op.item);\n }\n } else if (op.op === 'remove') {\n // Remove item\n const index = findBodyItem(annotation.body, op.item);\n if (index !== -1) {\n annotation.body.splice(index, 1);\n }\n } else if (op.op === 'replace') {\n // Replace item\n const index = findBodyItem(annotation.body, op.oldItem);\n if (index !== -1) {\n annotation.body[index] = op.newItem;\n }\n }\n }\n\n // Update modified timestamp\n annotation.modified = new Date(event.timestamp).toISOString();\n }\n break;\n\n // Resource metadata events don't affect annotations\n case 'resource.created':\n case 'resource.cloned':\n case 'resource.archived':\n case 'resource.unarchived':\n case 'representation.added':\n case 'representation.removed':\n case 'entitytag.added':\n case 'entitytag.removed':\n break;\n\n // Job events don't affect annotations\n case 'job.started':\n case 'job.progress':\n case 'job.completed':\n case 'job.failed':\n break;\n\n // System events don't affect annotations\n case 'entitytype.added':\n break;\n }\n }\n\n /**\n * Materialize entity types view - System-level view\n */\n async materializeEntityTypes(entityType: string): Promise<void> {\n const entityTypesPath = path.join(\n this.config.basePath,\n 'projections',\n '__system__',\n 'entitytypes.json'\n );\n\n\n // Read current view\n let view = { entityTypes: [] as string[] };\n try {\n const content = await fs.readFile(entityTypesPath, 'utf-8');\n view = JSON.parse(content);\n } catch (error: any) {\n if (error.code !== 'ENOENT') throw error;\n // File doesn't exist - will create it\n }\n\n // Add entity type (idempotent - Set ensures uniqueness)\n const entityTypeSet = new Set(view.entityTypes);\n entityTypeSet.add(entityType);\n view.entityTypes = Array.from(entityTypeSet).sort();\n\n // Write view\n await fs.mkdir(path.dirname(entityTypesPath), { recursive: true });\n await fs.writeFile(entityTypesPath, JSON.stringify(view, null, 2));\n }\n}\n","/**\n * ViewManager - Materialized View Management Layer\n *\n * Single Responsibility: View updates only\n * - Updates resource views from events\n * - Updates system views (entity types)\n * - Rebuilds views when needed\n *\n * Does NOT handle:\n * - Event persistence (see EventLog)\n * - Pub/sub notifications (see EventBus)\n */\n\nimport { type ResourceId, type ResourceEvent, type StoredEvent } from '@semiont/core';\nimport { ViewMaterializer, type ViewMaterializerConfig } from './views/view-materializer';\nimport type { ViewStorage, ResourceView } from './storage/view-storage';\n\nexport interface ViewManagerConfig {\n basePath: string;\n backendUrl: string;\n}\n\n/**\n * ViewManager wraps ViewMaterializer with a clean API\n * Handles both resource and system-level views\n */\nexport class ViewManager {\n // Expose materializer for direct access to view methods\n readonly materializer: ViewMaterializer;\n\n constructor(\n viewStorage: ViewStorage,\n config: ViewManagerConfig\n ) {\n const materializerConfig: ViewMaterializerConfig = {\n basePath: config.basePath,\n backendUrl: config.backendUrl,\n };\n this.materializer = new ViewMaterializer(viewStorage, materializerConfig);\n }\n\n /**\n * Update resource view with a new event\n * Falls back to full rebuild if view doesn't exist\n * @param resourceId - Branded ResourceId (from @semiont/core)\n * @param event - Resource event (from @semiont/core)\n * @param getAllEvents - Function to retrieve all events for rebuild if needed\n */\n async materializeResource(\n resourceId: ResourceId,\n event: ResourceEvent,\n getAllEvents: () => Promise<StoredEvent[]>\n ): Promise<void> {\n await this.materializer.materializeIncremental(resourceId, event, getAllEvents);\n }\n\n /**\n * Update system-level view (currently only entity types)\n * @param eventType - Type of system event\n * @param payload - Event payload\n */\n async materializeSystem(eventType: string, payload: any): Promise<void> {\n if (eventType === 'entitytype.added') {\n await this.materializer.materializeEntityTypes(payload.entityType);\n }\n // Future system views can be added here\n // e.g., user.created, workspace.created, etc.\n }\n\n /**\n * Get resource view (builds from events if needed)\n * @param resourceId - Branded ResourceId (from @semiont/core)\n * @param events - Stored events for the resource (from @semiont/core)\n * @returns Resource view or null if no events\n */\n async getOrMaterialize(\n resourceId: ResourceId,\n events: StoredEvent[]\n ): Promise<ResourceView | null> {\n return this.materializer.materialize(events, resourceId);\n }\n}\n","/**\n * EventStore - Orchestration Layer\n *\n * Coordinates event sourcing operations across 3 focused components:\n * - EventLog: Event persistence (append, retrieve, query)\n * - EventBus: Pub/sub notifications (publish, subscribe)\n * - ViewManager: View updates (resource and system)\n *\n * Thin coordination layer - delegates all work to specialized components.\n *\n * @see docs/EVENT-STORE.md for complete architecture documentation\n */\n\nimport type {\n ResourceEvent,\n StoredEvent,\n ResourceId,\n} from '@semiont/core';\nimport { EventBus as CoreEventBus } from '@semiont/core';\nimport type { ViewStorage } from './storage/view-storage';\nimport type { IdentifierConfig } from './identifier-utils';\n\n// Import focused components\nimport { EventLog, type EventLogConfig } from './event-log';\nimport { EventBus, type EventBusConfig } from './event-bus';\nimport { ViewManager, type ViewManagerConfig } from './view-manager';\nimport type { EventStorageConfig } from './storage/event-storage';\n\n/**\n * EventStore orchestrates event sourcing operations\n * Delegates to specialized components for focused functionality\n * NO state - just coordination between components\n */\nexport class EventStore {\n // Focused components - each with single responsibility\n readonly log: EventLog;\n readonly bus: EventBus;\n readonly views: ViewManager;\n readonly viewStorage: ViewStorage;\n readonly coreEventBus?: CoreEventBus;\n\n constructor(\n config: EventStorageConfig,\n viewStorage: ViewStorage,\n identifierConfig: IdentifierConfig,\n coreEventBus?: CoreEventBus\n ) {\n // Store viewStorage for direct access\n this.viewStorage = viewStorage;\n this.coreEventBus = coreEventBus;\n\n // Initialize focused components\n const logConfig: EventLogConfig = {\n basePath: config.basePath,\n dataDir: config.dataDir,\n enableSharding: config.enableSharding,\n maxEventsPerFile: config.maxEventsPerFile,\n };\n this.log = new EventLog(logConfig);\n\n const busConfig: EventBusConfig = {\n identifierConfig,\n };\n this.bus = new EventBus(busConfig);\n\n const viewConfig: ViewManagerConfig = {\n basePath: config.basePath,\n backendUrl: identifierConfig.baseUrl,\n };\n this.views = new ViewManager(viewStorage, viewConfig);\n }\n\n /**\n * Append an event to the store\n * Coordinates: persistence → view → notification\n */\n async appendEvent(event: Omit<ResourceEvent, 'id' | 'timestamp'>): Promise<StoredEvent> {\n // System-level events (entitytype.added) have no resourceId - use __system__\n const resourceId: ResourceId | '__system__' = event.resourceId || '__system__';\n\n // 1. Persist event to log\n const storedEvent = await this.log.append(event, resourceId as any);\n\n // 2. Update views\n if (resourceId === '__system__') {\n // System-level view (entity types, etc.)\n await this.views.materializeSystem(\n storedEvent.event.type,\n storedEvent.event.payload\n );\n } else {\n // Resource view\n await this.views.materializeResource(\n resourceId as ResourceId,\n storedEvent.event,\n () => this.log.getEvents(resourceId as ResourceId)\n );\n }\n\n // 3. Notify subscribers (legacy event bus)\n await this.bus.publish(storedEvent);\n\n // 4. Publish to @semiont/core EventBus if provided (domain events)\n if (this.coreEventBus && resourceId !== '__system__') {\n // Use resource-scoped bus for isolation\n const scopedBus = this.coreEventBus.scope(resourceId as string);\n // Publish domain event to generic 'make-meaning:event' channel\n scopedBus.get('make-meaning:event').next(storedEvent.event);\n }\n\n return storedEvent;\n }\n}\n","/**\n * View Storage - Materialized Views\n *\n * Stores materialized views of resource state and annotations\n * Built from event streams, can be rebuilt at any time\n *\n * Stores both ResourceDescriptor metadata and ResourceAnnotations, but keeps them logically separate\n */\n\nimport { promises as fs } from 'fs';\nimport * as path from 'path';\nimport { getShardPath } from './shard-utils';\nimport type { components } from '@semiont/core';\nimport type { ResourceAnnotations, ResourceId } from '@semiont/core';\n\ntype ResourceDescriptor = components['schemas']['ResourceDescriptor'];\n\n// Complete state for a resource in materialized view (metadata + annotations)\nexport interface ResourceView {\n resource: ResourceDescriptor;\n annotations: ResourceAnnotations;\n}\n\nexport interface ViewStorage {\n save(resourceId: ResourceId, view: ResourceView): Promise<void>;\n get(resourceId: ResourceId): Promise<ResourceView | null>;\n delete(resourceId: ResourceId): Promise<void>;\n exists(resourceId: ResourceId): Promise<boolean>;\n getAll(): Promise<ResourceView[]>;\n}\n\nexport class FilesystemViewStorage implements ViewStorage {\n private basePath: string;\n\n constructor(basePath: string, projectRoot?: string) {\n // If path is absolute, use it directly\n if (path.isAbsolute(basePath)) {\n this.basePath = basePath;\n }\n // If projectRoot provided, resolve relative paths against it\n else if (projectRoot) {\n this.basePath = path.resolve(projectRoot, basePath);\n }\n // Otherwise fall back to resolving against cwd (backward compat)\n else {\n this.basePath = path.resolve(basePath);\n }\n }\n\n private getProjectionPath(resourceId: ResourceId): string {\n // Use 4-hex Jump Consistent Hash sharding (65,536 shards)\n const [ab, cd] = getShardPath(resourceId);\n return path.join(this.basePath, 'projections', 'resources', ab, cd, `${resourceId}.json`);\n }\n\n async save(resourceId: ResourceId, projection: ResourceView): Promise<void> {\n const projPath = this.getProjectionPath(resourceId);\n const projDir = path.dirname(projPath);\n\n // Ensure shard directory exists\n await fs.mkdir(projDir, { recursive: true });\n\n // Write projection to file\n await fs.writeFile(projPath, JSON.stringify(projection, null, 2), 'utf-8');\n }\n\n async get(resourceId: ResourceId): Promise<ResourceView | null> {\n const projPath = this.getProjectionPath(resourceId);\n\n try {\n const content = await fs.readFile(projPath, 'utf-8');\n return JSON.parse(content) as ResourceView;\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n return null;\n }\n // Auto-delete corrupted view files (views are derived data, can be rebuilt from events)\n // This only handles JSON parsing errors, not broken event chains\n if (error instanceof SyntaxError) {\n console.error(`[ViewStorage] Corrupted view file detected for ${resourceId}: ${error.message}`);\n console.error(`[ViewStorage] Deleting corrupted view file: ${projPath}`);\n try {\n await fs.unlink(projPath);\n } catch (unlinkError) {\n console.error(`[ViewStorage] Failed to delete corrupted file:`, unlinkError);\n }\n return null;\n }\n throw error;\n }\n }\n\n async delete(resourceId: ResourceId): Promise<void> {\n const projPath = this.getProjectionPath(resourceId);\n\n try {\n await fs.unlink(projPath);\n } catch (error: any) {\n if (error.code !== 'ENOENT') {\n throw error;\n }\n // Ignore if file doesn't exist\n }\n }\n\n async exists(resourceId: ResourceId): Promise<boolean> {\n const projPath = this.getProjectionPath(resourceId);\n\n try {\n await fs.access(projPath);\n return true;\n } catch {\n return false;\n }\n }\n\n async getAll(): Promise<ResourceView[]> {\n const views: ResourceView[] = [];\n const annotationsPath = path.join(this.basePath, 'projections', 'resources');\n\n try {\n // Recursively walk through all shard directories\n const walkDir = async (dir: string): Promise<void> => {\n const entries = await fs.readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n await walkDir(fullPath);\n } else if (entry.isFile() && entry.name.endsWith('.json')) {\n try {\n const content = await fs.readFile(fullPath, 'utf-8');\n const view = JSON.parse(content) as ResourceView;\n views.push(view);\n } catch (error) {\n console.error(`[ViewStorage] Failed to read view ${fullPath}:`, error);\n // Skip invalid view files\n }\n }\n }\n };\n\n await walkDir(annotationsPath);\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n // Views directory doesn't exist yet\n return [];\n }\n throw error;\n }\n\n return views;\n }\n}","/**\n * Event Store Factory\n *\n * Factory function for creating EventStore instances with standard configuration.\n * This is the canonical way to instantiate an EventStore.\n */\n\nimport * as path from 'path';\nimport type { EventBus as CoreEventBus } from '@semiont/core';\nimport { EventStore } from './event-store';\nimport { FilesystemViewStorage } from './storage/view-storage';\nimport type { EventStorageConfig } from './storage/event-storage';\nimport type { IdentifierConfig } from './types';\n\n/**\n * Create and initialize an EventStore instance\n *\n * @param basePath - Absolute path to the data directory (must be resolved by caller)\n * @param baseUrl - Base URL for generating identifiers (e.g., \"http://localhost:8080\")\n * @param config - Optional additional storage configuration\n * @param eventBus - Optional @semiont/core EventBus for publishing domain events\n * @returns Configured EventStore instance ready for use\n *\n * @example\n * ```typescript\n * const eventStore = createEventStore(\n * '/absolute/path/to/data',\n * 'http://localhost:8080'\n * );\n * await eventStore.appendEvent({\n * type: 'resource.created',\n * resourceId: 'doc-123',\n * userId: 'user-456',\n * version: 1,\n * payload: { name: 'My Document' }\n * });\n * ```\n */\nexport function createEventStore(\n basePath: string,\n baseUrl: string,\n config?: Partial<EventStorageConfig>,\n eventBus?: CoreEventBus\n): EventStore {\n if (!basePath) {\n throw new Error('basePath is required to create EventStore');\n }\n if (!baseUrl) {\n throw new Error('baseUrl is required to create EventStore');\n }\n if (!path.isAbsolute(basePath)) {\n throw new Error('basePath must be an absolute path (use path.resolve() to convert relative paths)');\n }\n\n const identifierConfig: IdentifierConfig = {\n baseUrl,\n };\n\n // Create ViewStorage for materialized views\n // Structure: <basePath>/projections/resources/...\n const viewStorage = new FilesystemViewStorage(basePath);\n\n // Determine data directory for events\n // Structure: <basePath>/events/...\n const dataDir = path.join(basePath, 'events');\n\n const eventStore = new EventStore(\n {\n ...config,\n basePath,\n dataDir,\n enableSharding: true,\n numShards: 65536, // 4 hex digits (0000-ffff)\n },\n viewStorage,\n identifierConfig,\n eventBus\n );\n\n return eventStore;\n}\n","/**\n * Event Query - Read Operations\n *\n * Handles querying and reading events from storage:\n * - Query events with filters (type, user, timestamp, sequence)\n * - Get all events for a resource\n * - Get last event from a file\n * - Efficient streaming reads from JSONL files\n *\n * @see docs/EVENT-STORE.md#eventquery for architecture details\n */\n\nimport type { StoredEvent, EventQuery as EventQueryType, ResourceId } from '@semiont/core';\nimport type { EventStorage } from '../storage/event-storage';\n\n/**\n * EventQuery handles all read operations for events\n * Uses EventStorage for file access, adds query filtering\n */\nexport class EventQuery {\n constructor(private eventStorage: EventStorage) {}\n\n /**\n * Query events with filters\n * Supports filtering by: userId, eventTypes, timestamps, sequence number, limit\n */\n async queryEvents(query: EventQueryType): Promise<StoredEvent[]> {\n if (!query.resourceId) {\n throw new Error('resourceId is required for event queries');\n }\n\n // Get all events from storage\n const allEvents = await this.eventStorage.getAllEvents(query.resourceId);\n\n // Apply filters\n let results = allEvents;\n\n if (query.userId) {\n results = results.filter(e => e.event.userId === query.userId);\n }\n\n if (query.eventTypes && query.eventTypes.length > 0) {\n results = results.filter(e => query.eventTypes!.includes(e.event.type));\n }\n\n if (query.fromTimestamp) {\n results = results.filter(e => e.event.timestamp >= query.fromTimestamp!);\n }\n\n if (query.toTimestamp) {\n results = results.filter(e => e.event.timestamp <= query.toTimestamp!);\n }\n\n if (query.fromSequence) {\n results = results.filter(e => e.metadata.sequenceNumber >= query.fromSequence!);\n }\n\n // Apply limit\n if (query.limit && query.limit > 0) {\n results = results.slice(0, query.limit);\n }\n\n return results;\n }\n\n /**\n * Get all events for a specific resource (no filters)\n */\n async getResourceEvents(resourceId: ResourceId): Promise<StoredEvent[]> {\n return this.eventStorage.getAllEvents(resourceId);\n }\n\n /**\n * Get the last event from a specific file\n * Useful for initializing sequence numbers and last hashes\n */\n async getLastEvent(resourceId: ResourceId, filename: string): Promise<StoredEvent | null> {\n return this.eventStorage.getLastEvent(resourceId, filename);\n }\n\n /**\n * Get the latest event for a resource across all files\n */\n async getLatestEvent(resourceId: ResourceId): Promise<StoredEvent | null> {\n const files = await this.eventStorage.getEventFiles(resourceId);\n if (files.length === 0) return null;\n\n // Check files in reverse order (newest first)\n for (let i = files.length - 1; i >= 0; i--) {\n const file = files[i];\n if (!file) continue;\n const lastEvent = await this.eventStorage.getLastEvent(resourceId, file);\n if (lastEvent) return lastEvent;\n }\n\n return null;\n }\n\n /**\n * Get event count for a resource\n */\n async getEventCount(resourceId: ResourceId): Promise<number> {\n const events = await this.getResourceEvents(resourceId);\n return events.length;\n }\n\n /**\n * Check if a resource has any events\n */\n async hasEvents(resourceId: ResourceId): Promise<boolean> {\n const files = await this.eventStorage.getEventFiles(resourceId);\n return files.length > 0;\n }\n}\n","/**\n * Event Validator - Event Chain Integrity\n *\n * Validates event chain integrity using cryptographic hashing:\n * - prevEventHash links to previous event's checksum\n * - Each event's checksum is verified against its payload\n * - Detects broken chains and tampered events\n *\n * @see docs/EVENT-STORE.md#eventvalidator for architecture details\n */\n\nimport type { StoredEvent } from '@semiont/core';\nimport { sha256 } from '../storage/shard-utils';\n\nexport interface ValidationResult {\n valid: boolean;\n errors: string[];\n}\n\n/**\n * EventValidator verifies event chain integrity\n * Uses cryptographic checksums to detect broken chains or tampering\n */\nexport class EventValidator {\n /**\n * Validate event chain integrity for a resource's events\n * Checks that each event properly links to the previous event\n */\n validateEventChain(events: StoredEvent[]): ValidationResult {\n const errors: string[] = [];\n\n for (let i = 1; i < events.length; i++) {\n const prev = events[i - 1];\n const curr = events[i];\n\n if (!prev || !curr) continue;\n\n // Check prevEventHash points to previous event\n if (curr.metadata.prevEventHash !== prev.metadata.checksum) {\n errors.push(\n `Event chain broken at sequence ${curr.metadata.sequenceNumber}: ` +\n `prevEventHash=${curr.metadata.prevEventHash} but previous checksum=${prev.metadata.checksum}`\n );\n }\n\n // Verify checksum of current event\n const calculated = sha256(curr.event);\n if (calculated !== curr.metadata.checksum) {\n errors.push(\n `Checksum mismatch at sequence ${curr.metadata.sequenceNumber}: ` +\n `calculated=${calculated} but stored=${curr.metadata.checksum}`\n );\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n };\n }\n\n /**\n * Validate a single event's checksum\n * Useful for validating events before writing them\n */\n validateEventChecksum(event: StoredEvent): boolean {\n const calculated = sha256(event.event);\n return calculated === event.metadata.checksum;\n }\n\n /**\n * Validate that an event properly links to a previous event\n * Returns true if the link is valid or if this is the first event\n */\n validateEventLink(currentEvent: StoredEvent, previousEvent: StoredEvent | null): boolean {\n // First event in chain should have no prevEventHash\n if (!previousEvent) {\n return !currentEvent.metadata.prevEventHash;\n }\n\n // Subsequent events should link to previous event's checksum\n return currentEvent.metadata.prevEventHash === previousEvent.metadata.checksum;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../node_modules/uuid/dist/esm-node/rng.js","../../../node_modules/uuid/dist/esm-node/regex.js","../../../node_modules/uuid/dist/esm-node/validate.js","../../../node_modules/uuid/dist/esm-node/stringify.js","../../../node_modules/uuid/dist/esm-node/v4.js","../src/storage/shard-utils.ts","../src/storage/event-storage.ts","../src/event-log.ts","../src/identifier-utils.ts","../src/subscriptions/event-subscriptions.ts","../src/event-bus.ts","../src/views/view-materializer.ts","../src/view-manager.ts","../src/event-store.ts","../src/storage/view-storage.ts","../src/event-store-factory.ts","../src/query/event-query.ts","../src/validation/event-validator.ts"],"names":["fs","resourceId","makeResourceId","resourceUri","path2","path3","path4"],"mappings":"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","file":"index.js","sourcesContent":["import crypto from 'crypto';\nconst rnds8Pool = new Uint8Array(256); // # of random values to pre-allocate\n\nlet poolPtr = rnds8Pool.length;\nexport default function rng() {\n if (poolPtr > rnds8Pool.length - 16) {\n crypto.randomFillSync(rnds8Pool);\n poolPtr = 0;\n }\n\n return rnds8Pool.slice(poolPtr, poolPtr += 16);\n}","export default /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;","import REGEX from './regex.js';\n\nfunction validate(uuid) {\n return typeof uuid === 'string' && REGEX.test(uuid);\n}\n\nexport default validate;","import validate from './validate.js';\n/**\n * Convert array of 16 byte values to UUID string format of the form:\n * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX\n */\n\nconst byteToHex = [];\n\nfor (let i = 0; i < 256; ++i) {\n byteToHex.push((i + 0x100).toString(16).substr(1));\n}\n\nfunction stringify(arr, offset = 0) {\n // Note: Be careful editing this code! It's been tuned for performance\n // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434\n const uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); // Consistency check for valid UUID. If this throws, it's likely due to one\n // of the following:\n // - One or more input array values don't map to a hex octet (leading to\n // \"undefined\" in the uuid)\n // - Invalid input values for the RFC `version` or `variant` fields\n\n if (!validate(uuid)) {\n throw TypeError('Stringified UUID is invalid');\n }\n\n return uuid;\n}\n\nexport default stringify;","import rng from './rng.js';\nimport stringify from './stringify.js';\n\nfunction v4(options, buf, offset) {\n options = options || {};\n const rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`\n\n rnds[6] = rnds[6] & 0x0f | 0x40;\n rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided\n\n if (buf) {\n offset = offset || 0;\n\n for (let i = 0; i < 16; ++i) {\n buf[offset + i] = rnds[i];\n }\n\n return buf;\n }\n\n return stringify(rnds);\n}\n\nexport default v4;","/**\n * Sharding Utilities\n *\n * Shared utilities for consistent sharding across all storage layers\n * Uses Google's Jump Consistent Hash algorithm for even distribution\n */\n\nimport { createHash } from 'crypto';\n\n/**\n * TEMPORARY: Simple modulo-based hash sharding\n *\n * ⚠️ TODO: Replace with proper Jump Consistent Hash implementation\n *\n * This is a TEMPORARY implementation using simple modulo. It works and provides\n * good distribution, but does NOT provide the minimal reshuffling property of\n * Jump Consistent Hash when changing bucket counts.\n *\n * The proper implementation should use Google's Jump Consistent Hash algorithm:\n * Reference: \"A Fast, Minimal Memory, Consistent Hash Algorithm\" by Lamping & Veach (2014)\n * https://arxiv.org/abs/1406.2294\n *\n * Working implementations exist in npm packages like:\n * - jumphash (https://www.npmjs.com/package/jumphash)\n * - jump-gouache (https://github.com/bhoudu/jump-gouache)\n *\n * The algorithm requires proper 64-bit integer handling with BigInt to avoid\n * precision loss in JavaScript. The previous attempt failed due to incorrect\n * BigInt arithmetic in the while loop condition.\n *\n * Until replaced, this modulo approach will cause ALL data to be reshuffled\n * if bucket count changes, rather than the optimal O(n/k) reshuffling that\n * Jump Consistent Hash provides.\n *\n * @param key - The key to hash (typically a resource ID)\n * @param numBuckets - Number of shards/buckets (default: 65536 for 4-hex sharding)\n * @returns Shard number (0 to numBuckets-1)\n */\nexport function jumpConsistentHash(key: string, numBuckets: number = 65536): number {\n const hash = hashToUint32(key);\n return hash % numBuckets;\n}\n\n/**\n * Hash string to 32-bit unsigned integer\n */\nfunction hashToUint32(str: string): number {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n hash = ((hash << 5) - hash) + str.charCodeAt(i);\n hash = hash & 0xFFFFFFFF;\n }\n return Math.abs(hash);\n}\n\n/**\n * Convert shard number to 4-hex directory path (ab/cd)\n *\n * @param shardId - Shard number (0-65535)\n * @returns Path segments like ['ab', 'cd']\n */\nexport function shardIdToPath(shardId: number): [string, string] {\n if (shardId < 0 || shardId >= 65536) {\n throw new Error(`Invalid shard ID: ${shardId}. Must be 0-65535 for 4-hex sharding.`);\n }\n\n const shardHex = shardId.toString(16).padStart(4, '0');\n const ab = shardHex.substring(0, 2);\n const cd = shardHex.substring(2, 4);\n\n return [ab, cd];\n}\n\n/**\n * Get 4-hex shard path for a key\n *\n * @param key - The key to hash (typically a resource ID)\n * @param numBuckets - Number of shards (default: 65536)\n * @returns Path segments like ['ab', 'cd']\n */\nexport function getShardPath(key: string, numBuckets: number = 65536): [string, string] {\n const shardId = jumpConsistentHash(key, numBuckets);\n return shardIdToPath(shardId);\n}\n\n/**\n * Calculate SHA-256 hash of data\n */\nexport function sha256(data: string | object): string {\n const content = typeof data === 'string' ? data : JSON.stringify(data);\n return createHash('sha256').update(content).digest('hex');\n}","/**\n * Event Storage - Physical Storage Layer\n *\n * Handles file I/O operations for event storage:\n * - JSONL file writing/reading\n * - 4-hex sharding (65,536 shards)\n * - File rotation\n * - Event stream initialization\n *\n * @see docs/EVENT-STORE.md#eventstorage for architecture details\n */\n\nimport { promises as fs } from 'fs';\nimport * as path from 'path';\nimport { createReadStream } from 'fs';\nimport * as readline from 'readline';\nimport { v4 as uuidv4 } from 'uuid';\nimport type { StoredEvent, ResourceEvent, EventMetadata, ResourceId, Logger } from '@semiont/core';\nimport { resourceId as makeResourceId } from '@semiont/core';\nimport { jumpConsistentHash, sha256 } from './shard-utils';\n\nexport interface EventStorageConfig {\n basePath: string; // Base path (e.g., /data/uploads)\n dataDir: string; // Events directory (e.g., /data/uploads/events)\n maxEventsPerFile?: number; // File rotation threshold (default: 10000)\n enableSharding?: boolean; // Enable 4-hex sharding (default: true)\n numShards?: number; // Number of shards (default: 65536)\n enableCompression?: boolean; // Gzip rotated files (default: true)\n}\n\n/**\n * EventStorage handles physical storage of events\n * Owns: file I/O, sharding, AND sequence/hash tracking\n */\nexport class EventStorage {\n private config: Required<EventStorageConfig>;\n private logger?: Logger;\n\n // Per-resource sequence tracking: resourceId -> sequence number\n private resourceSequences: Map<string, number> = new Map();\n // Per-resource last event hash: resourceId -> hash\n private resourceLastHash: Map<string, string> = new Map();\n\n constructor(config: EventStorageConfig, logger?: Logger) {\n this.logger = logger;\n this.config = {\n basePath: config.basePath,\n dataDir: config.dataDir,\n maxEventsPerFile: config.maxEventsPerFile || 10000,\n enableSharding: config.enableSharding ?? true,\n numShards: config.numShards || 65536,\n enableCompression: config.enableCompression ?? true,\n };\n }\n\n /**\n * Calculate shard path for a resource ID\n * Uses jump consistent hash for uniform distribution\n * Special case: __system__ events bypass sharding\n */\n getShardPath(resourceId: ResourceId): string {\n // System events don't get sharded\n if (resourceId === '__system__' || !this.config.enableSharding) {\n return '';\n }\n\n // Jump consistent hash for uniform shard distribution\n const shardIndex = jumpConsistentHash(resourceId, this.config.numShards);\n\n // Convert to 4-hex format (e.g., 0000, 0001, ..., ffff)\n const hex = shardIndex.toString(16).padStart(4, '0');\n const [ab, cd] = [hex.substring(0, 2), hex.substring(2, 4)];\n\n return path.join(ab, cd);\n }\n\n /**\n * Get full path to resource's event directory\n */\n getResourcePath(resourceId: ResourceId): string {\n const shardPath = this.getShardPath(resourceId);\n return path.join(this.config.dataDir, 'events', shardPath, resourceId);\n }\n\n /**\n * Initialize directory structure for a resource's event stream\n * Also loads sequence number and last hash if stream exists\n */\n async initializeResourceStream(resourceId: ResourceId): Promise<void> {\n const docPath = this.getResourcePath(resourceId);\n\n // Check if already initialized\n let exists = false;\n try {\n await fs.access(docPath);\n exists = true;\n } catch {\n // Doesn't exist, create it\n }\n\n if (!exists) {\n // Create directory structure\n await fs.mkdir(docPath, { recursive: true });\n\n // Create initial empty events file\n const filename = this.createEventFilename(1);\n const filePath = path.join(docPath, filename);\n await fs.writeFile(filePath, '', 'utf-8');\n\n // Initialize sequence number\n this.resourceSequences.set(resourceId, 0);\n\n this.logger?.info('[EventStorage] Initialized event stream', { resourceId, path: docPath });\n } else {\n // Load existing sequence number and last hash\n const files = await this.getEventFiles(resourceId);\n if (files.length > 0) {\n const lastFile = files[files.length - 1];\n if (lastFile) {\n const lastEvent = await this.getLastEvent(resourceId, lastFile);\n if (lastEvent) {\n this.resourceSequences.set(resourceId, lastEvent.metadata.sequenceNumber);\n if (lastEvent.metadata.checksum) {\n this.resourceLastHash.set(resourceId, lastEvent.metadata.checksum);\n }\n }\n }\n } else {\n this.resourceSequences.set(resourceId, 0);\n }\n }\n }\n\n /**\n * Append an event - handles EVERYTHING for event creation\n * Creates ID, timestamp, metadata, checksum, sequence tracking, and writes to disk\n */\n async appendEvent(event: Omit<ResourceEvent, 'id' | 'timestamp'>, resourceId: ResourceId): Promise<StoredEvent> {\n // Ensure resource stream is initialized\n if (this.getSequenceNumber(resourceId) === 0) {\n await this.initializeResourceStream(resourceId);\n }\n\n // Create complete event with ID and timestamp\n const completeEvent: ResourceEvent = {\n ...event,\n id: uuidv4(),\n timestamp: new Date().toISOString(),\n } as ResourceEvent;\n\n // Calculate metadata\n const sequenceNumber = this.getNextSequenceNumber(resourceId);\n const prevEventHash = this.getLastEventHash(resourceId);\n\n const metadata: EventMetadata = {\n sequenceNumber,\n streamPosition: 0, // Will be set during write\n timestamp: new Date().toISOString(),\n prevEventHash: prevEventHash || undefined,\n checksum: sha256(completeEvent),\n };\n\n const storedEvent: StoredEvent = {\n event: completeEvent,\n metadata,\n };\n\n // Write to disk\n await this.writeEvent(storedEvent, resourceId);\n\n // Update last hash\n this.setLastEventHash(resourceId, metadata.checksum!);\n\n return storedEvent;\n }\n\n /**\n * Write an event to storage (append to JSONL)\n * Internal method - use appendEvent() instead\n */\n private async writeEvent(event: StoredEvent, resourceId: ResourceId): Promise<void> {\n const docPath = this.getResourcePath(resourceId);\n\n // Get current event files\n const files = await this.getEventFiles(resourceId);\n\n // Determine target file (rotate if needed)\n let targetFile: string;\n if (files.length === 0) {\n // No files yet - create first one\n targetFile = await this.createNewEventFile(resourceId);\n } else {\n const currentFile = files[files.length - 1];\n if (!currentFile) {\n // Shouldn't happen, but handle it\n targetFile = await this.createNewEventFile(resourceId);\n } else {\n const eventCount = await this.countEventsInFile(resourceId, currentFile);\n\n if (eventCount >= this.config.maxEventsPerFile) {\n // Rotate to new file\n targetFile = await this.createNewEventFile(resourceId);\n } else {\n targetFile = currentFile;\n }\n }\n }\n\n // Append event to file (JSONL format)\n const targetPath = path.join(docPath, targetFile);\n const eventLine = JSON.stringify(event) + '\\n';\n await fs.appendFile(targetPath, eventLine, 'utf-8');\n }\n\n /**\n * Count events in a specific file\n */\n async countEventsInFile(resourceId: ResourceId, filename: string): Promise<number> {\n const docPath = this.getResourcePath(resourceId);\n const filePath = path.join(docPath, filename);\n\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const lines = content.trim().split('\\n').filter(line => line.trim() !== '');\n return lines.length;\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n return 0;\n }\n throw error;\n }\n }\n\n /**\n * Read all events from a specific file\n */\n async readEventsFromFile(resourceId: ResourceId, filename: string): Promise<StoredEvent[]> {\n const docPath = this.getResourcePath(resourceId);\n const filePath = path.join(docPath, filename);\n\n const events: StoredEvent[] = [];\n\n try {\n const fileStream = createReadStream(filePath, { encoding: 'utf-8' });\n const rl = readline.createInterface({\n input: fileStream,\n crlfDelay: Infinity,\n });\n\n for await (const line of rl) {\n const trimmed = line.trim();\n if (trimmed === '') continue;\n\n try {\n const event = JSON.parse(trimmed) as StoredEvent;\n events.push(event);\n } catch (parseError) {\n this.logger?.error('[EventStorage] Failed to parse event', { filePath, error: parseError });\n // Skip malformed lines\n }\n }\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n return []; // File doesn't exist\n }\n throw error;\n }\n\n return events;\n }\n\n /**\n * Get list of event files for a resource (sorted by sequence)\n */\n async getEventFiles(resourceId: ResourceId): Promise<string[]> {\n const docPath = this.getResourcePath(makeResourceId(resourceId));\n\n try {\n const files = await fs.readdir(docPath);\n\n // Filter to .jsonl files and sort by sequence number\n const eventFiles = files\n .filter(f => f.startsWith('events-') && f.endsWith('.jsonl'))\n .sort((a, b) => {\n const seqA = parseInt(a.match(/events-(\\d+)\\.jsonl/)?.[1] || '0');\n const seqB = parseInt(b.match(/events-(\\d+)\\.jsonl/)?.[1] || '0');\n return seqA - seqB;\n });\n\n return eventFiles;\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n return []; // Directory doesn't exist\n }\n throw error;\n }\n }\n\n /**\n * Create a new event file for rotation\n */\n async createNewEventFile(resourceId: ResourceId): Promise<string> {\n const files = await this.getEventFiles(resourceId);\n\n // Determine next sequence number\n const lastFile = files[files.length - 1];\n const lastSeq = lastFile ? parseInt(lastFile.match(/events-(\\d+)\\.jsonl/)?.[1] || '1') : 1;\n const newSeq = lastSeq + 1;\n\n // Create new file\n const filename = this.createEventFilename(newSeq);\n const docPath = this.getResourcePath(resourceId);\n const filePath = path.join(docPath, filename);\n\n await fs.writeFile(filePath, '', 'utf-8');\n\n this.logger?.info('[EventStorage] Created new event file', { filename, resourceId });\n\n return filename;\n }\n\n /**\n * Get the last event from a specific file\n */\n async getLastEvent(resourceId: ResourceId, filename: string): Promise<StoredEvent | null> {\n const events = await this.readEventsFromFile(resourceId, filename);\n const lastEvent = events.length > 0 ? events[events.length - 1] : undefined;\n return lastEvent ?? null;\n }\n\n /**\n * Get all events for a resource across all files\n */\n async getAllEvents(resourceId: ResourceId): Promise<StoredEvent[]> {\n const files = await this.getEventFiles(resourceId);\n const allEvents: StoredEvent[] = [];\n\n for (const file of files) {\n const events = await this.readEventsFromFile(resourceId, file);\n allEvents.push(...events);\n }\n\n return allEvents;\n }\n\n /**\n * Get all resource IDs by scanning shard directories\n */\n async getAllResourceIds(): Promise<ResourceId[]> {\n const eventsDir = path.join(this.config.dataDir, 'events');\n const resourceIds: ResourceId[] = [];\n\n try {\n await fs.access(eventsDir);\n } catch {\n return []; // No events directory yet\n }\n\n // Recursively scan shard directories\n const scanDir = async (dir: string) => {\n const entries = await fs.readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n // Check if this looks like a resource ID (not a shard directory)\n // Shard directories are 2-char hex (00-ff), resource IDs are longer\n if (entry.name.length > 2) {\n resourceIds.push(makeResourceId(entry.name));\n } else {\n // Recurse into shard directory\n await scanDir(fullPath);\n }\n }\n }\n };\n\n await scanDir(eventsDir);\n return resourceIds;\n }\n\n /**\n * Create filename for event file\n */\n private createEventFilename(sequenceNumber: number): string {\n return `events-${sequenceNumber.toString().padStart(6, '0')}.jsonl`;\n }\n\n // ============================================================\n // Sequence/Hash Tracking\n // ============================================================\n\n /**\n * Get current sequence number for a resource\n */\n getSequenceNumber(resourceId: ResourceId): number {\n return this.resourceSequences.get(resourceId) || 0;\n }\n\n /**\n * Increment and return next sequence number for a resource\n */\n getNextSequenceNumber(resourceId: ResourceId): number {\n const current = this.getSequenceNumber(resourceId);\n const next = current + 1;\n this.resourceSequences.set(resourceId, next);\n return next;\n }\n\n /**\n * Get last event hash for a resource\n */\n getLastEventHash(resourceId: ResourceId): string | null {\n return this.resourceLastHash.get(resourceId) || null;\n }\n\n /**\n * Set last event hash for a resource\n */\n setLastEventHash(resourceId: ResourceId, hash: string): void {\n this.resourceLastHash.set(resourceId, hash);\n }\n}\n","/**\n * EventLog - Event Persistence Layer\n *\n * Single Responsibility: Event persistence only\n * - Appends events to storage (JSONL files)\n * - Retrieves events by resource\n * - Queries events with filters\n *\n * Does NOT handle:\n * - Pub/sub notifications (see EventBus)\n * - View updates (see ViewManager)\n */\n\nimport { type ResourceId, type StoredEvent, type ResourceEvent, type EventQuery, type Logger } from '@semiont/core';\nimport { EventStorage } from './storage/event-storage';\n\nexport interface EventLogConfig {\n basePath: string;\n dataDir: string;\n enableSharding?: boolean;\n maxEventsPerFile?: number;\n}\n\nexport class EventLog {\n // Expose storage for EventQuery (read operations)\n readonly storage: EventStorage;\n\n constructor(config: EventLogConfig, logger?: Logger) {\n this.storage = new EventStorage({\n basePath: config.basePath,\n dataDir: config.dataDir,\n enableSharding: config.enableSharding ?? true,\n maxEventsPerFile: config.maxEventsPerFile ?? 10000,\n }, logger?.child({ component: 'EventStorage' }));\n }\n\n /**\n * Append event to log\n * @param event - Resource event (from @semiont/core)\n * @param resourceId - Branded ResourceId (from @semiont/core)\n * @returns Stored event with metadata (sequence number, timestamp, checksum)\n */\n async append(event: Omit<ResourceEvent, 'id' | 'timestamp'>, resourceId: ResourceId): Promise<StoredEvent> {\n return this.storage.appendEvent(event, resourceId);\n }\n\n /**\n * Get all events for a resource\n * @param resourceId - Branded ResourceId (from @semiont/core)\n */\n async getEvents(resourceId: ResourceId): Promise<StoredEvent[]> {\n return this.storage.getAllEvents(resourceId);\n }\n\n /**\n * Get all resource IDs\n * @returns Array of branded ResourceId types\n */\n async getAllResourceIds(): Promise<ResourceId[]> {\n return this.storage.getAllResourceIds();\n }\n\n /**\n * Query events with filter\n * @param resourceId - Branded ResourceId (from @semiont/core)\n * @param filter - Optional event filter\n */\n async queryEvents(resourceId: ResourceId, filter?: EventQuery): Promise<StoredEvent[]> {\n const events = await this.storage.getAllEvents(resourceId);\n if (!filter) return events;\n\n return events.filter(e => {\n if (filter.eventTypes && !filter.eventTypes.includes(e.event.type as any)) return false;\n if (filter.fromSequence && e.metadata.sequenceNumber < filter.fromSequence) return false;\n if (filter.fromTimestamp && e.event.timestamp < filter.fromTimestamp) return false;\n if (filter.toTimestamp && e.event.timestamp > filter.toTimestamp) return false;\n if (filter.userId && e.event.userId !== filter.userId) return false;\n return true;\n });\n }\n}\n","/**\n * Identifier conversion functions - Convert between short IDs and W3C-compliant HTTP URIs\n *\n * These functions handle the conversion between:\n * - Short IDs (e.g., \"abc123\") - used internally in events\n * - HTTP URIs (e.g., \"http://localhost:4000/resources/abc123\") - used in API responses\n *\n * The W3C Web Annotation Model requires HTTP(S) URIs for @id fields.\n *\n * All functions are pure - they take config explicitly as a parameter.\n */\n\nimport { nanoid } from 'nanoid';\nimport {\n type ResourceId,\n type AnnotationId,\n type ResourceUri,\n type AnnotationUri,\n resourceUri,\n annotationUri,\n} from '@semiont/core';\nimport type { IdentifierConfig } from './types';\n\n// Re-export IdentifierConfig for convenience\nexport type { IdentifierConfig };\n\n// Convert IDs to URIs\nexport function toResourceUri(\n config: IdentifierConfig,\n id: ResourceId\n): ResourceUri {\n if (!config.baseUrl) {\n throw new Error('baseUrl is required');\n }\n return resourceUri(`${config.baseUrl}/resources/${id}`);\n}\n\nexport function toAnnotationUri(\n config: IdentifierConfig,\n id: AnnotationId\n): AnnotationUri {\n if (!config.baseUrl) {\n throw new Error('baseUrl is required');\n }\n return annotationUri(`${config.baseUrl}/annotations/${id}`);\n}\n\n/**\n * Generate a unique annotation ID (W3C-compliant HTTP URI)\n * Moved from apps/backend/src/utils/id-generator.ts\n *\n * @param baseUrl - Base URL for the annotation service (e.g., \"http://localhost:8080\")\n * @returns A W3C-compliant annotation URI (e.g., \"http://localhost:8080/annotations/V1StGXR8_Z5jdHi6B-myT\")\n */\nexport function generateAnnotationId(baseUrl: string): string {\n if (!baseUrl) {\n throw new Error('baseUrl is required to generate annotation URIs');\n }\n // Remove trailing slash if present\n const normalizedBase = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;\n return `${normalizedBase}/annotations/${nanoid(21)}`;\n}\n","/**\n * Event Subscriptions - Real-time Event Pub/Sub\n *\n * Manages subscriptions for both resource-scoped and system-level events:\n * - Resource subscriptions: notifications for a specific resource's events\n * - Global subscriptions: notifications for all system-level events\n * - Fire-and-forget notification pattern (non-blocking)\n * - Automatic cleanup of empty subscription sets\n *\n * SINGLETON PATTERN: All EventStore instances share the same EventSubscriptions\n * to ensure SSE connections receive events from any EventStore instance.\n *\n * @see docs/EVENT-STORE.md#eventsubscriptions for architecture details\n */\n\nimport type { StoredEvent, ResourceUri, Logger } from '@semiont/core';\n\nexport type EventCallback = (event: StoredEvent) => void | Promise<void>;\n\nexport interface EventSubscription {\n resourceUri: ResourceUri;\n callback: EventCallback;\n unsubscribe: () => void;\n}\n\n/**\n * EventSubscriptions manages real-time event pub/sub\n * Supports both resource-scoped and global subscriptions\n */\nexport class EventSubscriptions {\n // Per-resource subscriptions: ResourceUri -> Set of callbacks\n private subscriptions: Map<ResourceUri, Set<EventCallback>> = new Map();\n // Global subscriptions for system-level events (no resourceId)\n private globalSubscriptions: Set<EventCallback> = new Set();\n private logger?: Logger;\n\n constructor(logger?: Logger) {\n this.logger = logger;\n }\n\n /**\n * Subscribe to events for a specific resource using full URI\n * Returns an EventSubscription with unsubscribe function\n */\n subscribe(resourceUri: ResourceUri, callback: EventCallback): EventSubscription {\n if (!this.subscriptions.has(resourceUri)) {\n this.subscriptions.set(resourceUri, new Set());\n }\n\n const callbacks = this.subscriptions.get(resourceUri)!;\n callbacks.add(callback);\n\n this.logger?.info('[EventSubscriptions] Subscription added for resource', { resourceUri, totalSubscribers: callbacks.size });\n\n return {\n resourceUri,\n callback,\n unsubscribe: () => {\n callbacks.delete(callback);\n this.logger?.info('[EventSubscriptions] Subscription removed for resource', { resourceUri, remainingSubscribers: callbacks.size });\n if (callbacks.size === 0) {\n this.subscriptions.delete(resourceUri);\n this.logger?.info('[EventSubscriptions] No more subscribers for resource, removed from subscriptions map', { resourceUri });\n }\n }\n };\n }\n\n /**\n * Subscribe to all system-level events (no resourceId)\n * Returns an EventSubscription with unsubscribe function\n *\n * Use this for consumers that need to react to global events like:\n * - entitytype.added (global entity type collection changes)\n * - Future system-level events (user.created, workspace.created, etc.)\n */\n subscribeGlobal(callback: EventCallback): EventSubscription {\n this.globalSubscriptions.add(callback);\n\n this.logger?.info('[EventSubscriptions] Global subscription added', { totalSubscribers: this.globalSubscriptions.size });\n\n return {\n resourceUri: '__global__' as ResourceUri, // Special marker for global subscriptions\n callback,\n unsubscribe: () => {\n this.globalSubscriptions.delete(callback);\n this.logger?.info('[EventSubscriptions] Global subscription removed', { remainingSubscribers: this.globalSubscriptions.size });\n }\n };\n }\n\n /**\n * Notify all subscribers for a resource when a new event is appended\n * @param resourceUri - Full resource URI (e.g., http://localhost:4000/resources/abc123)\n */\n async notifySubscribers(resourceUri: ResourceUri, event: StoredEvent): Promise<void> {\n const callbacks = this.subscriptions.get(resourceUri);\n if (!callbacks || callbacks.size === 0) {\n this.logger?.info('[EventSubscriptions] Event - no subscribers to notify', { eventType: event.event.type, resourceUri });\n return;\n }\n\n this.logger?.info('[EventSubscriptions] Notifying subscribers of event', { subscriberCount: callbacks.size, eventType: event.event.type, resourceUri });\n\n // Call all callbacks without waiting - fire and forget\n // Each callback handles its own errors and cleanup\n // This prevents slow/hanging callbacks from blocking event emission\n Array.from(callbacks).forEach((callback, index) => {\n Promise.resolve(callback(event))\n .then(() => {\n this.logger?.info('[EventSubscriptions] Subscriber successfully notified', { subscriberIndex: index + 1, eventType: event.event.type });\n })\n .catch((error: unknown) => {\n this.logger?.error('[EventSubscriptions] Error in subscriber', { subscriberIndex: index + 1, resourceUri, eventType: event.event.type, error });\n });\n });\n }\n\n /**\n * Notify all global subscribers when a system-level event is appended\n */\n async notifyGlobalSubscribers(event: StoredEvent): Promise<void> {\n if (this.globalSubscriptions.size === 0) {\n this.logger?.info('[EventSubscriptions] System event - no global subscribers to notify', { eventType: event.event.type });\n return;\n }\n\n this.logger?.info('[EventSubscriptions] Notifying global subscribers of system event', { subscriberCount: this.globalSubscriptions.size, eventType: event.event.type });\n\n // Call all global callbacks without waiting - fire and forget\n // Each callback handles its own errors and cleanup\n // This prevents slow/hanging callbacks from blocking event emission\n Array.from(this.globalSubscriptions).forEach((callback, index) => {\n Promise.resolve(callback(event))\n .then(() => {\n this.logger?.info('[EventSubscriptions] Global subscriber successfully notified', { subscriberIndex: index + 1, eventType: event.event.type });\n })\n .catch((error: unknown) => {\n this.logger?.error('[EventSubscriptions] Error in global subscriber', { subscriberIndex: index + 1, eventType: event.event.type, error });\n });\n });\n }\n\n /**\n * Get subscription count for a resource (useful for debugging)\n */\n getSubscriptionCount(resourceUri: ResourceUri): number {\n return this.subscriptions.get(resourceUri)?.size || 0;\n }\n\n /**\n * Get total number of active subscriptions across all resources\n */\n getTotalSubscriptions(): number {\n let total = 0;\n for (const callbacks of this.subscriptions.values()) {\n total += callbacks.size;\n }\n return total;\n }\n\n /**\n * Get total number of global subscriptions\n */\n getGlobalSubscriptionCount(): number {\n return this.globalSubscriptions.size;\n }\n}\n\n// Singleton instance - shared across all EventStore instances\n// This ensures SSE connections receive events from any EventStore instance\nlet globalEventSubscriptions: EventSubscriptions | null = null;\n\nexport function getEventSubscriptions(logger?: Logger): EventSubscriptions {\n if (!globalEventSubscriptions) {\n globalEventSubscriptions = new EventSubscriptions(logger);\n logger?.info('[EventSubscriptions] Created global singleton instance');\n }\n return globalEventSubscriptions;\n}\n","/**\n * EventBus - Event Pub/Sub Layer\n *\n * Single Responsibility: Event pub/sub only\n * - Publishes events to subscribers\n * - Manages subscriptions (resource-scoped and global)\n * - Converts ResourceId to ResourceUri internally\n *\n * Does NOT handle:\n * - Event persistence (see EventLog)\n * - View updates (see ViewManager)\n */\n\nimport { type StoredEvent, type ResourceId, isResourceEvent, isSystemEvent, type Logger } from '@semiont/core';\nimport { toResourceUri, type IdentifierConfig } from './identifier-utils';\nimport { getEventSubscriptions, type EventSubscriptions, type EventCallback, type EventSubscription } from './subscriptions/event-subscriptions';\n\nexport interface EventBusConfig {\n identifierConfig: IdentifierConfig;\n}\n\n/**\n * EventBus wraps EventSubscriptions with a clean API\n * Handles ID-to-URI conversion internally for type safety\n */\nexport class EventBus {\n // Expose subscriptions for direct access (legacy compatibility)\n readonly subscriptions: EventSubscriptions;\n private identifierConfig: IdentifierConfig;\n private logger?: Logger;\n\n constructor(config: EventBusConfig, logger?: Logger) {\n this.identifierConfig = config.identifierConfig;\n this.logger = logger;\n // Use global singleton EventSubscriptions to ensure all EventBus instances\n // share the same subscription registry (critical for SSE real-time events)\n this.subscriptions = getEventSubscriptions(logger?.child({ component: 'EventSubscriptions' }));\n }\n\n /**\n * Publish event to subscribers\n * - Resource events: notifies BOTH resource-scoped AND global subscribers\n * - System events: notifies global subscribers only\n * @param event - Stored event (from @semiont/core)\n */\n async publish(event: StoredEvent): Promise<void> {\n if (isSystemEvent(event.event)) {\n // System-level event - notify global subscribers\n await this.subscriptions.notifyGlobalSubscribers(event);\n } else if (isResourceEvent(event.event)) {\n // Resource event - notify BOTH resource-scoped AND global subscribers\n // This enables projections (graph, search, etc.) to use global subscription\n const resourceId = event.event.resourceId as ResourceId;\n const resourceUri = toResourceUri(this.identifierConfig, resourceId);\n await this.subscriptions.notifySubscribers(resourceUri, event);\n await this.subscriptions.notifyGlobalSubscribers(event);\n } else {\n // Shouldn't happen - events should be either resource or system\n this.logger?.warn('[EventBus] Event is neither resource nor system event', { eventType: (event.event as any).type });\n }\n }\n\n /**\n * Subscribe to events for a specific resource\n * @param resourceId - Branded ResourceId (from @semiont/core)\n * @param callback - Event callback function\n * @returns EventSubscription with unsubscribe function\n */\n subscribe(resourceId: ResourceId, callback: EventCallback): EventSubscription {\n const resourceUri = toResourceUri(this.identifierConfig, resourceId);\n return this.subscriptions.subscribe(resourceUri, callback);\n }\n\n /**\n * Subscribe to all system-level events\n * @param callback - Event callback function\n * @returns EventSubscription with unsubscribe function\n */\n subscribeGlobal(callback: EventCallback): EventSubscription {\n return this.subscriptions.subscribeGlobal(callback);\n }\n\n /**\n * Unsubscribe from resource events\n * @param resourceId - Branded ResourceId (from @semiont/core)\n * @param callback - Event callback function to remove\n */\n unsubscribe(resourceId: ResourceId, callback: EventCallback): void {\n const resourceUri = toResourceUri(this.identifierConfig, resourceId);\n const callbacks = (this.subscriptions as any).subscriptions.get(resourceUri);\n if (callbacks) {\n callbacks.delete(callback);\n if (callbacks.size === 0) {\n (this.subscriptions as any).subscriptions.delete(resourceUri);\n }\n }\n }\n\n /**\n * Unsubscribe from global events\n * @param callback - Event callback function to remove\n */\n unsubscribeGlobal(callback: EventCallback): void {\n (this.subscriptions as any).globalSubscriptions.delete(callback);\n }\n\n /**\n * Get subscriber count for a resource\n * @param resourceId - Branded ResourceId (from @semiont/core)\n * @returns Number of active subscribers\n */\n getSubscriberCount(resourceId: ResourceId): number {\n const resourceUri = toResourceUri(this.identifierConfig, resourceId);\n return this.subscriptions.getSubscriptionCount(resourceUri);\n }\n\n /**\n * Get total number of active subscriptions across all resources\n */\n getTotalSubscriptions(): number {\n return this.subscriptions.getTotalSubscriptions();\n }\n\n /**\n * Get total number of global subscriptions\n */\n getGlobalSubscriptionCount(): number {\n return this.subscriptions.getGlobalSubscriptionCount();\n }\n}\n","/**\n * View Materializer - Materialized View Management\n *\n * Materializes resource views from events:\n * - Full view materialization from scratch\n * - Incremental view updates\n * - System-level views (entity types)\n *\n * @see docs/EVENT-STORE.md#viewmaterializer for architecture details\n */\n\nimport { promises as fs } from 'fs';\nimport * as path from 'path';\nimport { didToAgent } from '@semiont/core';\nimport type { components } from '@semiont/core';\n\ntype Representation = components['schemas']['Representation'];\ntype Annotation = components['schemas']['Annotation'];\ntype ResourceDescriptor = components['schemas']['ResourceDescriptor'];\n\nimport type {\n ResourceEvent,\n StoredEvent,\n ResourceAnnotations,\n ResourceId,\n Logger,\n} from '@semiont/core';\nimport { findBodyItem } from '@semiont/core';\nimport type { ViewStorage, ResourceView } from '../storage/view-storage';\n\nexport interface ViewMaterializerConfig {\n basePath: string;\n backendUrl: string;\n}\n\n/**\n * ViewMaterializer builds and maintains materialized views from events\n */\nexport class ViewMaterializer {\n private logger?: Logger;\n\n constructor(\n private viewStorage: ViewStorage,\n private config: ViewMaterializerConfig,\n logger?: Logger\n ) {\n this.logger = logger;\n }\n\n /**\n * Materialize resource view from events\n * Loads existing view if cached, otherwise rebuilds from events\n */\n async materialize(events: StoredEvent[], resourceId: ResourceId): Promise<ResourceView | null> {\n // Try to load existing view\n const existing = await this.viewStorage.get(resourceId);\n if (existing) {\n return existing;\n }\n\n // No view exists - rebuild from events\n if (events.length === 0) return null;\n\n const view = this.materializeFromEvents(events, resourceId);\n\n // Save rebuilt view\n await this.viewStorage.save(resourceId, view);\n\n return view;\n }\n\n /**\n * Materialize view incrementally with a single event\n * Falls back to full rebuild if view doesn't exist\n */\n async materializeIncremental(\n resourceId: ResourceId,\n event: ResourceEvent,\n getAllEvents: () => Promise<StoredEvent[]>\n ): Promise<void> {\n this.logger?.info('[ViewMaterializer] Updating view for resource with event', { resourceId, eventType: event.type });\n\n // Try to load existing view\n let view = await this.viewStorage.get(resourceId);\n\n if (!view) {\n // No view exists - do full rebuild from all events\n this.logger?.info('[ViewMaterializer] No view found, rebuilding from scratch', { resourceId });\n const events = await getAllEvents();\n view = this.materializeFromEvents(events, resourceId);\n } else {\n // Apply single event incrementally to existing view\n this.logger?.info('[ViewMaterializer] Applying event incrementally to existing view', { resourceId, version: view.annotations.version });\n this.applyEventToResource(view.resource, event);\n this.applyEventToAnnotations(view.annotations, event);\n view.annotations.version++;\n view.annotations.updatedAt = event.timestamp;\n }\n\n // Save updated view\n await this.viewStorage.save(resourceId, view);\n this.logger?.info('[ViewMaterializer] View saved', { resourceId, version: view.annotations.version, annotationCount: view.annotations.annotations.length });\n }\n\n /**\n * Materialize view from event list (full rebuild)\n */\n private materializeFromEvents(events: StoredEvent[], resourceId: ResourceId): ResourceView {\n // Build W3C-compliant HTTP URI for @id\n const backendUrl = this.config.backendUrl;\n const normalizedBase = backendUrl.endsWith('/') ? backendUrl.slice(0, -1) : backendUrl;\n\n // Start with empty ResourceDescriptor state\n const resource: ResourceDescriptor = {\n '@context': 'https://schema.org/',\n '@id': `${normalizedBase}/resources/${resourceId}`,\n name: '',\n representations: [],\n archived: false,\n entityTypes: [],\n creationMethod: 'api',\n };\n\n // Start with empty annotations\n const annotations: ResourceAnnotations = {\n resourceId,\n annotations: [],\n version: 0,\n updatedAt: '',\n };\n\n // Apply events in sequenceNumber order\n events.sort((a, b) => a.metadata.sequenceNumber - b.metadata.sequenceNumber);\n\n for (const storedEvent of events) {\n this.applyEventToResource(resource, storedEvent.event);\n this.applyEventToAnnotations(annotations, storedEvent.event);\n annotations.version++;\n annotations.updatedAt = storedEvent.event.timestamp;\n }\n\n return { resource, annotations };\n }\n\n /**\n * Apply an event to ResourceDescriptor state (metadata only)\n */\n private applyEventToResource(resource: ResourceDescriptor, event: ResourceEvent): void {\n switch (event.type) {\n case 'resource.created':\n resource.name = event.payload.name;\n resource.entityTypes = event.payload.entityTypes || [];\n resource.dateCreated = event.timestamp;\n resource.creationMethod = event.payload.creationMethod || 'api';\n resource.wasAttributedTo = didToAgent(event.userId);\n\n // Create representation from format and checksum\n if (!resource.representations) resource.representations = [];\n const reps = Array.isArray(resource.representations) ? resource.representations : [resource.representations];\n reps.push({\n mediaType: event.payload.format,\n checksum: event.payload.contentChecksum,\n byteSize: event.payload.contentByteSize,\n rel: 'original',\n language: event.payload.language,\n } as Representation);\n resource.representations = reps;\n\n // First-class fields\n resource.isDraft = event.payload.isDraft;\n resource.wasDerivedFrom = event.payload.generatedFrom;\n break;\n\n case 'resource.cloned':\n resource.name = event.payload.name;\n resource.entityTypes = event.payload.entityTypes || [];\n resource.dateCreated = event.timestamp;\n resource.creationMethod = 'clone';\n resource.sourceResourceId = event.payload.parentResourceId;\n resource.wasAttributedTo = didToAgent(event.userId);\n\n // Create representation from format and checksum\n if (!resource.representations) resource.representations = [];\n const reps2 = Array.isArray(resource.representations) ? resource.representations : [resource.representations];\n reps2.push({\n mediaType: event.payload.format,\n checksum: event.payload.contentChecksum,\n byteSize: event.payload.contentByteSize,\n rel: 'original',\n language: event.payload.language,\n } as Representation);\n resource.representations = reps2;\n break;\n\n case 'resource.archived':\n resource.archived = true;\n break;\n\n case 'resource.unarchived':\n resource.archived = false;\n break;\n\n case 'representation.added': {\n const { representation } = event.payload;\n\n // Add to representations array (avoid duplicates by checksum)\n if (!resource.representations) {\n resource.representations = [];\n }\n\n const repsArray = Array.isArray(resource.representations)\n ? resource.representations\n : [resource.representations];\n\n // Check if representation already exists\n const exists = repsArray.some(r => r.checksum === representation.checksum);\n if (!exists) {\n resource.representations = [...repsArray, representation];\n }\n break;\n }\n\n case 'representation.removed': {\n const { checksum } = event.payload;\n\n if (resource.representations) {\n const repsArray = Array.isArray(resource.representations)\n ? resource.representations\n : [resource.representations];\n\n resource.representations = repsArray.filter(r => r.checksum !== checksum);\n }\n break;\n }\n\n case 'entitytag.added':\n if (!resource.entityTypes) resource.entityTypes = [];\n if (!resource.entityTypes.includes(event.payload.entityType)) {\n resource.entityTypes.push(event.payload.entityType);\n }\n break;\n\n case 'entitytag.removed':\n if (resource.entityTypes) {\n resource.entityTypes = resource.entityTypes.filter(\n (t: string) => t !== event.payload.entityType\n );\n }\n break;\n\n // Annotation events don't affect resource metadata\n case 'annotation.added':\n case 'annotation.removed':\n case 'annotation.body.updated':\n break;\n\n // Job events don't affect resource metadata\n case 'job.started':\n case 'job.progress':\n case 'job.completed':\n case 'job.failed':\n break;\n\n // System events don't affect resource metadata\n case 'entitytype.added':\n break;\n }\n }\n\n /**\n * Apply an event to ResourceAnnotations (annotation collections only)\n */\n private applyEventToAnnotations(annotations: ResourceAnnotations, event: ResourceEvent): void {\n switch (event.type) {\n case 'annotation.added':\n // Event payload contains Omit<Annotation, 'creator' | 'created'> (includes @context and type)\n // Add creator/created from event metadata\n annotations.annotations.push({\n ...event.payload.annotation,\n creator: didToAgent(event.userId),\n created: new Date(event.timestamp).toISOString(),\n });\n break;\n\n case 'annotation.removed':\n // payload.annotationId is just the UUID, but a.id might be full URI or plain ID\n // Handle both: plain ID ('anno1') and full URI ('http://.../annotations/anno1')\n annotations.annotations = annotations.annotations.filter(\n (a: Annotation) => a.id !== event.payload.annotationId && !a.id.endsWith(`/annotations/${event.payload.annotationId}`)\n );\n break;\n\n case 'annotation.body.updated':\n // Find annotation by ID\n // payload.annotationId is just the UUID, but a.id might be full URI or plain ID\n // Handle both: plain ID ('anno1') and full URI ('http://.../annotations/anno1')\n const annotation = annotations.annotations.find((a: Annotation) =>\n a.id === event.payload.annotationId || a.id.endsWith(`/annotations/${event.payload.annotationId}`)\n );\n if (annotation) {\n // Ensure body is an array\n if (!Array.isArray(annotation.body)) {\n annotation.body = annotation.body ? [annotation.body] : [];\n }\n\n // Apply each operation\n for (const op of event.payload.operations) {\n if (op.op === 'add') {\n // Add item (idempotent - don't add if already exists)\n const exists = findBodyItem(annotation.body, op.item) !== -1;\n if (!exists) {\n annotation.body.push(op.item);\n }\n } else if (op.op === 'remove') {\n // Remove item\n const index = findBodyItem(annotation.body, op.item);\n if (index !== -1) {\n annotation.body.splice(index, 1);\n }\n } else if (op.op === 'replace') {\n // Replace item\n const index = findBodyItem(annotation.body, op.oldItem);\n if (index !== -1) {\n annotation.body[index] = op.newItem;\n }\n }\n }\n\n // Update modified timestamp\n annotation.modified = new Date(event.timestamp).toISOString();\n }\n break;\n\n // Resource metadata events don't affect annotations\n case 'resource.created':\n case 'resource.cloned':\n case 'resource.archived':\n case 'resource.unarchived':\n case 'representation.added':\n case 'representation.removed':\n case 'entitytag.added':\n case 'entitytag.removed':\n break;\n\n // Job events don't affect annotations\n case 'job.started':\n case 'job.progress':\n case 'job.completed':\n case 'job.failed':\n break;\n\n // System events don't affect annotations\n case 'entitytype.added':\n break;\n }\n }\n\n /**\n * Materialize entity types view - System-level view\n */\n async materializeEntityTypes(entityType: string): Promise<void> {\n const entityTypesPath = path.join(\n this.config.basePath,\n 'projections',\n '__system__',\n 'entitytypes.json'\n );\n\n\n // Read current view\n let view = { entityTypes: [] as string[] };\n try {\n const content = await fs.readFile(entityTypesPath, 'utf-8');\n view = JSON.parse(content);\n } catch (error: any) {\n if (error.code !== 'ENOENT') throw error;\n // File doesn't exist - will create it\n }\n\n // Add entity type (idempotent - Set ensures uniqueness)\n const entityTypeSet = new Set(view.entityTypes);\n entityTypeSet.add(entityType);\n view.entityTypes = Array.from(entityTypeSet).sort();\n\n // Write view\n await fs.mkdir(path.dirname(entityTypesPath), { recursive: true });\n await fs.writeFile(entityTypesPath, JSON.stringify(view, null, 2));\n }\n}\n","/**\n * ViewManager - Materialized View Management Layer\n *\n * Single Responsibility: View updates only\n * - Updates resource views from events\n * - Updates system views (entity types)\n * - Rebuilds views when needed\n *\n * Does NOT handle:\n * - Event persistence (see EventLog)\n * - Pub/sub notifications (see EventBus)\n */\n\nimport { type ResourceId, type ResourceEvent, type StoredEvent, type Logger } from '@semiont/core';\nimport { ViewMaterializer, type ViewMaterializerConfig } from './views/view-materializer';\nimport type { ViewStorage, ResourceView } from './storage/view-storage';\n\nexport interface ViewManagerConfig {\n basePath: string;\n backendUrl: string;\n}\n\n/**\n * ViewManager wraps ViewMaterializer with a clean API\n * Handles both resource and system-level views\n */\nexport class ViewManager {\n // Expose materializer for direct access to view methods\n readonly materializer: ViewMaterializer;\n\n constructor(\n viewStorage: ViewStorage,\n config: ViewManagerConfig,\n logger?: Logger\n ) {\n const materializerConfig: ViewMaterializerConfig = {\n basePath: config.basePath,\n backendUrl: config.backendUrl,\n };\n this.materializer = new ViewMaterializer(viewStorage, materializerConfig, logger?.child({ component: 'ViewMaterializer' }));\n }\n\n /**\n * Update resource view with a new event\n * Falls back to full rebuild if view doesn't exist\n * @param resourceId - Branded ResourceId (from @semiont/core)\n * @param event - Resource event (from @semiont/core)\n * @param getAllEvents - Function to retrieve all events for rebuild if needed\n */\n async materializeResource(\n resourceId: ResourceId,\n event: ResourceEvent,\n getAllEvents: () => Promise<StoredEvent[]>\n ): Promise<void> {\n await this.materializer.materializeIncremental(resourceId, event, getAllEvents);\n }\n\n /**\n * Update system-level view (currently only entity types)\n * @param eventType - Type of system event\n * @param payload - Event payload\n */\n async materializeSystem(eventType: string, payload: any): Promise<void> {\n if (eventType === 'entitytype.added') {\n await this.materializer.materializeEntityTypes(payload.entityType);\n }\n // Future system views can be added here\n // e.g., user.created, workspace.created, etc.\n }\n\n /**\n * Get resource view (builds from events if needed)\n * @param resourceId - Branded ResourceId (from @semiont/core)\n * @param events - Stored events for the resource (from @semiont/core)\n * @returns Resource view or null if no events\n */\n async getOrMaterialize(\n resourceId: ResourceId,\n events: StoredEvent[]\n ): Promise<ResourceView | null> {\n return this.materializer.materialize(events, resourceId);\n }\n}\n","/**\n * EventStore - Orchestration Layer\n *\n * Coordinates event sourcing operations across 3 focused components:\n * - EventLog: Event persistence (append, retrieve, query)\n * - EventBus: Pub/sub notifications (publish, subscribe)\n * - ViewManager: View updates (resource and system)\n *\n * Thin coordination layer - delegates all work to specialized components.\n *\n * @see docs/EVENT-STORE.md for complete architecture documentation\n */\n\nimport type {\n ResourceEvent,\n StoredEvent,\n ResourceId,\n Logger,\n} from '@semiont/core';\nimport { EventBus as CoreEventBus } from '@semiont/core';\nimport type { ViewStorage } from './storage/view-storage';\nimport type { IdentifierConfig } from './identifier-utils';\n\n// Import focused components\nimport { EventLog, type EventLogConfig } from './event-log';\nimport { EventBus, type EventBusConfig } from './event-bus';\nimport { ViewManager, type ViewManagerConfig } from './view-manager';\nimport type { EventStorageConfig } from './storage/event-storage';\n\n/**\n * EventStore orchestrates event sourcing operations\n * Delegates to specialized components for focused functionality\n * NO state - just coordination between components\n */\nexport class EventStore {\n // Focused components - each with single responsibility\n readonly log: EventLog;\n readonly bus: EventBus;\n readonly views: ViewManager;\n readonly viewStorage: ViewStorage;\n readonly coreEventBus?: CoreEventBus;\n\n constructor(\n config: EventStorageConfig,\n viewStorage: ViewStorage,\n identifierConfig: IdentifierConfig,\n coreEventBus?: CoreEventBus,\n logger?: Logger\n ) {\n // Store viewStorage for direct access\n this.viewStorage = viewStorage;\n this.coreEventBus = coreEventBus;\n\n // Initialize focused components\n const logConfig: EventLogConfig = {\n basePath: config.basePath,\n dataDir: config.dataDir,\n enableSharding: config.enableSharding,\n maxEventsPerFile: config.maxEventsPerFile,\n };\n this.log = new EventLog(logConfig, logger?.child({ component: 'EventLog' }));\n\n const busConfig: EventBusConfig = {\n identifierConfig,\n };\n this.bus = new EventBus(busConfig, logger?.child({ component: 'EventBus' }));\n\n const viewConfig: ViewManagerConfig = {\n basePath: config.basePath,\n backendUrl: identifierConfig.baseUrl,\n };\n this.views = new ViewManager(viewStorage, viewConfig, logger?.child({ component: 'ViewManager' }));\n }\n\n /**\n * Append an event to the store\n * Coordinates: persistence → view → notification\n */\n async appendEvent(event: Omit<ResourceEvent, 'id' | 'timestamp'>): Promise<StoredEvent> {\n // System-level events (entitytype.added) have no resourceId - use __system__\n const resourceId: ResourceId | '__system__' = event.resourceId || '__system__';\n\n // 1. Persist event to log\n const storedEvent = await this.log.append(event, resourceId as any);\n\n // 2. Update views\n if (resourceId === '__system__') {\n // System-level view (entity types, etc.)\n await this.views.materializeSystem(\n storedEvent.event.type,\n storedEvent.event.payload\n );\n } else {\n // Resource view\n await this.views.materializeResource(\n resourceId as ResourceId,\n storedEvent.event,\n () => this.log.getEvents(resourceId as ResourceId)\n );\n }\n\n // 3. Notify subscribers (legacy event bus)\n await this.bus.publish(storedEvent);\n\n // 4. Publish to @semiont/core EventBus if provided (domain events)\n if (this.coreEventBus && resourceId !== '__system__') {\n // Use resource-scoped bus for isolation\n const scopedBus = this.coreEventBus.scope(resourceId as string);\n // Publish domain event to generic 'make-meaning:event' channel\n scopedBus.get('make-meaning:event').next(storedEvent.event);\n }\n\n return storedEvent;\n }\n}\n","/**\n * View Storage - Materialized Views\n *\n * Stores materialized views of resource state and annotations\n * Built from event streams, can be rebuilt at any time\n *\n * Stores both ResourceDescriptor metadata and ResourceAnnotations, but keeps them logically separate\n */\n\nimport { promises as fs } from 'fs';\nimport * as path from 'path';\nimport { getShardPath } from './shard-utils';\nimport type { components } from '@semiont/core';\nimport type { ResourceAnnotations, ResourceId, Logger } from '@semiont/core';\n\ntype ResourceDescriptor = components['schemas']['ResourceDescriptor'];\n\n// Complete state for a resource in materialized view (metadata + annotations)\nexport interface ResourceView {\n resource: ResourceDescriptor;\n annotations: ResourceAnnotations;\n}\n\nexport interface ViewStorage {\n save(resourceId: ResourceId, view: ResourceView): Promise<void>;\n get(resourceId: ResourceId): Promise<ResourceView | null>;\n delete(resourceId: ResourceId): Promise<void>;\n exists(resourceId: ResourceId): Promise<boolean>;\n getAll(): Promise<ResourceView[]>;\n}\n\nexport class FilesystemViewStorage implements ViewStorage {\n private basePath: string;\n private logger?: Logger;\n\n constructor(basePath: string, projectRoot?: string, logger?: Logger) {\n this.logger = logger;\n // If path is absolute, use it directly\n if (path.isAbsolute(basePath)) {\n this.basePath = basePath;\n }\n // If projectRoot provided, resolve relative paths against it\n else if (projectRoot) {\n this.basePath = path.resolve(projectRoot, basePath);\n }\n // Otherwise fall back to resolving against cwd (backward compat)\n else {\n this.basePath = path.resolve(basePath);\n }\n }\n\n private getProjectionPath(resourceId: ResourceId): string {\n // Use 4-hex Jump Consistent Hash sharding (65,536 shards)\n const [ab, cd] = getShardPath(resourceId);\n return path.join(this.basePath, 'projections', 'resources', ab, cd, `${resourceId}.json`);\n }\n\n async save(resourceId: ResourceId, projection: ResourceView): Promise<void> {\n const projPath = this.getProjectionPath(resourceId);\n const projDir = path.dirname(projPath);\n\n // Ensure shard directory exists\n await fs.mkdir(projDir, { recursive: true });\n\n // Write projection to file\n await fs.writeFile(projPath, JSON.stringify(projection, null, 2), 'utf-8');\n }\n\n async get(resourceId: ResourceId): Promise<ResourceView | null> {\n const projPath = this.getProjectionPath(resourceId);\n\n try {\n const content = await fs.readFile(projPath, 'utf-8');\n return JSON.parse(content) as ResourceView;\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n return null;\n }\n // Auto-delete corrupted view files (views are derived data, can be rebuilt from events)\n // This only handles JSON parsing errors, not broken event chains\n if (error instanceof SyntaxError) {\n this.logger?.error('[ViewStorage] Corrupted view file detected', { resourceId, error: error.message });\n this.logger?.error('[ViewStorage] Deleting corrupted view file', { path: projPath });\n try {\n await fs.unlink(projPath);\n } catch (unlinkError) {\n this.logger?.error('[ViewStorage] Failed to delete corrupted file', { error: unlinkError });\n }\n return null;\n }\n throw error;\n }\n }\n\n async delete(resourceId: ResourceId): Promise<void> {\n const projPath = this.getProjectionPath(resourceId);\n\n try {\n await fs.unlink(projPath);\n } catch (error: any) {\n if (error.code !== 'ENOENT') {\n throw error;\n }\n // Ignore if file doesn't exist\n }\n }\n\n async exists(resourceId: ResourceId): Promise<boolean> {\n const projPath = this.getProjectionPath(resourceId);\n\n try {\n await fs.access(projPath);\n return true;\n } catch {\n return false;\n }\n }\n\n async getAll(): Promise<ResourceView[]> {\n const views: ResourceView[] = [];\n const annotationsPath = path.join(this.basePath, 'projections', 'resources');\n\n try {\n // Recursively walk through all shard directories\n const walkDir = async (dir: string): Promise<void> => {\n const entries = await fs.readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n await walkDir(fullPath);\n } else if (entry.isFile() && entry.name.endsWith('.json')) {\n try {\n const content = await fs.readFile(fullPath, 'utf-8');\n const view = JSON.parse(content) as ResourceView;\n views.push(view);\n } catch (error) {\n this.logger?.error('[ViewStorage] Failed to read view', { path: fullPath, error });\n // Skip invalid view files\n }\n }\n }\n };\n\n await walkDir(annotationsPath);\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n // Views directory doesn't exist yet\n return [];\n }\n throw error;\n }\n\n return views;\n }\n}","/**\n * Event Store Factory\n *\n * Factory function for creating EventStore instances with standard configuration.\n * This is the canonical way to instantiate an EventStore.\n */\n\nimport * as path from 'path';\nimport type { EventBus as CoreEventBus, Logger } from '@semiont/core';\nimport { EventStore } from './event-store';\nimport { FilesystemViewStorage } from './storage/view-storage';\nimport type { EventStorageConfig } from './storage/event-storage';\nimport type { IdentifierConfig } from './types';\n\n/**\n * Create and initialize an EventStore instance\n *\n * @param basePath - Absolute path to the data directory (must be resolved by caller)\n * @param baseUrl - Base URL for generating identifiers (e.g., \"http://localhost:8080\")\n * @param config - Optional additional storage configuration\n * @param eventBus - Optional @semiont/core EventBus for publishing domain events\n * @param logger - Optional logger for structured logging\n * @returns Configured EventStore instance ready for use\n *\n * @example\n * ```typescript\n * const eventStore = createEventStore(\n * '/absolute/path/to/data',\n * 'http://localhost:8080'\n * );\n * await eventStore.appendEvent({\n * type: 'resource.created',\n * resourceId: 'doc-123',\n * userId: 'user-456',\n * version: 1,\n * payload: { name: 'My Document' }\n * });\n * ```\n */\nexport function createEventStore(\n basePath: string,\n baseUrl: string,\n config?: Partial<EventStorageConfig>,\n eventBus?: CoreEventBus,\n logger?: Logger\n): EventStore {\n if (!basePath) {\n throw new Error('basePath is required to create EventStore');\n }\n if (!baseUrl) {\n throw new Error('baseUrl is required to create EventStore');\n }\n if (!path.isAbsolute(basePath)) {\n throw new Error('basePath must be an absolute path (use path.resolve() to convert relative paths)');\n }\n\n const identifierConfig: IdentifierConfig = {\n baseUrl,\n };\n\n // Create ViewStorage for materialized views\n // Structure: <basePath>/projections/resources/...\n const viewStorage = new FilesystemViewStorage(basePath, undefined, logger?.child({ component: 'view-storage' }));\n\n // Determine data directory for events\n // Structure: <basePath>/events/...\n const dataDir = path.join(basePath, 'events');\n\n const eventStore = new EventStore(\n {\n ...config,\n basePath,\n dataDir,\n enableSharding: true,\n numShards: 65536, // 4 hex digits (0000-ffff)\n },\n viewStorage,\n identifierConfig,\n eventBus,\n logger\n );\n\n return eventStore;\n}\n","/**\n * Event Query - Read Operations\n *\n * Handles querying and reading events from storage:\n * - Query events with filters (type, user, timestamp, sequence)\n * - Get all events for a resource\n * - Get last event from a file\n * - Efficient streaming reads from JSONL files\n *\n * @see docs/EVENT-STORE.md#eventquery for architecture details\n */\n\nimport type { StoredEvent, EventQuery as EventQueryType, ResourceId } from '@semiont/core';\nimport type { EventStorage } from '../storage/event-storage';\n\n/**\n * EventQuery handles all read operations for events\n * Uses EventStorage for file access, adds query filtering\n */\nexport class EventQuery {\n constructor(private eventStorage: EventStorage) {}\n\n /**\n * Query events with filters\n * Supports filtering by: userId, eventTypes, timestamps, sequence number, limit\n */\n async queryEvents(query: EventQueryType): Promise<StoredEvent[]> {\n if (!query.resourceId) {\n throw new Error('resourceId is required for event queries');\n }\n\n // Get all events from storage\n const allEvents = await this.eventStorage.getAllEvents(query.resourceId);\n\n // Apply filters\n let results = allEvents;\n\n if (query.userId) {\n results = results.filter(e => e.event.userId === query.userId);\n }\n\n if (query.eventTypes && query.eventTypes.length > 0) {\n results = results.filter(e => query.eventTypes!.includes(e.event.type));\n }\n\n if (query.fromTimestamp) {\n results = results.filter(e => e.event.timestamp >= query.fromTimestamp!);\n }\n\n if (query.toTimestamp) {\n results = results.filter(e => e.event.timestamp <= query.toTimestamp!);\n }\n\n if (query.fromSequence) {\n results = results.filter(e => e.metadata.sequenceNumber >= query.fromSequence!);\n }\n\n // Apply limit\n if (query.limit && query.limit > 0) {\n results = results.slice(0, query.limit);\n }\n\n return results;\n }\n\n /**\n * Get all events for a specific resource (no filters)\n */\n async getResourceEvents(resourceId: ResourceId): Promise<StoredEvent[]> {\n return this.eventStorage.getAllEvents(resourceId);\n }\n\n /**\n * Get the last event from a specific file\n * Useful for initializing sequence numbers and last hashes\n */\n async getLastEvent(resourceId: ResourceId, filename: string): Promise<StoredEvent | null> {\n return this.eventStorage.getLastEvent(resourceId, filename);\n }\n\n /**\n * Get the latest event for a resource across all files\n */\n async getLatestEvent(resourceId: ResourceId): Promise<StoredEvent | null> {\n const files = await this.eventStorage.getEventFiles(resourceId);\n if (files.length === 0) return null;\n\n // Check files in reverse order (newest first)\n for (let i = files.length - 1; i >= 0; i--) {\n const file = files[i];\n if (!file) continue;\n const lastEvent = await this.eventStorage.getLastEvent(resourceId, file);\n if (lastEvent) return lastEvent;\n }\n\n return null;\n }\n\n /**\n * Get event count for a resource\n */\n async getEventCount(resourceId: ResourceId): Promise<number> {\n const events = await this.getResourceEvents(resourceId);\n return events.length;\n }\n\n /**\n * Check if a resource has any events\n */\n async hasEvents(resourceId: ResourceId): Promise<boolean> {\n const files = await this.eventStorage.getEventFiles(resourceId);\n return files.length > 0;\n }\n}\n","/**\n * Event Validator - Event Chain Integrity\n *\n * Validates event chain integrity using cryptographic hashing:\n * - prevEventHash links to previous event's checksum\n * - Each event's checksum is verified against its payload\n * - Detects broken chains and tampered events\n *\n * @see docs/EVENT-STORE.md#eventvalidator for architecture details\n */\n\nimport type { StoredEvent } from '@semiont/core';\nimport { sha256 } from '../storage/shard-utils';\n\nexport interface ValidationResult {\n valid: boolean;\n errors: string[];\n}\n\n/**\n * EventValidator verifies event chain integrity\n * Uses cryptographic checksums to detect broken chains or tampering\n */\nexport class EventValidator {\n /**\n * Validate event chain integrity for a resource's events\n * Checks that each event properly links to the previous event\n */\n validateEventChain(events: StoredEvent[]): ValidationResult {\n const errors: string[] = [];\n\n for (let i = 1; i < events.length; i++) {\n const prev = events[i - 1];\n const curr = events[i];\n\n if (!prev || !curr) continue;\n\n // Check prevEventHash points to previous event\n if (curr.metadata.prevEventHash !== prev.metadata.checksum) {\n errors.push(\n `Event chain broken at sequence ${curr.metadata.sequenceNumber}: ` +\n `prevEventHash=${curr.metadata.prevEventHash} but previous checksum=${prev.metadata.checksum}`\n );\n }\n\n // Verify checksum of current event\n const calculated = sha256(curr.event);\n if (calculated !== curr.metadata.checksum) {\n errors.push(\n `Checksum mismatch at sequence ${curr.metadata.sequenceNumber}: ` +\n `calculated=${calculated} but stored=${curr.metadata.checksum}`\n );\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n };\n }\n\n /**\n * Validate a single event's checksum\n * Useful for validating events before writing them\n */\n validateEventChecksum(event: StoredEvent): boolean {\n const calculated = sha256(event.event);\n return calculated === event.metadata.checksum;\n }\n\n /**\n * Validate that an event properly links to a previous event\n * Returns true if the link is valid or if this is the first event\n */\n validateEventLink(currentEvent: StoredEvent, previousEvent: StoredEvent | null): boolean {\n // First event in chain should have no prevEventHash\n if (!previousEvent) {\n return !currentEvent.metadata.prevEventHash;\n }\n\n // Subsequent events should link to previous event's checksum\n return currentEvent.metadata.prevEventHash === previousEvent.metadata.checksum;\n }\n}\n"]}
|
package/package.json
CHANGED