@semiont/event-sourcing 0.5.2 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/dist/event-log.d.ts +51 -0
- package/dist/event-log.d.ts.map +1 -0
- package/dist/event-store-factory.d.ts +19 -0
- package/dist/event-store-factory.d.ts.map +1 -0
- package/dist/event-store.d.ts +40 -0
- package/dist/event-store.d.ts.map +1 -0
- package/dist/identifier-utils.d.ts +10 -0
- package/dist/identifier-utils.d.ts.map +1 -0
- package/dist/index.d.ts +20 -566
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +80 -11
- package/dist/index.js.map +1 -1
- package/dist/query/event-query.d.ts +48 -0
- package/dist/query/event-query.d.ts.map +1 -0
- package/dist/storage/event-storage.d.ts +111 -0
- package/dist/storage/event-storage.d.ts.map +1 -0
- package/dist/storage/shard-utils.d.ts +56 -0
- package/dist/storage/shard-utils.d.ts.map +1 -0
- package/dist/storage/storage-uri-index.d.ts +60 -0
- package/dist/storage/storage-uri-index.d.ts.map +1 -0
- package/dist/storage/view-storage.d.ts +33 -0
- package/dist/storage/view-storage.d.ts.map +1 -0
- package/dist/view-manager.d.ts +84 -0
- package/dist/view-manager.d.ts.map +1 -0
- package/dist/views/projection-reducers.d.ts +73 -0
- package/dist/views/projection-reducers.d.ts.map +1 -0
- package/dist/views/view-materializer.d.ts +92 -0
- package/dist/views/view-materializer.d.ts.map +1 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -136,6 +136,17 @@ await eventStore.views.rebuildAll(eventStore.log);
|
|
|
136
136
|
|
|
137
137
|
The two paths use the same materialization primitives, so replaying event 1..N via `rebuildAll` produces the same final state as the live path walking 1..N over time.
|
|
138
138
|
|
|
139
|
+
#### Pure projection reducers
|
|
140
|
+
|
|
141
|
+
The `__system__` projections (`entitytypes.json`, `tagschemas.json`) are written by a thin I/O shell wrapping pure functions that own the merge/dedup/sort/conflict semantics. The pure reducers live in [`src/views/projection-reducers.ts`](src/views/projection-reducers.ts):
|
|
142
|
+
|
|
143
|
+
- `applyEntityTypeAdded(view, tag)` → `string[]` — dedup + locale-aware sort.
|
|
144
|
+
- `applyTagSchemaAdded(view, schema)` → `{ next; warning? }` — most-recent-wins by id, warning on overwrite-with-different-content.
|
|
145
|
+
|
|
146
|
+
The shell methods on `ViewMaterializer` (`materializeEntityTypes`, `materializeTagSchemas`) read the projection file, call the reducer, then write the result. The semantics are the reducer's; the disk I/O is the shell's.
|
|
147
|
+
|
|
148
|
+
This split keeps projection-update tests pure (single-digit milliseconds, no filesystem) and gives load-bearing invariants — sortedness, uniqueness, idempotence, most-recent-wins — a property-based-test home using fast-check. The full architectural narrative, the axiom catalog, and guidance for adding new projections lives in [`docs/system/PROJECTION-PATTERN.md`](../../docs/system/PROJECTION-PATTERN.md).
|
|
149
|
+
|
|
139
150
|
#### Why startup rebuild exists
|
|
140
151
|
|
|
141
152
|
The materialized views directory (`stateDir`) is **ephemeral by design** — it's safe to wipe (container recreation, `semiont destroy`, dev cleanup), and the event log under `.semiont/events/` is the single source of truth. `rebuildAll` is what makes "ephemeral" safe: any time `stateDir` goes empty, the next process start repopulates it from the event log.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EventLog - Event Persistence Layer
|
|
3
|
+
*
|
|
4
|
+
* Single Responsibility: Event persistence only
|
|
5
|
+
* - Appends events to storage (JSONL files)
|
|
6
|
+
* - Retrieves events by resource
|
|
7
|
+
* - Queries events with filters
|
|
8
|
+
*
|
|
9
|
+
* Does NOT handle:
|
|
10
|
+
* - Pub/sub notifications (see EventBus)
|
|
11
|
+
* - View updates (see ViewManager)
|
|
12
|
+
*/
|
|
13
|
+
import { type ResourceId, type StoredEvent, type EventQuery, type EventInput, type Logger } from '@semiont/core';
|
|
14
|
+
import type { SemiontProject } from '@semiont/core/node';
|
|
15
|
+
import { EventStorage } from './storage/event-storage';
|
|
16
|
+
export interface EventLogConfig {
|
|
17
|
+
project: SemiontProject;
|
|
18
|
+
enableSharding?: boolean;
|
|
19
|
+
maxEventsPerFile?: number;
|
|
20
|
+
}
|
|
21
|
+
export declare class EventLog {
|
|
22
|
+
readonly storage: EventStorage;
|
|
23
|
+
constructor(config: EventLogConfig, logger?: Logger);
|
|
24
|
+
/**
|
|
25
|
+
* Append event to log
|
|
26
|
+
* @param event - Resource event (from @semiont/core)
|
|
27
|
+
* @param resourceId - Branded ResourceId (from @semiont/core)
|
|
28
|
+
* @param options.correlationId - Optional command correlation id (stored on metadata)
|
|
29
|
+
* @returns Stored event with metadata (sequence number, timestamp, checksum)
|
|
30
|
+
*/
|
|
31
|
+
append(event: EventInput, resourceId: ResourceId, options?: {
|
|
32
|
+
correlationId?: string;
|
|
33
|
+
}): Promise<StoredEvent>;
|
|
34
|
+
/**
|
|
35
|
+
* Get all events for a resource
|
|
36
|
+
* @param resourceId - Branded ResourceId (from @semiont/core)
|
|
37
|
+
*/
|
|
38
|
+
getEvents(resourceId: ResourceId): Promise<StoredEvent[]>;
|
|
39
|
+
/**
|
|
40
|
+
* Get all resource IDs
|
|
41
|
+
* @returns Array of branded ResourceId types
|
|
42
|
+
*/
|
|
43
|
+
getAllResourceIds(): Promise<ResourceId[]>;
|
|
44
|
+
/**
|
|
45
|
+
* Query events with filter
|
|
46
|
+
* @param resourceId - Branded ResourceId (from @semiont/core)
|
|
47
|
+
* @param filter - Optional event filter
|
|
48
|
+
*/
|
|
49
|
+
queryEvents(resourceId: ResourceId, filter?: EventQuery): Promise<StoredEvent[]>;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=event-log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-log.d.ts","sourceRoot":"","sources":["../src/event-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AACjH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,cAAc,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,QAAQ;IAEnB,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;gBAEnB,MAAM,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,MAAM;IAOnD;;;;;;OAMG;IACG,MAAM,CACV,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,UAAU,EACtB,OAAO,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GACnC,OAAO,CAAC,WAAW,CAAC;IAIvB;;;OAGG;IACG,SAAS,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAI/D;;;OAGG;IACG,iBAAiB,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAIhD;;;;OAIG;IACG,WAAW,CAAC,UAAU,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;CAavF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event Store Factory
|
|
3
|
+
*
|
|
4
|
+
* Factory function for creating EventStore instances with standard configuration.
|
|
5
|
+
* This is the canonical way to instantiate an EventStore.
|
|
6
|
+
*/
|
|
7
|
+
import type { SemiontProject } from '@semiont/core/node';
|
|
8
|
+
import type { EventBus as CoreEventBus, Logger } from '@semiont/core';
|
|
9
|
+
import { EventStore } from './event-store';
|
|
10
|
+
/**
|
|
11
|
+
* Create and initialize an EventStore instance
|
|
12
|
+
*
|
|
13
|
+
* @param project - SemiontProject instance
|
|
14
|
+
* @param eventBus - @semiont/core EventBus for publishing domain events
|
|
15
|
+
* @param logger - Optional logger for structured logging
|
|
16
|
+
* @returns Configured EventStore instance ready for use
|
|
17
|
+
*/
|
|
18
|
+
export declare function createEventStore(project: SemiontProject, eventBus: CoreEventBus, logger?: Logger): EventStore;
|
|
19
|
+
//# sourceMappingURL=event-store-factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-store-factory.d.ts","sourceRoot":"","sources":["../src/event-store-factory.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,QAAQ,IAAI,YAAY,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,YAAY,EACtB,MAAM,CAAC,EAAE,MAAM,GACd,UAAU,CAUZ"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EventStore - Orchestration Layer
|
|
3
|
+
*
|
|
4
|
+
* Coordinates event sourcing operations:
|
|
5
|
+
* - EventLog: Event persistence (append, retrieve, query)
|
|
6
|
+
* - ViewManager: View materialization (resource and system)
|
|
7
|
+
* - Core EventBus: Publishes StoredEvent to typed channels after persistence
|
|
8
|
+
*
|
|
9
|
+
* appendEvent() is the single write path:
|
|
10
|
+
* 1. Persist to EventLog
|
|
11
|
+
* 2. Materialize views
|
|
12
|
+
* 3. Enrich (optional callback — attach post-materialization data)
|
|
13
|
+
* 4. Publish StoredEvent to global and resource-scoped typed channels
|
|
14
|
+
*/
|
|
15
|
+
import type { EventInput, StoredEvent, ResourceId, Logger } from '@semiont/core';
|
|
16
|
+
import { EventBus as CoreEventBus } from '@semiont/core';
|
|
17
|
+
import type { SemiontProject } from '@semiont/core/node';
|
|
18
|
+
import type { ViewStorage } from './storage/view-storage';
|
|
19
|
+
import { EventLog } from './event-log';
|
|
20
|
+
import { ViewManager } from './view-manager';
|
|
21
|
+
export type EnrichEvent = (event: StoredEvent, resourceId: ResourceId) => Promise<StoredEvent>;
|
|
22
|
+
export declare class EventStore {
|
|
23
|
+
readonly log: EventLog;
|
|
24
|
+
readonly views: ViewManager;
|
|
25
|
+
readonly viewStorage: ViewStorage;
|
|
26
|
+
readonly coreEventBus: CoreEventBus;
|
|
27
|
+
private enrichEvent;
|
|
28
|
+
constructor(project: SemiontProject, stateDir: string, viewStorage: ViewStorage, coreEventBus: CoreEventBus, logger?: Logger);
|
|
29
|
+
setEnrichEvent(fn: EnrichEvent): void;
|
|
30
|
+
/**
|
|
31
|
+
* Append an event to the store
|
|
32
|
+
* Coordinates: persistence → view → enrich → notification
|
|
33
|
+
*
|
|
34
|
+
* @param options.correlationId - Optional id propagated from a command.
|
|
35
|
+
*/
|
|
36
|
+
appendEvent(event: EventInput, options?: {
|
|
37
|
+
correlationId?: string;
|
|
38
|
+
}): Promise<StoredEvent>;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=event-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-store.d.ts","sourceRoot":"","sources":["../src/event-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,UAAU,EACV,MAAM,EACP,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,IAAI,YAAY,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,WAAW,EAA0B,MAAM,gBAAgB,CAAC;AAErE,MAAM,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;AAE/F,qBAAa,UAAU;IACrB,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,OAAO,CAAC,WAAW,CAA4B;gBAG7C,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,WAAW,EACxB,YAAY,EAAE,YAAY,EAC1B,MAAM,CAAC,EAAE,MAAM;IAajB,cAAc,CAAC,EAAE,EAAE,WAAW,GAAG,IAAI;IAIrC;;;;;OAKG;IACG,WAAW,CACf,KAAK,EAAE,UAAU,EACjB,OAAO,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GACnC,OAAO,CAAC,WAAW,CAAC;CAoCxB"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identifier utilities for event sourcing
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Generate a unique annotation ID (bare nanoid)
|
|
6
|
+
*
|
|
7
|
+
* @returns A bare annotation ID (e.g., "V1StGXR8_Z5jdHi6B-myT")
|
|
8
|
+
*/
|
|
9
|
+
export declare function generateAnnotationId(): string;
|
|
10
|
+
//# sourceMappingURL=identifier-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identifier-utils.d.ts","sourceRoot":"","sources":["../src/identifier-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C"}
|