boundlessdb 0.1.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 (60) hide show
  1. package/CHANGELOG.md +89 -0
  2. package/LICENSE +21 -0
  3. package/README.md +545 -0
  4. package/dist/better-sqlite3-shim.d.ts +12 -0
  5. package/dist/better-sqlite3-shim.d.ts.map +1 -0
  6. package/dist/better-sqlite3-shim.js +18 -0
  7. package/dist/better-sqlite3-shim.js.map +1 -0
  8. package/dist/browser.d.ts +14 -0
  9. package/dist/browser.d.ts.map +1 -0
  10. package/dist/browser.js +14 -0
  11. package/dist/browser.js.map +1 -0
  12. package/dist/config/extractor.d.ts +22 -0
  13. package/dist/config/extractor.d.ts.map +1 -0
  14. package/dist/config/extractor.js +132 -0
  15. package/dist/config/extractor.js.map +1 -0
  16. package/dist/config/validator.d.ts +14 -0
  17. package/dist/config/validator.d.ts.map +1 -0
  18. package/dist/config/validator.js +94 -0
  19. package/dist/config/validator.js.map +1 -0
  20. package/dist/event-store.browser.d.ts +61 -0
  21. package/dist/event-store.browser.d.ts.map +1 -0
  22. package/dist/event-store.browser.js +323 -0
  23. package/dist/event-store.browser.js.map +1 -0
  24. package/dist/event-store.d.ts +101 -0
  25. package/dist/event-store.d.ts.map +1 -0
  26. package/dist/event-store.js +249 -0
  27. package/dist/event-store.js.map +1 -0
  28. package/dist/index.d.ts +15 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +16 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/query-builder.d.ts +72 -0
  33. package/dist/query-builder.d.ts.map +1 -0
  34. package/dist/query-builder.js +84 -0
  35. package/dist/query-builder.js.map +1 -0
  36. package/dist/storage/interface.d.ts +48 -0
  37. package/dist/storage/interface.d.ts.map +1 -0
  38. package/dist/storage/interface.js +5 -0
  39. package/dist/storage/interface.js.map +1 -0
  40. package/dist/storage/memory.d.ts +27 -0
  41. package/dist/storage/memory.d.ts.map +1 -0
  42. package/dist/storage/memory.js +94 -0
  43. package/dist/storage/memory.js.map +1 -0
  44. package/dist/storage/postgres.d.ts +76 -0
  45. package/dist/storage/postgres.d.ts.map +1 -0
  46. package/dist/storage/postgres.js +346 -0
  47. package/dist/storage/postgres.js.map +1 -0
  48. package/dist/storage/sqlite.d.ts +47 -0
  49. package/dist/storage/sqlite.d.ts.map +1 -0
  50. package/dist/storage/sqlite.js +249 -0
  51. package/dist/storage/sqlite.js.map +1 -0
  52. package/dist/storage/sqljs.d.ts +60 -0
  53. package/dist/storage/sqljs.d.ts.map +1 -0
  54. package/dist/storage/sqljs.js +354 -0
  55. package/dist/storage/sqljs.js.map +1 -0
  56. package/dist/types.d.ts +172 -0
  57. package/dist/types.d.ts.map +1 -0
  58. package/dist/types.js +52 -0
  59. package/dist/types.js.map +1 -0
  60. package/package.json +75 -0
