@eventualize/core 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/EvDbStream.test.js +10 -16
  2. package/dist/EvDbStream.test.js.map +1 -1
  3. package/dist/adapters/IEvDbStorageAdapter.d.ts +7 -0
  4. package/dist/adapters/IEvDbStorageAdapter.js +2 -0
  5. package/dist/adapters/IEvDbStorageAdapter.js.map +1 -0
  6. package/dist/codegen/generateStreamFactory.d.ts +18 -0
  7. package/dist/codegen/generateStreamFactory.js +97 -0
  8. package/dist/codegen/generateStreamFactory.js.map +1 -0
  9. package/dist/factories/EvDbStreamFactory.d.ts +51 -0
  10. package/dist/factories/EvDbStreamFactory.js +103 -0
  11. package/dist/factories/EvDbStreamFactory.js.map +1 -0
  12. package/dist/factories/EvDbStreamFactoryTypes.d.ts +20 -0
  13. package/dist/factories/EvDbStreamFactoryTypes.js +2 -0
  14. package/dist/factories/EvDbStreamFactoryTypes.js.map +1 -0
  15. package/dist/factories/EvDbViewFactory.d.ts +24 -0
  16. package/dist/{EvDbViewFactory.js → factories/EvDbViewFactory.js} +4 -4
  17. package/dist/factories/EvDbViewFactory.js.map +1 -0
  18. package/dist/factories/EvDbViewFactoryTypes.d.ts +24 -0
  19. package/dist/factories/EvDbViewFactoryTypes.js +2 -0
  20. package/dist/factories/EvDbViewFactoryTypes.js.map +1 -0
  21. package/dist/factories/IEvDbStreamFactory.d.ts +13 -0
  22. package/dist/factories/IEvDbStreamFactory.js +2 -0
  23. package/dist/factories/IEvDbStreamFactory.js.map +1 -0
  24. package/dist/factories/StreamFactoryBuilder.d.ts +35 -0
  25. package/dist/factories/StreamFactoryBuilder.js +67 -0
  26. package/dist/factories/StreamFactoryBuilder.js.map +1 -0
  27. package/dist/store/EvDbStream.d.ts +150 -0
  28. package/dist/store/EvDbStream.js +192 -0
  29. package/dist/store/EvDbStream.js.map +1 -0
  30. package/dist/stream/IEvDbStream.d.ts +0 -0
  31. package/dist/stream/IEvDbStream.js +2 -0
  32. package/dist/stream/IEvDbStream.js.map +1 -0
  33. package/dist/view/EvDbView.d.ts +19 -0
  34. package/dist/view/EvDbView.js +26 -0
  35. package/dist/view/EvDbView.js.map +1 -0
  36. package/dist/view/EvDbViewRaw.d.ts +22 -0
  37. package/dist/view/EvDbViewRaw.js +41 -0
  38. package/dist/view/EvDbViewRaw.js.map +1 -0
  39. package/package.json +2 -2
  40. package/dist/EvDbEventStore.d.ts +0 -123
  41. package/dist/EvDbEventStore.js +0 -182
  42. package/dist/EvDbEventStore.js.map +0 -1
  43. package/dist/EvDbStream.d.ts +0 -49
  44. package/dist/EvDbStream.js +0 -115
  45. package/dist/EvDbStream.js.map +0 -1
  46. package/dist/EvDbStreamFactory.d.ts +0 -97
  47. package/dist/EvDbStreamFactory.js +0 -155
  48. package/dist/EvDbStreamFactory.js.map +0 -1
  49. package/dist/EvDbView.d.ts +0 -34
  50. package/dist/EvDbView.js +0 -64
  51. package/dist/EvDbView.js.map +0 -1
  52. package/dist/EvDbViewFactory.d.ts +0 -45
  53. package/dist/EvDbViewFactory.js.map +0 -1
@@ -0,0 +1,150 @@
1
+ import EvDbEvent from "@eventualize/types/events/EvDbEvent";
2
+ import type EvDbMessage from "@eventualize/types/messages/EvDbMessage";
3
+ import type IEvDbStorageStreamAdapter from "@eventualize/types/adapters/IEvDbStorageStreamAdapter";
4
+ import type IEvDbView from "@eventualize/types/view/IEvDbView";
5
+ import EvDbStreamAddress from "@eventualize/types/stream/EvDbStreamAddress";
6
+ import type IEvDbStreamStore from "@eventualize/types/store/IEvDbStreamStore";
7
+ import type IEvDbStreamStoreData from "@eventualize/types/store/IEvDbStreamStoreData";
8
+ import type IEvDbEventPayload from "@eventualize/types/events/IEvDbEventPayload";
9
+ import StreamStoreAffected from "@eventualize/types/stream/StreamStoreAffected";
10
+ import type IEvDbEventMetadata from "@eventualize/types/events/IEvDbEventMetadata";
11
+ import type { EvDbStreamType } from "@eventualize/types/primitives/EvDbStreamType";
12
+ import type EVDbMessagesProducer from "@eventualize/types/messages/EvDbMessagesProducer";
13
+ import type { EvDbView } from "../view/EvDbView.js";
14
+ type ImmutableIEvDbView = Readonly<EvDbView<unknown>>;
15
+ /**
16
+ * A read-only map of view name to view instance for a stream.
17
+ * Use this type when you need to pass or store the full set of a stream's views
18
+ * without allowing structural mutation.
19
+ */
20
+ export type ImmutableIEvDbViewMap = Readonly<Record<string, ImmutableIEvDbView>>;
21
+ /**
22
+ * Core event-sourcing stream that coordinates event appending, view projection,
23
+ * outbox message production, and optimistic-concurrency-controlled persistence.
24
+ *
25
+ * Use `EvDbStream` as the base class for all domain streams. It implements
26
+ * `IEvDbStreamStore` (store/query pending events) and `IEvDbStreamStoreData`
27
+ * (access unspecialized events, messages, and views) so consumers can work
28
+ * against those interfaces without coupling to this concrete class.
29
+ */
30
+ export default class EvDbStream implements IEvDbStreamStore, IEvDbStreamStoreData {
31
+ protected messagesProducer: EVDbMessagesProducer;
32
+ protected _pendingEvents: ReadonlyArray<EvDbEvent>;
33
+ protected _pendingMessages: ReadonlyArray<EvDbMessage>;
34
+ private static readonly ASSEMBLY_NAME;
35
+ private static readonly DEFAULT_CAPTURE_BY;
36
+ private readonly _storageAdapter;
37
+ protected readonly _views: ImmutableIEvDbViewMap;
38
+ /**
39
+ * Returns all views registered on this stream, keyed by view name.
40
+ * Use this when you need to inspect or iterate over every projection without
41
+ * knowing the view names up-front (e.g. generic tooling or serialization).
42
+ */
43
+ getViews(): ImmutableIEvDbViewMap;
44
+ /**
45
+ * Returns a single view by its name, or `undefined` if not registered.
46
+ * Use this for targeted access to a specific projection when you know the
47
+ * view name at call-site (prefer typed accessors on concrete subclasses when
48
+ * available).
49
+ */
50
+ getView(viewName: string): Readonly<IEvDbView> | undefined;
51
+ /**
52
+ * Returns the full list of pending (not-yet-stored) events as untyped
53
+ * `EvDbEvent` instances.
54
+ * Use this when you need generic/unspecialized access to the pending event
55
+ * list, e.g. for logging, debugging, or framework-level inspection.
56
+ * Strongly-typed subclasses may expose a narrower accessor instead.
57
+ */
58
+ getEvents(): ReadonlyArray<EvDbEvent>;
59
+ /**
60
+ * The unique address that identifies this stream instance, combining the
61
+ * stream type and stream ID.
62
+ * Use this to correlate events, cursors, and log entries back to a specific
63
+ * stream without holding a reference to the full stream object.
64
+ */
65
+ streamAddress: EvDbStreamAddress;
66
+ /**
67
+ * The offset of the last event successfully persisted to storage.
68
+ * Use this to determine the persistence watermark of the stream — it is
69
+ * updated after each successful `store()` call and drives OCC conflict
70
+ * detection on the next write.
71
+ */
72
+ storedOffset: number;
73
+ /**
74
+ * Constructs a new stream instance, wiring together storage, views, and
75
+ * the outbox message producer.
76
+ *
77
+ * You should not call this constructor directly; use the stream factory
78
+ * (e.g. `EvDbStreamFactory`) so that the adapter, views, and producer are
79
+ * configured consistently.
80
+ *
81
+ * @param streamType - Descriptor that categorises the stream (domain + version).
82
+ * @param views - Projection views that fold events into query-ready state.
83
+ * @param storageAdapter - Adapter used to persist events and outbox messages.
84
+ * @param streamId - Instance-level identifier that, together with `streamType`,
85
+ * uniquely addresses this stream.
86
+ * @param lastStoredOffset - Offset of the last event already in storage; used as
87
+ * the starting cursor and for OCC checks.
88
+ * @param messagesProducer - Function invoked after each `appendEvent` to derive
89
+ * outbox messages from the new event and current view states.
90
+ */
91
+ constructor(streamType: EvDbStreamType, views: ImmutableIEvDbView[], storageAdapter: IEvDbStorageStreamAdapter, streamId: string, lastStoredOffset: number, messagesProducer: EVDbMessagesProducer);
92
+ /**
93
+ * Appends a domain event to the pending list, applies it to all registered
94
+ * views, and invokes the outbox producer to derive any resulting messages.
95
+ *
96
+ * Use this in concrete subclass methods (e.g. `deposited(amount)`) rather than
97
+ * calling storage directly. The event is **not** persisted until `store()` is
98
+ * called, so multiple `appendEvent` calls can be batched into a single atomic
99
+ * write.
100
+ *
101
+ * @param payload - Typed event payload; `payloadType` must match a type
102
+ * registered on this stream's factory.
103
+ * @param capturedBy - Optional label identifying who/what produced this event
104
+ * (defaults to the core assembly identifier).
105
+ * @returns The populated event metadata (cursor, timestamp, capturedBy).
106
+ */
107
+ protected appendEvent(payload: IEvDbEventPayload, capturedBy?: string | null): IEvDbEventMetadata;
108
+ private getNextCursor;
109
+ /**
110
+ * Manually inserts a message into the pending outbox without going through
111
+ * the domain event flow.
112
+ *
113
+ * Use this when you need to publish a notification or integration event that
114
+ * is not a direct consequence of a domain event — for example, a saga
115
+ * coordination message or a manually triggered notification. For event-driven
116
+ * messages prefer the `messagesProducer` callback passed to the constructor,
117
+ * which fires automatically inside `appendEvent`.
118
+ */
119
+ appendToOutbox(e: EvDbMessage): void;
120
+ /**
121
+ * Atomically persists all pending events and outbox messages to storage,
122
+ * advances `storedOffset`, potentialy saves view snapshots, and clears the pending
123
+ * buffers.
124
+ *
125
+ * Use this once you have finished building up a unit of work via one or more
126
+ * `appendEvent` / `appendToOutbox` calls. The call is a no-op (returns
127
+ * `StreamStoreAffected.Empty`) when there are no pending events. Throws
128
+ * `OCCException` if another writer has already stored events at or beyond
129
+ * the current `storedOffset` (optimistic concurrency conflict).
130
+ *
131
+ * @returns A `StreamStoreAffected` value describing how many events and
132
+ * outbox messages were written.
133
+ */
134
+ store(): Promise<StreamStoreAffected>;
135
+ /**
136
+ * The number of events appended since the last successful `store()` call.
137
+ * Use this to guard against accidentally calling `store()` with an empty
138
+ * batch or to implement pre-store validation that requires at least one event.
139
+ */
140
+ get countOfPendingEvents(): number;
141
+ /**
142
+ * Returns the full list of pending outbox messages (integration events,
143
+ * notifications, saga commands) that have not yet been stored.
144
+ * Use this for generic/unspecialized access — e.g. framework-level
145
+ * inspection, testing, or logging — when you do not need message-type
146
+ * discrimination. Persisted alongside events during `store()`.
147
+ */
148
+ getMessages(): ReadonlyArray<EvDbMessage>;
149
+ }
150
+ export {};
@@ -0,0 +1,192 @@
1
+ import EvDbEvent from "@eventualize/types/events/EvDbEvent";
2
+ import EvDbStreamAddress from "@eventualize/types/stream/EvDbStreamAddress";
3
+ import StreamStoreAffected from "@eventualize/types/stream/StreamStoreAffected";
4
+ import EvDbStreamCursor from "@eventualize/types/stream/EvDbStreamCursor";
5
+ import OCCException from "@eventualize/types/primitives/OCCException";
6
+ /**
7
+ * Core event-sourcing stream that coordinates event appending, view projection,
8
+ * outbox message production, and optimistic-concurrency-controlled persistence.
9
+ *
10
+ * Use `EvDbStream` as the base class for all domain streams. It implements
11
+ * `IEvDbStreamStore` (store/query pending events) and `IEvDbStreamStoreData`
12
+ * (access unspecialized events, messages, and views) so consumers can work
13
+ * against those interfaces without coupling to this concrete class.
14
+ */
15
+ class EvDbStream {
16
+ /**
17
+ * Returns all views registered on this stream, keyed by view name.
18
+ * Use this when you need to inspect or iterate over every projection without
19
+ * knowing the view names up-front (e.g. generic tooling or serialization).
20
+ */
21
+ getViews() {
22
+ return this._views;
23
+ }
24
+ /**
25
+ * Returns a single view by its name, or `undefined` if not registered.
26
+ * Use this for targeted access to a specific projection when you know the
27
+ * view name at call-site (prefer typed accessors on concrete subclasses when
28
+ * available).
29
+ */
30
+ getView(viewName) {
31
+ return this._views[viewName];
32
+ }
33
+ /**
34
+ * Returns the full list of pending (not-yet-stored) events as untyped
35
+ * `EvDbEvent` instances.
36
+ * Use this when you need generic/unspecialized access to the pending event
37
+ * list, e.g. for logging, debugging, or framework-level inspection.
38
+ * Strongly-typed subclasses may expose a narrower accessor instead.
39
+ */
40
+ getEvents() {
41
+ return this._pendingEvents;
42
+ }
43
+ /**
44
+ * Constructs a new stream instance, wiring together storage, views, and
45
+ * the outbox message producer.
46
+ *
47
+ * You should not call this constructor directly; use the stream factory
48
+ * (e.g. `EvDbStreamFactory`) so that the adapter, views, and producer are
49
+ * configured consistently.
50
+ *
51
+ * @param streamType - Descriptor that categorises the stream (domain + version).
52
+ * @param views - Projection views that fold events into query-ready state.
53
+ * @param storageAdapter - Adapter used to persist events and outbox messages.
54
+ * @param streamId - Instance-level identifier that, together with `streamType`,
55
+ * uniquely addresses this stream.
56
+ * @param lastStoredOffset - Offset of the last event already in storage; used as
57
+ * the starting cursor and for OCC checks.
58
+ * @param messagesProducer - Function invoked after each `appendEvent` to derive
59
+ * outbox messages from the new event and current view states.
60
+ */
61
+ constructor(streamType, views, storageAdapter, streamId, lastStoredOffset, messagesProducer) {
62
+ this.messagesProducer = messagesProducer;
63
+ this._pendingEvents = [];
64
+ this._pendingMessages = [];
65
+ this._views = views.reduce((acc, view) => {
66
+ const viewName = view.address.viewName;
67
+ acc[viewName] = view;
68
+ return acc;
69
+ }, {});
70
+ this._storageAdapter = storageAdapter;
71
+ this.streamAddress = new EvDbStreamAddress(streamType, streamId);
72
+ this.storedOffset = lastStoredOffset;
73
+ }
74
+ /**
75
+ * Appends a domain event to the pending list, applies it to all registered
76
+ * views, and invokes the outbox producer to derive any resulting messages.
77
+ *
78
+ * Use this in concrete subclass methods (e.g. `deposited(amount)`) rather than
79
+ * calling storage directly. The event is **not** persisted until `store()` is
80
+ * called, so multiple `appendEvent` calls can be batched into a single atomic
81
+ * write.
82
+ *
83
+ * @param payload - Typed event payload; `payloadType` must match a type
84
+ * registered on this stream's factory.
85
+ * @param capturedBy - Optional label identifying who/what produced this event
86
+ * (defaults to the core assembly identifier).
87
+ * @returns The populated event metadata (cursor, timestamp, capturedBy).
88
+ */
89
+ appendEvent(payload, capturedBy) {
90
+ capturedBy = capturedBy ?? EvDbStream.DEFAULT_CAPTURE_BY;
91
+ // const json = JSON.stringify(payload); // Or use custom serializer
92
+ const cursor = this.getNextCursor(this._pendingEvents);
93
+ const e = new EvDbEvent(payload.payloadType, cursor, payload, new Date(), capturedBy);
94
+ this._pendingEvents = [...this._pendingEvents, e];
95
+ // Apply to views
96
+ for (const view of Object.values(this._views)) {
97
+ view.applyEvent(e);
98
+ }
99
+ // Outbox producer
100
+ const viewsStates = Object.fromEntries(Object.entries(this._views).map(([k, v]) => {
101
+ return [k, v.state];
102
+ }));
103
+ const producedMessages = this.messagesProducer(e, viewsStates);
104
+ this._pendingMessages = [...this._pendingMessages, ...producedMessages];
105
+ return e;
106
+ }
107
+ getNextCursor(events) {
108
+ if (events.length === 0) {
109
+ return new EvDbStreamCursor(this.streamAddress, this.storedOffset + 1);
110
+ }
111
+ const lastEvent = events[events.length - 1];
112
+ const offset = lastEvent.streamCursor.offset;
113
+ return new EvDbStreamCursor(this.streamAddress, offset + 1);
114
+ }
115
+ /**
116
+ * Manually inserts a message into the pending outbox without going through
117
+ * the domain event flow.
118
+ *
119
+ * Use this when you need to publish a notification or integration event that
120
+ * is not a direct consequence of a domain event — for example, a saga
121
+ * coordination message or a manually triggered notification. For event-driven
122
+ * messages prefer the `messagesProducer` callback passed to the constructor,
123
+ * which fires automatically inside `appendEvent`.
124
+ */
125
+ appendToOutbox(e) {
126
+ this._pendingMessages = [...this._pendingMessages, e];
127
+ }
128
+ /**
129
+ * Atomically persists all pending events and outbox messages to storage,
130
+ * advances `storedOffset`, potentialy saves view snapshots, and clears the pending
131
+ * buffers.
132
+ *
133
+ * Use this once you have finished building up a unit of work via one or more
134
+ * `appendEvent` / `appendToOutbox` calls. The call is a no-op (returns
135
+ * `StreamStoreAffected.Empty`) when there are no pending events. Throws
136
+ * `OCCException` if another writer has already stored events at or beyond
137
+ * the current `storedOffset` (optimistic concurrency conflict).
138
+ *
139
+ * @returns A `StreamStoreAffected` value describing how many events and
140
+ * outbox messages were written.
141
+ */
142
+ async store() {
143
+ // Telemetry
144
+ // const tags = this.streamAddress.toOtelTags();
145
+ // const duration = EvDbStream._sysMeters.measureStoreEventsDuration(tags);
146
+ // const activity = EvDbStream._trace.startActivity(tags, 'EvDb.Store');
147
+ try {
148
+ if (this._pendingEvents.length === 0) {
149
+ return StreamStoreAffected.Empty;
150
+ }
151
+ const affected = await this._storageAdapter.storeStreamAsync(this._pendingEvents, this._pendingMessages);
152
+ const lastEvent = this._pendingEvents[this._pendingEvents.length - 1];
153
+ this.storedOffset = lastEvent.streamCursor.offset;
154
+ this._pendingEvents = [];
155
+ this._pendingMessages = [];
156
+ const viewSaveTasks = Object.values(this._views).map((v) => v.store());
157
+ await Promise.all(viewSaveTasks);
158
+ return affected;
159
+ }
160
+ catch (error) {
161
+ if (error instanceof OCCException) {
162
+ throw error;
163
+ }
164
+ throw error;
165
+ }
166
+ }
167
+ /**
168
+ * The number of events appended since the last successful `store()` call.
169
+ * Use this to guard against accidentally calling `store()` with an empty
170
+ * batch or to implement pre-store validation that requires at least one event.
171
+ */
172
+ get countOfPendingEvents() {
173
+ return this._pendingEvents.length;
174
+ }
175
+ /**
176
+ * Returns the full list of pending outbox messages (integration events,
177
+ * notifications, saga commands) that have not yet been stored.
178
+ * Use this for generic/unspecialized access — e.g. framework-level
179
+ * inspection, testing, or logging — when you do not need message-type
180
+ * discrimination. Persisted alongside events during `store()`.
181
+ */
182
+ getMessages() {
183
+ return this._pendingMessages;
184
+ }
185
+ }
186
+ EvDbStream.ASSEMBLY_NAME = {
187
+ name: "evdb-core",
188
+ version: "1.0.0",
189
+ };
190
+ EvDbStream.DEFAULT_CAPTURE_BY = `${EvDbStream.ASSEMBLY_NAME.name}-${EvDbStream.ASSEMBLY_NAME.version}`;
191
+ export default EvDbStream;
192
+ //# sourceMappingURL=EvDbStream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EvDbStream.js","sourceRoot":"","sources":["../../src/store/EvDbStream.ts"],"names":[],"mappings":"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"}
File without changes
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ //# sourceMappingURL=IEvDbStream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IEvDbStream.js","sourceRoot":"","sources":["../../src/stream/IEvDbStream.ts"],"names":[],"mappings":""}
@@ -0,0 +1,19 @@
1
+ import type { IEvDbViewStoreGeneric } from "@eventualize/types/view/IEvDbViewStoreGeneric";
2
+ import type EvDbViewAddress from "@eventualize/types/view/EvDbViewAddress";
3
+ import type IEvDbStorageSnapshotAdapter from "@eventualize/types/adapters/IEvDbStorageSnapshotAdapter";
4
+ import { EvDbStoredSnapshotData } from "@eventualize/types/snapshots/EvDbStoredSnapshotData";
5
+ import type { EvDbStoredSnapshotResult } from "@eventualize/types/snapshots/EvDbStoredSnapshotResult";
6
+ import type IEvDbEventMetadata from "@eventualize/types/events/IEvDbEventMetadata";
7
+ import type IEvDbEventPayload from "@eventualize/types/events/IEvDbEventPayload";
8
+ import type EvDbEvent from "@eventualize/types/events/EvDbEvent";
9
+ import { EvDbViewRaw } from "./EvDbViewRaw.js";
10
+ export declare abstract class EvDbView<TState> extends EvDbViewRaw implements IEvDbViewStoreGeneric<TState> {
11
+ readonly defaultState: TState;
12
+ protected getDefaultState(): TState;
13
+ protected _state: TState;
14
+ get state(): TState;
15
+ constructor(address: EvDbViewAddress, storageAdapter: IEvDbStorageSnapshotAdapter, snapshot: EvDbStoredSnapshotResult<TState>, defaultState: TState);
16
+ getSnapshotData(): EvDbStoredSnapshotData;
17
+ abstract handleOnApply(oldState: TState, event: IEvDbEventPayload, metadata: IEvDbEventMetadata): TState;
18
+ protected onApplyEvent(e: EvDbEvent): void;
19
+ }
@@ -0,0 +1,26 @@
1
+ import { EvDbStoredSnapshotData } from "@eventualize/types/snapshots/EvDbStoredSnapshotData";
2
+ import { EvDbViewRaw } from "./EvDbViewRaw.js";
3
+ export class EvDbView extends EvDbViewRaw {
4
+ getDefaultState() {
5
+ return this.defaultState;
6
+ }
7
+ get state() {
8
+ return this._state;
9
+ }
10
+ constructor(address, storageAdapter, snapshot, defaultState) {
11
+ super(storageAdapter, address, snapshot);
12
+ this.defaultState = defaultState;
13
+ this._state = this.getDefaultState();
14
+ if (snapshot.offset === 0)
15
+ this._state = this.getDefaultState();
16
+ else
17
+ this._state = snapshot.state;
18
+ }
19
+ getSnapshotData() {
20
+ return EvDbStoredSnapshotData.fromAddress(this.address, this.memoryOffset, this.storeOffset, this._state);
21
+ }
22
+ onApplyEvent(e) {
23
+ this._state = this.handleOnApply(this._state, e.payload, e);
24
+ }
25
+ }
26
+ //# sourceMappingURL=EvDbView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EvDbView.js","sourceRoot":"","sources":["../../src/view/EvDbView.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,sBAAsB,EAAE,MAAM,qDAAqD,CAAC;AAK7F,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,MAAM,OAAgB,QACpB,SAAQ,WAAW;IAGT,eAAe;QACvB,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,YACE,OAAwB,EACxB,cAA2C,EAC3C,QAA0C,EAC1B,YAAoB;QAEpC,KAAK,CAAC,cAAc,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QAFzB,iBAAY,GAAZ,YAAY,CAAQ;QAT5B,WAAM,GAAW,IAAI,CAAC,eAAe,EAAE,CAAC;QAYhD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;;YAC3D,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC;IACpC,CAAC;IAED,eAAe;QACb,OAAO,sBAAsB,CAAC,WAAW,CACvC,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,YAAY,EACjB,IAAI,CAAC,WAAW,EAChB,IAAI,CAAC,MAAM,CACZ,CAAC;IACJ,CAAC;IAQS,YAAY,CAAC,CAAY;QACjC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAC9D,CAAC;CACF"}
@@ -0,0 +1,22 @@
1
+ import type IEvDbViewStore from "@eventualize/types/view/IEvDbViewStore";
2
+ import type EvDbViewAddress from "@eventualize/types/view/EvDbViewAddress";
3
+ import type IEvDbStorageSnapshotAdapter from "@eventualize/types/adapters/IEvDbStorageSnapshotAdapter";
4
+ import type EvDbEvent from "@eventualize/types/events/EvDbEvent";
5
+ import type { EvDbStoredSnapshotData } from "@eventualize/types/snapshots/EvDbStoredSnapshotData";
6
+ import type { EvDbStoredSnapshotResult } from "@eventualize/types/snapshots/EvDbStoredSnapshotResult";
7
+ export declare abstract class EvDbViewRaw implements IEvDbViewStore {
8
+ private readonly _storageAdapter;
9
+ readonly address: EvDbViewAddress;
10
+ private _memoryOffset;
11
+ private _storeOffset;
12
+ private _storedAt;
13
+ protected constructor(_storageAdapter: IEvDbStorageSnapshotAdapter, address: EvDbViewAddress, snapshot: EvDbStoredSnapshotResult<any>);
14
+ abstract getSnapshotData(): EvDbStoredSnapshotData;
15
+ get storedAt(): Date;
16
+ get storeOffset(): number;
17
+ get memoryOffset(): number;
18
+ shouldStoreSnapshot(_offsetGapFromLastSave: number, _durationSinceLastSaveMs: number): boolean;
19
+ applyEvent(e: EvDbEvent): void;
20
+ store(): Promise<void>;
21
+ protected abstract onApplyEvent(e: EvDbEvent): void;
22
+ }
@@ -0,0 +1,41 @@
1
+ export class EvDbViewRaw {
2
+ constructor(_storageAdapter, address, snapshot) {
3
+ this._storageAdapter = _storageAdapter;
4
+ this.address = address;
5
+ const storeOffset = snapshot.offset ?? 0;
6
+ this._memoryOffset = storeOffset;
7
+ this._storeOffset = storeOffset;
8
+ this._storedAt = snapshot.storedAt ?? new Date();
9
+ }
10
+ get storedAt() {
11
+ return this._storedAt;
12
+ }
13
+ get storeOffset() {
14
+ return this._storeOffset;
15
+ }
16
+ get memoryOffset() {
17
+ return this._memoryOffset;
18
+ }
19
+ shouldStoreSnapshot(_offsetGapFromLastSave, _durationSinceLastSaveMs) {
20
+ return true;
21
+ }
22
+ applyEvent(e) {
23
+ const offset = e.streamCursor.offset;
24
+ if (this.memoryOffset >= offset) {
25
+ return;
26
+ }
27
+ this.onApplyEvent(e);
28
+ this._memoryOffset = offset;
29
+ }
30
+ async store() {
31
+ const eventsSinceLatestSnapshot = this.memoryOffset - this.storeOffset;
32
+ const secondsSinceLatestSnapshot = new Date().getTime() - this.storedAt.getTime();
33
+ if (!this.shouldStoreSnapshot(eventsSinceLatestSnapshot, secondsSinceLatestSnapshot)) {
34
+ return;
35
+ }
36
+ const snapshotData = this.getSnapshotData();
37
+ await this._storageAdapter.storeSnapshotAsync(snapshotData);
38
+ this._storeOffset = this._memoryOffset;
39
+ }
40
+ }
41
+ //# sourceMappingURL=EvDbViewRaw.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EvDbViewRaw.js","sourceRoot":"","sources":["../../src/view/EvDbViewRaw.ts"],"names":[],"mappings":"AAOA,MAAM,OAAgB,WAAW;IAK/B,YACmB,eAA4C,EAC7C,OAAwB,EACxC,QAAuC;QAFtB,oBAAe,GAAf,eAAe,CAA6B;QAC7C,YAAO,GAAP,OAAO,CAAiB;QAGxC,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,CAAC;QACzC,IAAI,CAAC,aAAa,GAAG,WAAW,CAAC;QACjC,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAEhC,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,QAAQ,IAAI,IAAI,IAAI,EAAE,CAAC;IACnD,CAAC;IAGD,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IACD,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IACD,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED,mBAAmB,CAAC,sBAA8B,EAAE,wBAAgC;QAClF,OAAO,IAAI,CAAC;IACd,CAAC;IACD,UAAU,CAAC,CAAY;QACrB,MAAM,MAAM,GAAG,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC;QACrC,IAAI,IAAI,CAAC,YAAY,IAAI,MAAM,EAAE,CAAC;YAChC,OAAO;QACT,CAAC;QACD,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACrB,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,yBAAyB,GAAG,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC;QACvE,MAAM,0BAA0B,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;QAClF,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,yBAAyB,EAAE,0BAA0B,CAAC,EAAE,CAAC;YACrF,OAAO;QACT,CAAC;QACD,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QAC5C,MAAM,IAAI,CAAC,eAAe,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC;QAC5D,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,aAAa,CAAC;IACzC,CAAC;CAGF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventualize/core",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",
@@ -29,7 +29,7 @@
29
29
  "test": "echo not tests implemented yet."