@@ -0,0 +1,249 @@
1
+ /**
2
+ * Main EventStore class
3
+ */
4
+ import { randomUUID, createHash } from 'node:crypto';
5
+ import { KeyExtractor } from './config/extractor.js';
6
+ import { validateConfig } from './config/validator.js';
7
+ import { SqliteStorage } from './storage/sqlite.js';
8
+ import { QueryResult, isConstrainedCondition, } from './types.js';
9
+ import { QueryBuilder } from './query-builder.js';
10
+ /**
11
+ * Recursively sort object keys for deterministic JSON
12
+ */
13
+ function sortObjectKeys(obj) {
14
+ if (obj === null || typeof obj !== 'object') {
15
+ return obj;
16
+ }
17
+ if (Array.isArray(obj)) {
18
+ return obj.map(sortObjectKeys);
19
+ }
20
+ const sorted = {};
21
+ for (const key of Object.keys(obj).sort()) {
22
+ sorted[key] = sortObjectKeys(obj[key]);
23
+ }
24
+ return sorted;
25
+ }
26
+ /**
27
+ * Compute SHA256 hash of ConsistencyConfig
28
+ */
29
+ function hashConfig(config) {
30
+ const normalized = JSON.stringify(sortObjectKeys(config));
31
+ return createHash('sha256').update(normalized).digest('hex');
32
+ }
33
+ /**
34
+ * DCB-native Event Store
35
+ *
36
+ * Implements Dynamic Consistency Boundaries for event sourcing.
37
+ * No cryptographic signing - tokens are Base64 encoded for convenience.
38
+ */
39
+ export class EventStore {
40
+ storage;
41
+ keyExtractor;
42
+ config;
43
+ constructor(options) {
44
+ // Validate configuration
45
+ validateConfig(options.consistency);
46
+ this.storage = options.storage;
47
+ this.config = options.consistency;
48
+ this.keyExtractor = new KeyExtractor(this.config);
49
+ // Check config hash and reindex if needed (SqliteStorage only)
50
+ this.checkAndReindexIfNeeded();
51
+ }
52
+ /**
53
+ * Check if config has changed since last run, reindex if needed
54
+ */
55
+ checkAndReindexIfNeeded() {
56
+ // Only works with SqliteStorage (has metadata table)
57
+ if (!(this.storage instanceof SqliteStorage)) {
58
+ return;
59
+ }
60
+ const currentHash = hashConfig(this.config);
61
+ const storedHash = this.storage.getConfigHash();
62
+ if (storedHash === null) {
63
+ // First run — just store the hash
64
+ console.log('[EventStore] First run, storing config hash:', currentHash.substring(0, 16) + '...');
65
+ this.storage.setConfigHash(currentHash);
66
+ }
67
+ else if (storedHash !== currentHash) {
68
+ // Config changed — reindex!
69
+ console.log('[EventStore] ⚠️ Config changed! Rebuilding key index...');
70
+ console.log(`[EventStore] Old hash: ${storedHash.substring(0, 16)}...`);
71
+ console.log(`[EventStore] New hash: ${currentHash.substring(0, 16)}...`);
72
+ const startTime = Date.now();
73
+ let eventCount = 0;
74
+ let keyCount = 0;
75
+ this.storage.reindex((event) => {
76
+ eventCount++;
77
+ // Convert StoredEvent to Event format for KeyExtractor
78
+ const keys = this.keyExtractor.extract({
79
+ type: event.type,
80
+ data: event.data,
81
+ metadata: event.metadata
82
+ });
83
+ keyCount += keys.length;
84
+ return keys;
85
+ });
86
+ // Update stored hash
87
+ this.storage.setConfigHash(currentHash);
88
+ const duration = Date.now() - startTime;
89
+ console.log(`[EventStore] ✅ Reindex complete: ${eventCount} events, ${keyCount} keys (${duration}ms)`);
90
+ }
91
+ }
92
+ /**
93
+ * Create a fluent query builder.
94
+ *
95
+ * @typeParam E - Event union type for typed results
96
+ * @returns QueryBuilder for chaining
97
+ *
98
+ * @example
99
+ * ```typescript
100
+ * const result = await store.query<CourseEvent>()
101
+ * .matchType('CourseCreated')
102
+ * .matchKey('StudentSubscribed', 'course', 'cs101')
103
+ * .fromPosition(100n)
104
+ * .limit(50)
105
+ * .read();
106
+ * ```
107
+ */
108
+ query() {
109
+ return new QueryBuilder(this);
110
+ }
111
+ /**
112
+ * Read events matching a query
113
+ *
114
+ * @typeParam E - Event union type for typed results
115
+ * @returns QueryResult with typed events and consistency token
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * // Typed read
120
+ * const result = await store.read<CartEvents>({
121
+ * conditions: [{ type: 'ProductItemAdded', key: 'cart', value: 'cart-123' }]
122
+ * });
123
+ *
124
+ * // Untyped read (all events of type)
125
+ * const result = await store.read({
126
+ * conditions: [{ type: 'ProductItemAdded' }]
127
+ * });
128
+ * ```
129
+ */
130
+ async read(query) {
131
+ const events = await this.storage.query(query.conditions, query.fromPosition, query.limit);
132
+ // Get the position for the append condition
133
+ // If we have events, use the last event's position
134
+ // Otherwise, use the current latest position
135
+ const position = events.length > 0
136
+ ? events[events.length - 1].position
137
+ : await this.storage.getLatestPosition();
138
+ return new QueryResult(events, position, query.conditions);
139
+ }
140
+ /**
141
+ * Append events with optional consistency check
142
+ *
143
+ * @typeParam E - Event type for type checking
144
+ * @param events Events to append
145
+ * @param condition Consistency check - can be:
146
+ * - null: Skip consistency check (optimistic first write)
147
+ * - AppendCondition: { position, conditions } from a previous read
148
+ * @returns AppendResult on success, ConflictResult on conflict
149
+ *
150
+ * @example
151
+ * ```typescript
152
+ * // With appendCondition from read
153
+ * const result = await store.read<CartEvents>({ conditions: [...] });
154
+ * await store.append<CartEvents>([newEvent], result.appendCondition);
155
+ *
156
+ * // Without consistency check (first write)
157
+ * await store.append<CartEvents>([newEvent], null);
158
+ * ```
159
+ */
160
+ async append(events, condition) {
161
+ if (events.length === 0) {
162
+ // Nothing to append
163
+ const position = await this.storage.getLatestPosition();
164
+ return {
165
+ conflict: false,
166
+ position,
167
+ appendCondition: { position, conditions: condition?.conditions ?? [] },
168
+ };
169
+ }
170
+ // Extract keys from all events
171
+ const keysPerEvent = events.map(event => this.keyExtractor.extract(event));
172
+ // Check for conflicts if condition provided
173
+ if (condition !== null) {
174
+ const conflictingEvents = await this.storage.getEventsSince(condition.conditions, condition.position);
175
+ if (conflictingEvents.length > 0) {
176
+ // Conflict detected — return delta
177
+ const latestPosition = conflictingEvents[conflictingEvents.length - 1].position;
178
+ return {
179
+ conflict: true,
180
+ conflictingEvents: conflictingEvents,
181
+ appendCondition: { position: latestPosition, conditions: condition.conditions },
182
+ };
183
+ }
184
+ }
185
+ // No conflict — prepare events for storage
186
+ const now = new Date();
187
+ const eventsToStore = events.map(event => ({
188
+ id: randomUUID(),
189
+ type: event.type,
190
+ data: event.data,
191
+ metadata: event.metadata,
192
+ timestamp: now,
193
+ }));
194
+ // Append atomically
195
+ const position = await this.storage.append(eventsToStore, keysPerEvent);
196
+ // Build new appendCondition
197
+ const newConditions = this.buildConditionsFromEvents(events, condition);
198
+ return {
199
+ conflict: false,
200
+ position,
201
+ appendCondition: { position, conditions: newConditions },
202
+ };
203
+ }
204
+ /**
205
+ * Build conditions that cover the appended events
206
+ * Used to create the appendCondition returned after append
207
+ */
208
+ buildConditionsFromEvents(events, originalCondition) {
209
+ // Start with original conditions if provided
210
+ const conditions = new Map();
211
+ if (originalCondition !== null) {
212
+ for (const cond of originalCondition.conditions) {
213
+ if (isConstrainedCondition(cond)) {
214
+ const key = `${cond.type}:${cond.key}:${cond.value}`;
215
+ conditions.set(key, cond);
216
+ }
217
+ }
218
+ }
219
+ // Add conditions from the newly appended events
220
+ for (const event of events) {
221
+ const extractedKeys = this.keyExtractor.extract(event);
222
+ for (const extracted of extractedKeys) {
223
+ const cond = { type: event.type, key: extracted.name, value: extracted.value };
224
+ const key = `${cond.type}:${cond.key}:${cond.value}`;
225
+ conditions.set(key, cond);
226
+ }
227
+ }
228
+ return Array.from(conditions.values());
229
+ }
230
+ /**
231
+ * Get the underlying storage (for advanced use cases)
232
+ */
233
+ getStorage() {
234
+ return this.storage;
235
+ }
236
+ /**
237
+ * Close the event store
238
+ */
239
+ async close() {
240
+ await this.storage.close();
241
+ }
242
+ }
243
+ /**
244
+ * Factory function to create an event store
245
+ */
246
+ export function createEventStore(options) {
247
+ return new EventStore(options);
248
+ }
249
+ //# sourceMappingURL=event-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-store.js","sourceRoot":"","sources":["../src/event-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * DCB Event Store - Public API
3
+ */
4
+ export type { Event, EventWithMetadata, StoredEvent, Query, QueryCondition, UnconstrainedCondition, ConstrainedCondition, ConsistencyConfig, ConsistencyKeyDef, EventTypeConfig, ExtractedKey, AppendResult, ConflictResult, AppendCondition, EventStoreOptions, } from './types.js';
5
+ export { QueryResult, isConflict, isConstrainedCondition } from './types.js';
6
+ export { EventStore, createEventStore, type EventStoreConfig } from './event-store.js';
7
+ export type { EventStorage, EventToStore } from './storage/interface.js';
8
+ export { InMemoryStorage } from './storage/memory.js';
9
+ export { SqliteStorage } from './storage/sqlite.js';
10
+ export { SqlJsStorage, type SqlJsStorageOptions } from './storage/sqljs.js';
11
+ export { PostgresStorage } from './storage/postgres.js';
12
+ export { KeyExtractor, KeyExtractionError } from './config/extractor.js';
13
+ export { validateConfig, ConfigValidationError } from './config/validator.js';
14
+ export { QueryBuilder } from './query-builder.js';
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,YAAY,EAEV,KAAK,EACL,iBAAiB,EACjB,WAAW,EAEX,KAAK,EACL,cAAc,EACd,sBAAsB,EACtB,oBAAoB,EAEpB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,YAAY,EAEZ,YAAY,EACZ,cAAc,EACd,eAAe,EACf,iBAAiB,GAClB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAG7E,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGvF,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAGxD,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAG9E,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * DCB Event Store - Public API
3
+ */
4
+ export { QueryResult, isConflict, isConstrainedCondition } from './types.js';
5
+ // Event Store
6
+ export { EventStore, createEventStore } from './event-store.js';
7
+ export { InMemoryStorage } from './storage/memory.js';
8
+ export { SqliteStorage } from './storage/sqlite.js';
9
+ export { SqlJsStorage } from './storage/sqljs.js';
10
+ export { PostgresStorage } from './storage/postgres.js';
11
+ // Config
12
+ export { KeyExtractor, KeyExtractionError } from './config/extractor.js';
13
+ export { validateConfig, ConfigValidationError } from './config/validator.js';
14
+ // Query Builder
15
+ export { QueryBuilder } from './query-builder.js';
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAyBH,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAE7E,cAAc;AACd,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAyB,MAAM,kBAAkB,CAAC;AAIvF,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,YAAY,EAA4B,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,SAAS;AACT,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAE9E,gBAAgB;AAChB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Fluent Query Builder for BoundlessDB
3
+ */
4
+ import type { Event, QueryCondition, QueryResult } from './types.js';
5
+ export interface QueryExecutor<E extends Event> {
6
+ read(query: {
7
+ conditions: QueryCondition[];
8
+ fromPosition?: bigint;
9
+ limit?: number;
10
+ }): Promise<QueryResult<E>>;
11
+ }
12
+ /**
13
+ * Fluent API for building queries.
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const result = await store.query<CourseEvent>()
18
+ * .matchType('CourseCreated')
19
+ * .matchKey('StudentSubscribed', 'course', 'cs101')
20
+ * .fromPosition(100n)
21
+ * .limit(50)
22
+ * .read();
23
+ * ```
24
+ */
25
+ export declare class QueryBuilder<E extends Event> {
26
+ private readonly executor;
27
+ private conditions;
28
+ private _fromPosition?;
29
+ private _limit?;
30
+ constructor(executor: QueryExecutor<E>);
31
+ /**
32
+ * Add an unconstrained condition (match all events of type).
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * .matchType('CourseCreated') // matches ALL CourseCreated events
37
+ * ```
38
+ */
39
+ matchType(type: string): this;
40
+ /**
41
+ * Add a constrained condition (match events where key equals value).
42
+ *
43
+ * @example
44
+ * ```typescript
45
+ * .matchKey('StudentSubscribed', 'course', 'cs101')
46
+ * ```
47
+ */
48
+ matchKey(type: string, key: string, value: string): this;
49
+ /**
50
+ * Start reading from a specific position.
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * .fromPosition(100n) // skip events before position 100
55
+ * ```
56
+ */
57
+ fromPosition(position: bigint): this;
58
+ /**
59
+ * Limit the number of events returned.
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * .limit(50) // return at most 50 events
64
+ * ```
65
+ */
66
+ limit(count: number): this;
67
+ /**
68
+ * Execute the query and return results.
69
+ */
70
+ read(): Promise<QueryResult<E>>;
71
+ }
72
+ //# sourceMappingURL=query-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-builder.d.ts","sourceRoot":"","sources":["../src/query-builder.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAErE,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,KAAK;IAC5C,IAAI,CAAC,KAAK,EAAE;QACV,UAAU,EAAE,cAAc,EAAE,CAAC;QAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;CAC7B;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,YAAY,CAAC,CAAC,SAAS,KAAK;IAK3B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAJrC,OAAO,CAAC,UAAU,CAAwB;IAC1C,OAAO,CAAC,aAAa,CAAC,CAAS;IAC/B,OAAO,CAAC,MAAM,CAAC,CAAS;gBAEK,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC;IAEvD;;;;;;;OAOG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAK7B;;;;;;;OAOG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAKxD;;;;;;;OAOG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKpC;;;;;;;OAOG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK1B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;CAOtC"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Fluent Query Builder for BoundlessDB
3
+ */
4
+ /**
5
+ * Fluent API for building queries.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const result = await store.query<CourseEvent>()
10
+ * .matchType('CourseCreated')
11
+ * .matchKey('StudentSubscribed', 'course', 'cs101')
12
+ * .fromPosition(100n)
13
+ * .limit(50)
14
+ * .read();
15
+ * ```
16
+ */
17
+ export class QueryBuilder {
18
+ executor;
19
+ conditions = [];
20
+ _fromPosition;
21
+ _limit;
22
+ constructor(executor) {
23
+ this.executor = executor;
24
+ }
25
+ /**
26
+ * Add an unconstrained condition (match all events of type).
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * .matchType('CourseCreated') // matches ALL CourseCreated events
31
+ * ```
32
+ */
33
+ matchType(type) {
34
+ this.conditions.push({ type });
35
+ return this;
36
+ }
37
+ /**
38
+ * Add a constrained condition (match events where key equals value).
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * .matchKey('StudentSubscribed', 'course', 'cs101')
43
+ * ```
44
+ */
45
+ matchKey(type, key, value) {
46
+ this.conditions.push({ type, key, value });
47
+ return this;
48
+ }
49
+ /**
50
+ * Start reading from a specific position.
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * .fromPosition(100n) // skip events before position 100
55
+ * ```
56
+ */
57
+ fromPosition(position) {
58
+ this._fromPosition = position;
59
+ return this;
60
+ }
61
+ /**
62
+ * Limit the number of events returned.
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * .limit(50) // return at most 50 events
67
+ * ```
68
+ */
69
+ limit(count) {
70
+ this._limit = count;
71
+ return this;
72
+ }
73
+ /**
74
+ * Execute the query and return results.
75
+ */
76
+ async read() {
77
+ return this.executor.read({
78
+ conditions: this.conditions,
79
+ fromPosition: this._fromPosition,
80
+ limit: this._limit,
81
+ });
82
+ }
83
+ }
84
+ //# sourceMappingURL=query-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-builder.js","sourceRoot":"","sources":["../src/query-builder.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,YAAY;IAKM;IAJrB,UAAU,GAAqB,EAAE,CAAC;IAClC,aAAa,CAAU;IACvB,MAAM,CAAU;IAExB,YAA6B,QAA0B;QAA1B,aAAQ,GAAR,QAAQ,CAAkB;IAAG,CAAC;IAE3D;;;;;;;OAOG;IACH,SAAS,CAAC,IAAY;QACpB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;OAOG;IACH,QAAQ,CAAC,IAAY,EAAE,GAAW,EAAE,KAAa;QAC/C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;QAC3C,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;OAOG;IACH,YAAY,CAAC,QAAgB;QAC3B,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,KAAa;QACjB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI;QACR,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YACxB,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,YAAY,EAAE,IAAI,CAAC,aAAa;YAChC,KAAK,EAAE,IAAI,CAAC,MAAM;SACnB,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Storage Interface for the Event Store
3
+ */
4
+ import type { ExtractedKey, QueryCondition, StoredEvent } from '../types.js';
5
+ /**
6
+ * Event to be stored (before position assignment)
7
+ */
8
+ export interface EventToStore {
9
+ id: string;
10
+ type: string;
11
+ data: unknown;
12
+ metadata?: Record<string, unknown>;
13
+ timestamp: Date;
14
+ }
15
+ /**
16
+ * Storage backend interface
17
+ */
18
+ export interface EventStorage {
19
+ /**
20
+ * Append events to the store with their extracted keys
21
+ * Must be atomic: either all events are stored, or none
22
+ * @returns Position of the last appended event
23
+ */
24
+ append(events: EventToStore[], keys: ExtractedKey[][]): Promise<bigint>;
25
+ /**
26
+ * Query events by conditions
27
+ * @param conditions Query conditions (type + key + value)
28
+ * @param fromPosition Start position (exclusive)
29
+ * @param limit Maximum number of events to return
30
+ */
31
+ query(conditions: QueryCondition[], fromPosition?: bigint, limit?: number): Promise<StoredEvent[]>;
32
+ /**
33
+ * Get events since a given position that match the conditions
34
+ * Used for consistency checks (conflict detection)
35
+ * @returns Events that match AND have position > sincePosition
36
+ */
37
+ getEventsSince(conditions: QueryCondition[], sincePosition: bigint): Promise<StoredEvent[]>;
38
+ /**
39
+ * Get the current highest position in the store
40
+ * @returns 0n if store is empty
41
+ */
42
+ getLatestPosition(): Promise<bigint>;
43
+ /**
44
+ * Close the storage connection
45
+ */
46
+ close(): Promise<void>;
47
+ }
48
+ //# sourceMappingURL=interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/storage/interface.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE7E;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,SAAS,EAAE,IAAI,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAExE;;;;;OAKG;IACH,KAAK,CACH,UAAU,EAAE,cAAc,EAAE,EAC5B,YAAY,CAAC,EAAE,MAAM,EACrB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAE1B;;;;OAIG;IACH,cAAc,CACZ,UAAU,EAAE,cAAc,EAAE,EAC5B,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAE1B;;;OAGG;IACH,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAErC;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Storage Interface for the Event Store
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interface.js","sourceRoot":"","sources":["../../src/storage/interface.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * In-Memory Storage implementation (for testing)
3
+ */
4
+ import { type ExtractedKey, type QueryCondition, type StoredEvent } from '../types.js';
5
+ import type { EventStorage, EventToStore } from './interface.js';
6
+ /**
7
+ * In-memory event storage for testing purposes
8
+ * NOT suitable for production use
9
+ */
10
+ export declare class InMemoryStorage implements EventStorage {
11
+ private events;
12
+ private nextPosition;
13
+ append(eventsToStore: EventToStore[], keys: ExtractedKey[][]): Promise<bigint>;
14
+ query(conditions: QueryCondition[], fromPosition?: bigint, limit?: number): Promise<StoredEvent[]>;
15
+ getEventsSince(conditions: QueryCondition[], sincePosition: bigint): Promise<StoredEvent[]>;
16
+ getLatestPosition(): Promise<bigint>;
17
+ close(): Promise<void>;
18
+ /**
19
+ * Get all events (for testing)
20
+ */
21
+ getAllEvents(): StoredEvent[];
22
+ /**
23
+ * Clear all events (for testing)
24
+ */
25
+ clear(): void;
26
+ }
27
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/storage/memory.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAA0B,KAAK,YAAY,EAAE,KAAK,cAAc,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/G,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAMjE;;;GAGG;AACH,qBAAa,eAAgB,YAAW,YAAY;IAClD,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,YAAY,CAAc;IAE5B,MAAM,CAAC,aAAa,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IA4B9E,KAAK,CACT,UAAU,EAAE,cAAc,EAAE,EAC5B,YAAY,CAAC,EAAE,MAAM,EACrB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,WAAW,EAAE,CAAC;IA6CnB,cAAc,CAClB,UAAU,EAAE,cAAc,EAAE,EAC5B,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,WAAW,EAAE,CAAC;IAInB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;IAOpC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;OAEG;IACH,YAAY,IAAI,WAAW,EAAE;IAI7B;;OAEG;IACH,KAAK,IAAI,IAAI;CAId"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * In-Memory Storage implementation (for testing)
3
+ */
4
+ import { isConstrainedCondition } from '../types.js';
5
+ /**
6
+ * In-memory event storage for testing purposes
7
+ * NOT suitable for production use
8
+ */
9
+ export class InMemoryStorage {
10
+ events = [];
11
+ nextPosition = 1n;
12
+ async append(eventsToStore, keys) {
13
+ if (eventsToStore.length !== keys.length) {
14
+ throw new Error('Events and keys arrays must have the same length');
15
+ }
16
+ let lastPosition = 0n;
17
+ for (let i = 0; i < eventsToStore.length; i++) {
18
+ const event = eventsToStore[i];
19
+ const eventKeys = keys[i];
20
+ const position = this.nextPosition++;
21
+ this.events.push({
22
+ id: event.id,
23
+ type: event.type,
24
+ data: event.data,
25
+ metadata: event.metadata,
26
+ timestamp: event.timestamp,
27
+ position,
28
+ keys: eventKeys,
29
+ });
30
+ lastPosition = position;
31
+ }
32
+ return lastPosition;
33
+ }
34
+ async query(conditions, fromPosition, limit) {
35
+ const startPos = fromPosition ?? 0n;
36
+ // Filter by position first
37
+ let matching = this.events.filter(event => event.position > startPos);
38
+ // If no conditions, return all events
39
+ if (conditions.length === 0) {
40
+ // Sort by position
41
+ matching.sort((a, b) => (a.position < b.position ? -1 : 1));
42
+ const limited = limit !== undefined ? matching.slice(0, limit) : matching;
43
+ return limited.map(({ keys: _keys, ...event }) => event);
44
+ }
45
+ // Filter by conditions
46
+ matching = matching.filter(event => {
47
+ // Must match at least one condition
48
+ return conditions.some(cond => {
49
+ // Type must match
50
+ if (event.type !== cond.type) {
51
+ return false;
52
+ }
53
+ // If unconstrained, type match is enough
54
+ if (!isConstrainedCondition(cond)) {
55
+ return true;
56
+ }
57
+ // Key must match
58
+ return event.keys.some(key => key.name === cond.key && key.value === cond.value);
59
+ });
60
+ });
61
+ // Sort by position
62
+ matching.sort((a, b) => (a.position < b.position ? -1 : 1));
63
+ // Apply limit
64
+ const limited = limit !== undefined ? matching.slice(0, limit) : matching;
65
+ // Strip internal keys
66
+ return limited.map(({ keys: _keys, ...event }) => event);
67
+ }
68
+ async getEventsSince(conditions, sincePosition) {
69
+ return this.query(conditions, sincePosition);
70
+ }
71
+ async getLatestPosition() {
72
+ if (this.events.length === 0) {
73
+ return 0n;
74
+ }
75
+ return this.events[this.events.length - 1].position;
76
+ }
77
+ async close() {
78
+ // Nothing to do
79
+ }
80
+ /**
81
+ * Get all events (for testing)
82
+ */
83
+ getAllEvents() {
84
+ return this.events.map(({ keys: _keys, ...event }) => event);
85
+ }
86
+ /**
87
+ * Clear all events (for testing)
88
+ */
89
+ clear() {
90
+ this.events = [];
91
+ this.nextPosition = 1n;
92
+ }
93
+ }
94
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/storage/memory.ts"],"names":[],"mappings":"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"}