30
30
  },
31
31
  "dependencies": {
32
- "@eventualize/types": "2.0.0"
32
+ "@eventualize/types": "3.0.0"
33
33
  },
34
34
  "license": "ISC",
35
35
  "type": "module",
@@ -1,123 +0,0 @@
1
- import EvDbStream from './EvDbStream.js';
2
- import IEvDbStorageSnapshotAdapter from '@eventualize/types/IEvDbStorageSnapshotAdapter';
3
- import IEvDbStorageStreamAdapter from '@eventualize/types/IEvDbStorageStreamAdapter';
4
- import IEvDbEventPayload from "@eventualize/types/IEvDbEventPayload";
5
- import { EvDbStreamFactory } from './EvDbStreamFactory.js';
6
- /**
7
- * Combined storage adapter interface
8
- */
9
- export interface IEvDbStorageAdapter extends IEvDbStorageStreamAdapter, IEvDbStorageSnapshotAdapter {
10
- }
11
- /**
12
- * Storage configuration - either separate adapters or combined
13
- */
14
- interface StorageConfig {
15
- streamAdapter: IEvDbStorageStreamAdapter;
16
- snapshotAdapter: IEvDbStorageSnapshotAdapter;
17
- }
18
- /**
19
- * Registry of stream factories by stream type
20
- */
21
- interface StreamFactoryRegistry {
22
- [streamType: string]: EvDbStreamFactory<any, any>;
23
- }
24
- /**
25
- * Store class - manages stream creation with configured adapters and factories
26
- */
27
- declare class BaseStore {
28
- private readonly storage;
29
- private readonly streamFactories;
30
- constructor(storage: StorageConfig, streamFactories: StreamFactoryRegistry);
31
- /**
32
- * Create a stream instance by stream type and ID
33
- */
34
- createStream(streamType: string, streamId: string): EvDbStream;
35
- /**
36
- * Get a stream instance from the event store by stream type and ID
37
- */
38
- getStream(streamType: string, streamId: string): Promise<EvDbStream>;
39
- /**
40
- * Check if a stream type is registered
41
- */
42
- hasStreamType(streamType: string): boolean;
43
- /**
44
- * Get all registered stream types
45
- */
46
- getStreamTypes(): string[];
47
- /**
48
- * Create a builder for configuring the store
49
- */
50
- static builder(): BaseStoreBuilder;
51
- close(): Promise<void>;
52
- }
53
- /**
54
- * Builder for creating Store instances
55
- */
56
- declare class BaseStoreBuilder {
57
- private streamAdapter?;
58
- private snapshotAdapter?;
59
- private streamFactories;
60
- /**
61
- * Configure with separate stream and snapshot adapters
62
- */
63
- withAdapters(streamAdapter: IEvDbStorageStreamAdapter, snapshotAdapter: IEvDbStorageSnapshotAdapter): this;
64
- /**
65
- * Configure with a combined adapter that implements both interfaces
66
- */
67
- withAdapter(adapter: IEvDbStorageAdapter): this;
68
- /**
69
- * Register a stream factory
70
- */
71
- withStreamFactory<TEvents extends IEvDbEventPayload, TStreamType extends string>(factory: EvDbStreamFactory<TEvents, TStreamType>): this;
72
- /**
73
- * Register multiple stream factories at once
74
- */
75
- withStreamFactories(factories: ReadonlyArray<EvDbStreamFactory<any, string>>): this;
76
- /**
77
- * Build the store instance
78
- */
79
- build(): BaseStore;
80
- }
81
- /**
82
- * Helper type to create method signatures for each stream factory
83
- */
84
- export type StreamCreatorMethods<TStreamTypes extends Record<string, EvDbStreamFactory<any, any>>> = {
85
- [K in keyof TStreamTypes as `create${K & string}`]: (streamId: string) => EvDbStream;
86
- };
87
- export type StreamMap = Record<string, any>;
88
- /**
89
- * Type-safe store that knows about specific stream types
90
- */
91
- export declare class EvDbEventStore<TStreamTypes extends Record<string, EvDbStreamFactory<any, any>>> {
92
- private readonly store;
93
- constructor(store: BaseStore);
94
- /**
95
- * Create a stream with type-safe stream type parameter (fallback method)
96
- */
97
- createStream<K extends keyof TStreamTypes & string>(streamType: K, streamId: string): EvDbStream;
98
- /**
99
- * Fetch a stream from the event store with type-safe stream type parameter (fallback method)
100
- */
101
- getStream<K extends keyof TStreamTypes & string>(streamType: K, streamId: string): Promise<EvDbStream>;
102
- /**
103
- * Create dynamic methods for each registered stream factory
104
- */
105
- private createDynamicMethods;
106
- /**
107
- * Get the underlying store
108
- */
109
- getStore(): BaseStore;
110
- }
111
- export type TypedStoreType<TStreamTypes extends Record<string, EvDbStreamFactory<any, any>>> = StreamCreatorMethods<TStreamTypes>;
112
- /**
113
- * Type-safe store builder
114
- */
115
- export declare class EvDbEventStoreBuilder<TStreamTypes extends Record<string, EvDbStreamFactory<any, string>> = {}> {
116
- private builder;
117
- withAdapters(streamAdapter: IEvDbStorageStreamAdapter, snapshotAdapter: IEvDbStorageSnapshotAdapter): this;
118
- withAdapter(adapter: IEvDbStorageAdapter): this;
119
- withStreamFactory<F extends EvDbStreamFactory<any, string>, K extends F extends EvDbStreamFactory<any, infer ST> ? ST : never>(factory: F): EvDbEventStoreBuilder<TStreamTypes & Record<K, F>>;
120
- build(): EvDbEventStore<TStreamTypes> & StreamCreatorMethods<TStreamTypes>;
121
- }
122
- export type EvDbEventStoreType<TStreams extends StreamMap = StreamMap> = EvDbEventStore<TStreams> & StreamCreatorMethods<TStreams>;
123
- export {};