@lunora/replica 1.0.0-alpha.4 → 1.0.0-alpha.41

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 (57) hide show
  1. package/LICENSE.md +214 -0
  2. package/dist/adapters/better-sqlite3.d.mts +14 -14
  3. package/dist/adapters/better-sqlite3.d.ts +14 -14
  4. package/dist/adapters/better-sqlite3.mjs +1 -29
  5. package/dist/adapters/sqlite-wasm.d.mts +29 -19
  6. package/dist/adapters/sqlite-wasm.d.ts +29 -19
  7. package/dist/adapters/sqlite-wasm.mjs +1 -56
  8. package/dist/adapters/sqljs.d.mts +10 -10
  9. package/dist/adapters/sqljs.d.ts +10 -10
  10. package/dist/adapters/sqljs.mjs +1 -55
  11. package/dist/index.d.mts +646 -574
  12. package/dist/index.d.ts +646 -574
  13. package/dist/index.mjs +1 -20
  14. package/dist/packem_shared/EventEmitter-ovTsLeAj.mjs +1 -0
  15. package/dist/packem_shared/EventLog-DmlRY_4Z.mjs +1 -0
  16. package/dist/packem_shared/EventLogDO-q80QYMLe.mjs +1 -0
  17. package/dist/packem_shared/EventLogDOClient-lkVhWras.mjs +1 -0
  18. package/dist/packem_shared/EventSource-ArQhJa6P.mjs +1 -0
  19. package/dist/packem_shared/EventsSync-DWyGGZQZ.mjs +1 -0
  20. package/dist/packem_shared/InMemorySnapshotStore-C4taIG5K.mjs +1 -0
  21. package/dist/packem_shared/LocalMirror-DCjNXIyf.mjs +4 -0
  22. package/dist/packem_shared/MaterializerRuntime-CqGGjSxl.mjs +1 -0
  23. package/dist/packem_shared/SubscriptionManager-CzEXcqvp.mjs +1 -0
  24. package/dist/packem_shared/applyDiff-BUzddc6r.mjs +1 -0
  25. package/dist/packem_shared/applyDiffToDb-DSnSZmL4.mjs +1 -0
  26. package/dist/packem_shared/classifyChanges-IoOGDVVx.mjs +1 -0
  27. package/dist/packem_shared/defineEvents-D3OcpXb_.mjs +1 -0
  28. package/dist/packem_shared/eventsContext-Dxow9Y7S.mjs +1 -0
  29. package/dist/packem_shared/isClientSeq-DSXBJskD.mjs +1 -0
  30. package/dist/packem_shared/local-mirror.d-ByrYTq4z.d.ts +530 -0
  31. package/dist/packem_shared/local-mirror.d-Cip3QuMf.d.mts +530 -0
  32. package/dist/packem_shared/subscribeToMirror-Dru_AYBu.mjs +1 -0
  33. package/dist/packem_shared/{types.d-BuAWjEY5.d.mts → types.d-CkMkSwLJ.d.mts} +10 -10
  34. package/dist/packem_shared/{types.d-BuAWjEY5.d.ts → types.d-CkMkSwLJ.d.ts} +10 -10
  35. package/dist/react.d.mts +88 -61
  36. package/dist/react.d.ts +88 -61
  37. package/dist/react.mjs +1 -15
  38. package/package.json +1 -1
  39. package/dist/packem_shared/EventEmitter-CMZfct03.mjs +0 -92
  40. package/dist/packem_shared/EventLog-zMy7AYP4.mjs +0 -162
  41. package/dist/packem_shared/EventLogDO-CZYUvvSr.mjs +0 -235
  42. package/dist/packem_shared/EventLogDOClient-DGiEdi96.mjs +0 -86
  43. package/dist/packem_shared/EventSource-DfV4VoRD.mjs +0 -195
  44. package/dist/packem_shared/EventsSync-DkVbU0WV.mjs +0 -91
  45. package/dist/packem_shared/InMemorySnapshotStore-BHVAD-Bp.mjs +0 -24
  46. package/dist/packem_shared/LocalMirror-GeJ26eNe.mjs +0 -188
  47. package/dist/packem_shared/MaterializerRuntime-HqNXqJxp.mjs +0 -204
  48. package/dist/packem_shared/SubscriptionManager-C5xbw0pg.mjs +0 -75
  49. package/dist/packem_shared/applyDiff-BtbIl1D3.mjs +0 -40
  50. package/dist/packem_shared/applyDiffToDb-DQ1xZp5J.mjs +0 -58
  51. package/dist/packem_shared/classifyChanges-aZmkxgVI.mjs +0 -38
  52. package/dist/packem_shared/defineEvents-DiBkPTh_.mjs +0 -28
  53. package/dist/packem_shared/eventsContext-Bk_p48hj.mjs +0 -6
  54. package/dist/packem_shared/isClientSeq-C46BkzqJ.mjs +0 -5
  55. package/dist/packem_shared/local-mirror.d-BUeOe5KC.d.mts +0 -439
  56. package/dist/packem_shared/local-mirror.d-Cd8tAg-W.d.ts +0 -439
  57. package/dist/packem_shared/subscribeToMirror-CiaM-nQ7.mjs +0 -45
package/dist/index.d.ts CHANGED
@@ -1,130 +1,131 @@
1
1
  export { createBetterSqlite3Adapter } from "./adapters/better-sqlite3.js";
2
2
  export { createSqliteWasmAdapter } from "./adapters/sqlite-wasm.js";
3
3
  export { createSqlJsAdapter } from "./adapters/sqljs.js";
4
- import { S as SqliteAdapter } from "./packem_shared/types.d-BuAWjEY5.js";
5
- import { T as TableDiff, I as InputEvent, S as Seq, E as EventLogEntry, a as EventLog, A as AppendOptions, L as LocalMirror } from "./packem_shared/local-mirror.d-Cd8tAg-W.js";
6
- export { type C as ClientSeq, type b as EventLogSnapshot, type G as GlobalSeq, type c as LocalMirrorOptions, type M as MirrorTableDef, type R as RowChange, d as classifyChanges, e as createTableDiff, f as diffSize, i as isClientSeq, g as isDiffEmpty, h as isGlobalSeq, j as isInputEvent, m as mergeDiffs } from "./packem_shared/local-mirror.d-Cd8tAg-W.js";
7
- /**
8
- * Apply a single {@link TableDiff} to an in-memory row map and return
9
- * the updated map.
10
- *
11
- * The function creates a **shallow copy** of the input map so the caller's
12
- * reference stays untouched unless they choose to replace it.
13
- * @example
14
- * ```ts
15
- * const rows = new Map<string, Record<string, unknown>>();
16
- * rows.set("id-1", { name: "alice" });
17
- *
18
- * const diff = createTableDiff("users", [
19
- * { type: "insert", data: { id: "id-2", name: "bob" } },
20
- * { type: "update", id: "id-1", data: { name: "alice-updated" } },
21
- * ]);
22
- *
23
- * const updated = applyDiff(rows, diff);
24
- * updated.get("id-1")?.name // "alice-updated"
25
- * updated.get("id-2")?.name // "bob"
26
- * ```
27
- * @experimental
28
- */
4
+ import { S as SqliteAdapter } from "./packem_shared/types.d-CkMkSwLJ.js";
5
+ import { T as TableDiff, I as InputEvent, S as Seq, E as EventLogEntry, a as EventLog, A as AppendOptions, L as LocalMirror } from "./packem_shared/local-mirror.d-ByrYTq4z.js";
6
+ export { type C as ClientSeq, type b as EventLogOptions, type c as EventLogSnapshot, type G as GlobalSeq, type d as LocalMirrorOptions, type M as MirrorTableDef, type R as RowChange, e as classifyChanges, f as createTableDiff, g as diffSize, i as isClientSeq, h as isDiffEmpty, j as isGlobalSeq, k as isInputEvent, m as mergeDiffs } from "./packem_shared/local-mirror.d-ByrYTq4z.js";
7
+ /**
8
+ * Apply a single {@link TableDiff} to an in-memory row map and return
9
+ * the updated map.
10
+ *
11
+ * The function creates a **shallow copy** of the input map so the caller's
12
+ * reference stays untouched unless they choose to replace it.
13
+ * @example
14
+ * ```ts
15
+ * const rows = new Map<string, Record<string, unknown>>();
16
+ * rows.set("id-1", { name: "alice" });
17
+ *
18
+ * const diff = createTableDiff("users", [
19
+ * { type: "insert", data: { id: "id-2", name: "bob" } },
20
+ * { type: "update", id: "id-1", data: { name: "alice-updated" } },
21
+ * ]);
22
+ *
23
+ * const updated = applyDiff(rows, diff);
24
+ * updated.get("id-1")?.name // "alice-updated"
25
+ * updated.get("id-2")?.name // "bob"
26
+ * ```
27
+ * @experimental
28
+ */
29
29
  declare const applyDiff: (current: ReadonlyMap<string, Record<string, unknown>>, diff: TableDiff) => Map<string, Record<string, unknown>>;
30
30
  /**
31
- * Apply an array of diffs **in order**, returning the final row map.
32
- *
33
- * This is equivalent to calling {@link applyDiff} repeatedly but avoids
34
- * intermediate map copies.
35
- * @experimental
36
- */
31
+ * Apply an array of diffs **in order**, returning the final row map.
32
+ *
33
+ * This is equivalent to calling {@link applyDiff} repeatedly but copies the
34
+ * input map exactly once rather than once per diff — catch-up replay of an
35
+ * N-diff backlog is a single copy, not N+1.
36
+ * @experimental
37
+ */
37
38
  declare const applyDiffs: (current: ReadonlyMap<string, Record<string, unknown>>, diffs: ReadonlyArray<TableDiff>) => Map<string, Record<string, unknown>>;
38
39
  /**
39
- * Merge the row-level effect of a {@link TableDiff} into plain JSON
40
- * state keyed by table name, returning a new snapshot.
41
- * @param snapshot Current snapshot, e.g. `{ users: Map&lt;id, row>, posts: Map&lt;id, row> }`.
42
- * @param diff Contains the target table name and the row-level changes to merge.
43
- * @returns A shallow copy of `snapshot` with `diff.table`'s map updated.
44
- * @experimental
45
- */
40
+ * Merge the row-level effect of a {@link TableDiff} into plain JSON
41
+ * state keyed by table name, returning a new snapshot.
42
+ * @param snapshot Current snapshot, e.g. `{ users: Map<id, row>, posts: Map<id, row> }`.
43
+ * @param diff Contains the target table name and the row-level changes to merge.
44
+ * @returns A shallow copy of `snapshot` with `diff.table`'s map updated.
45
+ * @experimental
46
+ */
46
47
  declare const applyDiffToSnapshot: (snapshot: ReadonlyMap<string, ReadonlyMap<string, Record<string, unknown>>>, diff: TableDiff) => Map<string, Map<string, Record<string, unknown>>>;
47
48
  /** Map a namespace-and-name pair to a qualified event type string. */
48
49
  type QualifiedType<Ns extends string, Name extends string> = `${Ns}.${Name}`;
49
50
  /**
50
- * Extract the payload type from an event schema.
51
- *
52
- * A `@lunora/values` validator (e.g. `v.object(...)`) carries its output type on
53
- * the phantom `__type` field (the same hook `Infer` reads), so match that FIRST
54
- * — otherwise a validator, being object-shaped, would fall through to the
55
- * `Record` branch and resolve to the validator instance itself rather than its
56
- * validated `{ … }` output. A bare factory function or plain descriptor object
57
- * is still supported as a fallback.
58
- */
51
+ * Extract the payload type from an event schema.
52
+ *
53
+ * A `@lunora/values` validator (e.g. `v.object(...)`) carries its output type on
54
+ * the phantom `__type` field (the same hook `Infer` reads), so match that FIRST
55
+ * — otherwise a validator, being object-shaped, would fall through to the
56
+ * `Record` branch and resolve to the validator instance itself rather than its
57
+ * validated `{ … }` output. A bare factory function or plain descriptor object
58
+ * is still supported as a fallback.
59
+ */
59
60
  type PayloadOf<T> = T extends {
60
61
  readonly __type: infer P;
61
62
  } ? P : T extends ((payload: infer P) => unknown) ? P : T extends Record<string, unknown> ? T : never;
62
63
  type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
63
64
  /**
64
- * Produce `{ "ns.name": Payload }` for every event, merged.
65
- */
66
- type EventTypeMap<TDefinition extends Record<string, Record<string, unknown>>> = UnionToIntersection<{ [Ns in keyof TDefinition & string]: { [Name in keyof TDefinition[Ns] & string]: { [K in QualifiedType<Ns, Name>]: PayloadOf<TDefinition[Ns][Name]> } }[keyof TDefinition[Ns] & string] }[keyof TDefinition & string]>;
65
+ * Produce `{ "ns.name": Payload }` for every event, merged.
66
+ */
67
+ type EventTypeMap<TDefinition extends Record<string, Record<string, unknown>>> = UnionToIntersection<{ [Ns in keyof TDefinition & string]: { [Name in keyof TDefinition[Ns] & string]: { [K in QualifiedType<Ns, Name>]: PayloadOf<TDefinition[Ns][Name]>; }; }[keyof TDefinition[Ns] & string]; }[keyof TDefinition & string]>;
67
68
  /**
68
- * A factory function that creates an {@link InputEvent} for a specific event type.
69
- *
70
- * The returned event has no `seq` — it is an optimistic / command payload
71
- * that the event log will assign a sequence number to on append.
72
- * @experimental
73
- */
69
+ * A factory function that creates an {@link InputEvent} for a specific event type.
70
+ *
71
+ * The returned event has no `seq` — it is an optimistic / command payload
72
+ * that the event log will assign a sequence number to on append.
73
+ * @experimental
74
+ */
74
75
  interface EventFactory<Type extends string, Payload> {
75
76
  (payload: Payload): InputEvent<Type, Payload>;
76
77
  /** The fully qualified event type string (e.g. `"chat.messageSent"`). */
77
78
  readonly type: Type;
78
79
  }
79
80
  /**
80
- * The namespace object returned for each group of events.
81
- * @experimental
82
- */
83
- type EventNamespace<Ns extends string, TDefinition extends Record<string, unknown>> = { [Name in keyof TDefinition & string]: EventFactory<QualifiedType<Ns, Name>, PayloadOf<TDefinition[Name]>> };
81
+ * The namespace object returned for each group of events.
82
+ * @experimental
83
+ */
84
+ type EventNamespace<Ns extends string, TDefinition extends Record<string, unknown>> = { [Name in keyof TDefinition & string]: EventFactory<QualifiedType<Ns, Name>, PayloadOf<TDefinition[Name]>>; };
84
85
  /**
85
- * The full result of {@link defineEvents}.
86
- * @experimental
87
- */
88
- type EventsDefinition<TDefinition extends Record<string, Record<string, unknown>>> = { [Ns in keyof TDefinition & string]: EventNamespace<Ns, TDefinition[Ns]> } & {
86
+ * The full result of {@link defineEvents}.
87
+ * @experimental
88
+ */
89
+ type EventsDefinition<TDefinition extends Record<string, Record<string, unknown>>> = { [Ns in keyof TDefinition & string]: EventNamespace<Ns, TDefinition[Ns]>; } & {
89
90
  /** Type-level map of event type → payload shape. Useful for generic code. */
90
91
  readonly _types: EventTypeMap<TDefinition>;
91
92
  };
92
93
  /**
93
- * Declare typed event types for event sourcing.
94
- *
95
- * Each key under a namespace becomes a factory function that produces
96
- * an {@link InputEvent} — an optimistic / command event that the event
97
- * log will assign a sequence number to on append.
98
- * @param definition A nested object where the outer keys are namespaces
99
- * and the inner keys are event names mapped to their
100
- * payload schemas (or simple type-descriptor objects).
101
- * @returns An object with the same nesting structure, where each leaf is
102
- * a factory function plus a `.type` property.
103
- */
94
+ * Declare typed event types for event sourcing.
95
+ *
96
+ * Each key under a namespace becomes a factory function that produces
97
+ * an {@link InputEvent} — an optimistic / command event that the event
98
+ * log will assign a sequence number to on append.
99
+ * @param definition A nested object where the outer keys are namespaces
100
+ * and the inner keys are event names mapped to their
101
+ * payload schemas (or simple type-descriptor objects).
102
+ * @returns An object with the same nesting structure, where each leaf is
103
+ * a factory function plus a `.type` property.
104
+ */
104
105
  interface DefineEventsOptions {
105
106
  /**
106
- * Optional version prefix for all event types.
107
- *
108
- * When set, every qualified event type is prefixed with `"v&lt;N>."`, enabling
109
- * versioned event naming like `"v1.chat.messageSent"` or `"v2.chat.messageSent"`.
110
- * This allows materializers to evolve their handling logic based on the event
111
- * version without breaking backward compatibility.
112
- * @example "v1" → event type becomes "v1.chat.messageSent"
113
- */
107
+ * Optional version prefix for all event types.
108
+ *
109
+ * When set, every qualified event type is prefixed with `"v<N>."`, enabling
110
+ * versioned event naming like `"v1.chat.messageSent"` or `"v2.chat.messageSent"`.
111
+ * This allows materializers to evolve their handling logic based on the event
112
+ * version without breaking backward compatibility.
113
+ * @example "v1" → event type becomes "v1.chat.messageSent"
114
+ */
114
115
  readonly version?: string;
115
116
  }
116
117
  /**
117
- * `defineEvents` is part of the experimental `@lunora/replica` API and may change without a major version bump.
118
- * @experimental
119
- */
118
+ * `defineEvents` is part of the experimental `@lunora/replica` API and may change without a major version bump.
119
+ * @experimental
120
+ */
120
121
  declare const defineEvents: <TDefinition extends Record<string, Record<string, unknown>>>(definition: TDefinition, options?: DefineEventsOptions) => EventsDefinition<TDefinition>;
121
122
  /**
122
- * Shape of the `events[]` items sent in a POST `/append` body.
123
- *
124
- * Like {@link InputEvent} but with `timestamp` optional — omit it to
125
- * let the server assign the timestamp.
126
- * @experimental
127
- */
123
+ * Shape of the `events[]` items sent in a POST `/append` body.
124
+ *
125
+ * Like {@link InputEvent} but with `timestamp` optional — omit it to
126
+ * let the server assign the timestamp.
127
+ * @experimental
128
+ */
128
129
  interface AppendEventInput {
129
130
  /** Globally-unique client identifier (for offline/optimistic support). */
130
131
  readonly clientId?: string;
@@ -140,133 +141,141 @@ interface AppendEventInput {
140
141
  readonly type: string;
141
142
  }
142
143
  /**
143
- * Options for constructing an {@link EventLogDOClient}.
144
- * @experimental
145
- */
144
+ * Options for constructing an {@link EventLogDOClient}.
145
+ * @experimental
146
+ */
146
147
  interface EventLogDOClientOptions {
147
148
  /**
148
- * A function that dispatches an HTTP request to the target EventLogDO
149
- * instance. In a Cloudflare Worker this is:
150
- *
151
- * ```ts
152
- * (req) => env.MY_DO_NAMESPACE.get(id).fetch(req)
153
- * ```
154
- */
149
+ * A function that dispatches an HTTP request to the target EventLogDO
150
+ * instance. In a Cloudflare Worker this is:
151
+ *
152
+ * ```ts
153
+ * (req) => env.MY_DO_NAMESPACE.get(id).fetch(req)
154
+ * ```
155
+ */
155
156
  fetch: (request: Request) => Promise<Response>;
156
157
  }
157
158
  /**
158
- * Lightweight HTTP client for EventLogDO's RPC surface.
159
- *
160
- * Each method maps to one of the DO's endpoints, throws on non-OK status,
161
- * and returns the parsed response body.
162
- * @experimental
163
- */
159
+ * Lightweight HTTP client for EventLogDO's RPC surface.
160
+ *
161
+ * Each method maps to one of the DO's endpoints, throws on non-OK status,
162
+ * and returns the parsed response body.
163
+ * @experimental
164
+ */
164
165
  declare class EventLogDOClient {
165
166
  #private;
166
167
  constructor(options: EventLogDOClientOptions);
167
168
  /**
168
- * Append one or more events to the log.
169
- * @returns The persisted entries with their assigned `seq` numbers.
170
- */
171
- append(events: AppendEventInput[]): Promise<EventLogEntry[]>;
172
- /**
173
- * Fetch all entries with `seq >= sinceSeq`.
174
- *
175
- * Pass `sinceSeq = 0` to fetch the entire log.
176
- */
169
+ * Append one or more events to the log.
170
+ * @param events The events to append.
171
+ * @param options Idempotency controls for the batch.
172
+ * @param options.batchId Optional idempotency key for the whole batch — a
173
+ * retried `append` call with the same `batchId` (e.g. after a network
174
+ * timeout that hid a successful response) returns the originally-persisted
175
+ * entries instead of inserting duplicates.
176
+ * @returns The persisted entries with their assigned `seq` numbers.
177
+ */
178
+ append(events: AppendEventInput[], options?: {
179
+ batchId?: string;
180
+ }): Promise<EventLogEntry[]>;
181
+ /**
182
+ * Fetch all entries with `seq >= sinceSeq`.
183
+ *
184
+ * Pass `sinceSeq = 0` to fetch the entire log.
185
+ */
177
186
  getSince(sinceSeq: number): Promise<EventLogEntry[]>;
178
187
  /**
179
- * Fetch a paginated range of entries.
180
- * @returns `{ entries, hasMore }` — `hasMore` is `true` when another
181
- * page exists (i.e. the DO returned `limit + 1` rows).
182
- */
188
+ * Fetch a paginated range of entries.
189
+ * @returns `{ entries, hasMore }` — `hasMore` is `true` when another
190
+ * page exists (i.e. the DO returned `limit + 1` rows).
191
+ */
183
192
  getRange(fromSeq: number, limit?: number): Promise<{
184
193
  entries: EventLogEntry[];
185
194
  hasMore: boolean;
186
195
  }>;
187
196
  /**
188
- * Return the total number of entries currently in the log.
189
- */
197
+ * Return the total number of entries currently in the log.
198
+ */
190
199
  getSize(): Promise<number>;
191
200
  /**
192
- * Return the full log state — all entries plus the next seq number.
193
- */
201
+ * Return the full log state — all entries plus the next seq number.
202
+ */
194
203
  getState(): Promise<{
195
204
  entries: EventLogEntry[];
196
205
  nextSeq: number;
197
206
  }>;
198
207
  }
199
208
  /**
200
- * Type-safe event emitter that powers the event-sourcing runtime.
201
- * @example
202
- * ```ts
203
- * type MyEvents = { userCreated: { id: string; name: string }; error: { message: string } };
204
- *
205
- * const emitter = new EventEmitter<MyEvents>();
206
- * emitter.on("userCreated", (payload) => console.log(payload.name));
207
- * emitter.emit("userCreated", { id: "1", name: "alice" });
208
- * ```
209
- * @experimental
210
- */
209
+ * Type-safe event emitter that powers the event-sourcing runtime.
210
+ * @example
211
+ * ```ts
212
+ * type MyEvents = { userCreated: { id: string; name: string }; error: { message: string } };
213
+ *
214
+ * const emitter = new EventEmitter<MyEvents>();
215
+ * emitter.on("userCreated", (payload) => console.log(payload.name));
216
+ * emitter.emit("userCreated", { id: "1", name: "alice" });
217
+ * ```
218
+ * @experimental
219
+ */
211
220
  declare class EventEmitter<EventMap extends Record<string, unknown>> {
212
221
  #private;
213
222
  /**
214
- * Register a handler for a specific event type.
215
- * @returns An unsubscribe function (equivalent to calling {@link off}).
216
- */
223
+ * Register a handler for a specific event type.
224
+ * @returns An unsubscribe function (equivalent to calling {@link off}).
225
+ */
217
226
  on<K extends keyof EventMap>(event: K, handler: (payload: EventMap[K]) => void): () => void;
218
227
  /**
219
- * Remove a previously registered handler.
220
- */
228
+ * Remove a previously registered handler.
229
+ */
221
230
  off<K extends keyof EventMap>(event: K, handler: (payload: EventMap[K]) => void): void;
222
231
  /**
223
- * Register a wildcard handler that fires for **every** event type.
224
- * @returns An unsubscribe function.
225
- */
232
+ * Register a wildcard handler that fires for **every** event type.
233
+ * @returns An unsubscribe function.
234
+ */
226
235
  onAny(handler: (event: keyof EventMap, payload: unknown) => void): () => void;
227
236
  /**
228
- * Remove a wildcard handler.
229
- */
237
+ * Remove a wildcard handler.
238
+ */
230
239
  offAny(handler: (event: keyof EventMap, payload: unknown) => void): void;
231
240
  /**
232
- * Emit an event. All registered handlers (typed + wildcard) are invoked
233
- * synchronously. Exceptions from handlers are caught and silently
234
- * swallowed — they **must not** break the emitter loop.
235
- * @returns `true` if at least one handler was called.
236
- */
241
+ * Emit an event. All registered handlers (typed + wildcard) are invoked
242
+ * synchronously. Exceptions from handlers are caught and silently
243
+ * swallowed — they **must not** break the emitter loop.
244
+ * @returns `true` if at least one handler was called.
245
+ */
237
246
  emit<K extends keyof EventMap>(event: K, payload: EventMap[K]): boolean;
238
247
  /**
239
- * Return `true` when at least one listener is registered for `event`.
240
- */
248
+ * Return `true` when at least one listener is registered for `event`.
249
+ */
241
250
  hasListeners(event: keyof EventMap): boolean;
242
251
  /**
243
- * Return the number of typed listeners for a specific event.
244
- */
252
+ * Return the number of typed listeners for a specific event.
253
+ */
245
254
  listenerCount(event: keyof EventMap): number;
246
255
  /**
247
- * Remove all listeners.
248
- */
256
+ * Remove all listeners.
257
+ */
249
258
  clear(): void;
250
259
  }
251
260
  /**
252
- * Strategy for handling events whose `type` the reducer does not recognise.
253
- *
254
- * - `"warn"` _(default)_ — log a warning and skip the event (state unchanged).
255
- * - `"ignore"` — skip silently (no warning, no error).
256
- * - `"fail"` — throw an error, halting the apply / replay cycle.
257
- * - A **callback** — invoked with the entry; return truthy to mark it as
258
- * handled (no warning), falsy to fall through to the configured fallback.
259
- * @experimental
260
- */
261
+ * Strategy for handling events whose `type` the reducer does not recognise.
262
+ *
263
+ * - `"warn"` _(default)_ — log a warning and skip the event (state unchanged).
264
+ * - `"ignore"` — skip silently (no warning, no error).
265
+ * - `"fail"` — throw an error, halting the apply / replay cycle.
266
+ * - A **callback** — invoked with the entry; return truthy to mark it as
267
+ * handled (no warning), falsy to fall through to the configured fallback.
268
+ * @experimental
269
+ */
261
270
  type UnknownEventHandling = "warn" | "ignore" | "fail" | ((entry: EventLogEntry) => boolean);
262
271
  /**
263
- * Events emitted by the {@link EventSource} runtime.
264
- *
265
- * A `type` (not `interface`) so it satisfies `EventEmitter`'s
266
- * `Record&lt;string, unknown>` constraint — interfaces have no implicit index
267
- * signature and aren't assignable to `Record&lt;string, unknown>`.
268
- * @experimental
269
- */
272
+ * Events emitted by the {@link EventSource} runtime.
273
+ *
274
+ * A `type` (not `interface`) so it satisfies `EventEmitter`'s
275
+ * `Record<string, unknown>` constraint — interfaces have no implicit index
276
+ * signature and aren't assignable to `Record<string, unknown>`.
277
+ * @experimental
278
+ */
270
279
  type EventSourceEvents = {
271
280
  /** Fired (once) after the initial replay completes. */
272
281
  ready: {
@@ -284,111 +293,145 @@ type EventSourceEvents = {
284
293
  };
285
294
  };
286
295
  /**
287
- * A function that reduces an event into a state mutation.
288
- *
289
- * Pure functions are strongly encouraged: given the same event payload
290
- * and state, they must produce the same next state.
291
- * @experimental
292
- */
293
- type EventReducer<S> = (state: S, entry: EventLogEntry) => S;
294
- /**
295
- * Options for constructing an {@link EventSource}.
296
- * @experimental
297
- */
296
+ * Sentinel a reducer can return to EXPLICITLY signal it does not handle a
297
+ * given event's `type` — as opposed to returning the current `state`
298
+ * reference unchanged to represent a legitimate, idempotent no-op for a type
299
+ * it DOES recognise.
300
+ *
301
+ * Reference equality alone can't tell these two cases apart (REPLICA-07): a
302
+ * reducer that intentionally returns `state` for a type it fully understands
303
+ * (e.g. "already applied this event, nothing to do") would otherwise be
304
+ * misclassified as "unhandled" and trigger {@link UnknownEventHandling} — a
305
+ * spurious warning, or worse, a thrown error under `"fail"`. Return `UNHANDLED`
306
+ * only for a `type` your reducer truly does not recognise; every other return
307
+ * (including a `state` returned by reference) is treated as handled.
308
+ *
309
+ * Reducers that always recognise every event they're given (a single
310
+ * always-matching type, or a catch-all) can ignore this entirely.
311
+ * @experimental
312
+ */
313
+ declare const UNHANDLED: unique symbol;
314
+ /**
315
+ * A function that reduces an event into a state mutation.
316
+ *
317
+ * Pure functions are strongly encouraged: given the same event payload
318
+ * and state, they must produce the same next state. Return {@link UNHANDLED}
319
+ * to explicitly mark an event `type` this reducer does not process — see
320
+ * {@link UNHANDLED} for why reference equality against the input `state`
321
+ * cannot be used for this instead.
322
+ * @experimental
323
+ */
324
+ type EventReducer<S> = (state: S, entry: EventLogEntry) => S | typeof UNHANDLED;
325
+ /**
326
+ * Options for constructing an {@link EventSource}.
327
+ * @experimental
328
+ */
298
329
  interface EventSourceOptions {
299
330
  /**
300
- * How to handle events whose `type` is not recognised by the reducer.
301
- * @default "warn"
302
- */
331
+ * Cap this runtime's internal `log` to this many entries (REPLICA-06).
332
+ * `replayFromLog` copies every entry it replays from the source log into
333
+ * `this.log` too — a second, uncapped copy of the same history — so a
334
+ * long-lived `EventSource` fed by repeated replay accumulates entries in
335
+ * both places forever without a cap.
336
+ *
337
+ * `undefined` (the default) preserves unbounded retention.
338
+ */
339
+ maxLogEntries?: number;
340
+ /**
341
+ * How to handle events whose `type` is not recognised by the reducer.
342
+ * @default "warn"
343
+ */
303
344
  unknownEventHandling?: UnknownEventHandling;
304
345
  }
305
346
  /**
306
- * Event-sourcing runtime that maintains a derived state by replaying an
307
- * append-only {@link EventLog}.
308
- *
309
- * Usage:
310
- * ```ts
311
- * const source = new EventSource(initialState, myReducer);
312
- * await source.replayFromLog(existingLog);
313
- *
314
- * // Later, when a new event arrives:
315
- * const entry = source.applyEvent("user-created", { id: "1", name: "alice" });
316
- * console.log(source.state); // updated state
317
- * ```
318
- * @experimental
319
- */
347
+ * Event-sourcing runtime that maintains a derived state by replaying an
348
+ * append-only {@link EventLog}.
349
+ *
350
+ * Usage:
351
+ * ```ts
352
+ * const source = new EventSource(initialState, myReducer);
353
+ * await source.replayFromLog(existingLog);
354
+ *
355
+ * // Later, when a new event arrives:
356
+ * const entry = source.applyEvent("user-created", { id: "1", name: "alice" });
357
+ * console.log(source.state); // updated state
358
+ * ```
359
+ * @experimental
360
+ */
320
361
  declare class EventSource<S extends Record<string, unknown> = Record<string, unknown>> {
321
362
  #private;
322
363
  readonly emitter: EventEmitter<EventSourceEvents>;
323
364
  readonly log: EventLog;
324
365
  constructor(initialState: S, reducer: EventReducer<S>, options?: EventSourceOptions);
325
366
  /**
326
- * The current derived state. Read-only snapshot; mutate through events.
327
- */
367
+ * The current derived state. Read-only snapshot; mutate through events.
368
+ */
328
369
  get state(): Readonly<S>;
329
370
  /**
330
- * Whether the initial replay from an existing log has completed.
331
- */
371
+ * Whether the initial replay from an existing log has completed.
372
+ */
332
373
  get replayed(): boolean;
333
374
  /**
334
- * Append a new event to the log and apply it to the current state.
335
- *
336
- * Accepts either an {@link InputEvent} (e.g. from a `defineEvents` factory)
337
- * or the traditional `(type, payload)` pair.
338
- * @returns The newly created log entry (with its assigned `seq`).
339
- */
375
+ * Append a new event to the log and apply it to the current state.
376
+ *
377
+ * Accepts either an {@link InputEvent} (e.g. from a `defineEvents` factory)
378
+ * or the traditional `(type, payload)` pair.
379
+ * @returns The newly created log entry (with its assigned `seq`).
380
+ */
340
381
  applyEvent(event: InputEvent, options?: AppendOptions): EventLogEntry;
341
382
  applyEvent(type: string, payload: unknown, options?: AppendOptions): EventLogEntry;
342
383
  /**
343
- * Replay all entries from an existing {@link EventLog} to bootstrap
344
- * the current state.
345
- *
346
- * Idempotent across calls: only source entries past the `#lastAppliedSeq`
347
- * watermark are applied, so re-invoking picks up just the new entries.
348
- * @param log The external log to replay from.
349
- */
384
+ * Replay all entries from an existing {@link EventLog} to bootstrap
385
+ * the current state.
386
+ *
387
+ * Idempotent across calls: only source entries past the `#lastAppliedSeq`
388
+ * watermark are applied, so re-invoking picks up just the new entries.
389
+ * @param log The external log to replay from.
390
+ */
350
391
  replayFromLog(log: EventLog): void;
351
392
  /**
352
- * Reset the runtime to a base state, optionally resuming from a watermark.
353
- *
354
- * Useful after loading a snapshot from the DO: pass the snapshot's state as
355
- * `initialState` and its highest applied source `seq` as `resumeFromSeq`, so
356
- * the next {@link replayFromLog} applies ONLY the events after the snapshot
357
- * (`getSince(resumeFromSeq + 1)`) rather than replaying the whole log on top
358
- * of the snapshot — which would double-apply non-idempotent reducers.
359
- *
360
- * Omit `resumeFromSeq` (default `-1`) for a full reset that replays from the
361
- * beginning.
362
- * @param initialState The base state to reset to (e.g. a loaded snapshot).
363
- * @param resumeFromSeq Highest source `seq` already baked into `initialState`, or `-1` to replay all.
364
- */
393
+ * Reset the runtime to a base state, optionally resuming from a watermark.
394
+ *
395
+ * Useful after loading a snapshot from the DO: pass the snapshot's state as
396
+ * `initialState` and its highest applied source `seq` as `resumeFromSeq`, so
397
+ * the next {@link replayFromLog} applies ONLY the events after the snapshot
398
+ * (`getSince(resumeFromSeq + 1)`) rather than replaying the whole log on top
399
+ * of the snapshot — which would double-apply non-idempotent reducers.
400
+ *
401
+ * Omit `resumeFromSeq` (default `-1`) for a full reset that replays from the
402
+ * beginning.
403
+ * @param initialState The base state to reset to (e.g. a loaded snapshot).
404
+ * @param resumeFromSeq Highest source `seq` already baked into `initialState`, or `-1` to replay all.
405
+ */
365
406
  reset(initialState: S, resumeFromSeq?: number): void;
366
407
  /**
367
- * Return an async generator that yields every event as it is applied,
368
- * starting from the events currently in the log and continuing with
369
- * every future `applyEvent` / `replayFromLog` call.
370
- *
371
- * The generator runs indefinitely — it never returns. Callers should
372
- * break out of the `for await` loop or use an `AbortSignal` to stop.
373
- * @example
374
- * ```ts
375
- * for await (const entry of source.events()) {
376
- * console.log("event applied:", entry);
377
- * }
378
- * ```
379
- */
408
+ * Return an async generator that yields every event as it is applied,
409
+ * starting from the events currently in the log and continuing with
410
+ * every future `applyEvent` / `replayFromLog` call.
411
+ *
412
+ * The generator runs indefinitely unless given a `signal` — callers
413
+ * should break out of the `for await` loop or pass an `AbortSignal` to
414
+ * stop it (an abort settles the generator, `done: true`, on its next
415
+ * iteration step; it does not throw).
416
+ * @example
417
+ * ```ts
418
+ * for await (const entry of source.events()) {
419
+ * console.log("event applied:", entry);
420
+ * }
421
+ * ```
422
+ */
380
423
  events(signal?: AbortSignal): AsyncGenerator<EventLogEntry>;
381
424
  }
382
425
  /**
383
- * Interface for persisting event-sourced state snapshots.
384
- *
385
- * In a Lunora app the primary implementation is backed by the
386
- * SnapshotDO (a Durable Object) on the server side. On the client
387
- * the {@link InMemorySnapshotStore} is used for the offline-first
388
- * local mirror, while a production client would implement this
389
- * over IndexedDB or OPFS.
390
- * @experimental
391
- */
426
+ * Interface for persisting event-sourced state snapshots.
427
+ *
428
+ * In a Lunora app the primary implementation is backed by the
429
+ * SnapshotDO (a Durable Object) on the server side. On the client
430
+ * the {@link InMemorySnapshotStore} is used for the offline-first
431
+ * local mirror, while a production client would implement this
432
+ * over IndexedDB or OPFS.
433
+ * @experimental
434
+ */
392
435
  interface SnapshotStore {
393
436
  /** Delete all snapshots. */
394
437
  clear: () => Promise<void>;
@@ -402,11 +445,11 @@ interface SnapshotStore {
402
445
  save: (key: string, snapshot: unknown) => Promise<void>;
403
446
  }
404
447
  /**
405
- * In-memory snapshot store. Useful for testing and for the local
406
- * offline-first mirror where persistence is handled at a higher
407
- * layer (IndexedDB adapter).
408
- * @experimental
409
- */
448
+ * In-memory snapshot store. Useful for testing and for the local
449
+ * offline-first mirror where persistence is handled at a higher
450
+ * layer (IndexedDB adapter).
451
+ * @experimental
452
+ */
410
453
  declare class InMemorySnapshotStore implements SnapshotStore {
411
454
  #private;
412
455
  save(key: string, snapshot: unknown): Promise<void>;
@@ -416,23 +459,23 @@ declare class InMemorySnapshotStore implements SnapshotStore {
416
459
  clear(): Promise<void>;
417
460
  }
418
461
  /**
419
- * A function that reduces an event entry into a state mutation.
420
- *
421
- * Pure functions are strongly encouraged: given the same event and state,
422
- * they must produce the same next state for deterministic replay.
423
- * @experimental
424
- */
462
+ * A function that reduces an event entry into a state mutation.
463
+ *
464
+ * Pure functions are strongly encouraged: given the same event and state,
465
+ * they must produce the same next state for deterministic replay.
466
+ * @experimental
467
+ */
425
468
  type MaterializerReducer<S> = (state: S, entry: EventLogEntry) => S;
426
469
  /**
427
- * Options for defining a single materializer.
428
- * @experimental
429
- */
470
+ * Options for defining a single materializer.
471
+ * @experimental
472
+ */
430
473
  interface MaterializerDef<S> {
431
474
  /**
432
- * Reducer invoked for every event in the log.
433
- *
434
- * Return the current state unchanged to skip the event.
435
- */
475
+ * Reducer invoked for every event in the log.
476
+ *
477
+ * Return the current state unchanged to skip the event.
478
+ */
436
479
  handle: MaterializerReducer<S>;
437
480
  /** Factory for the initial (empty) state. */
438
481
  initial: () => S;
@@ -440,9 +483,9 @@ interface MaterializerDef<S> {
440
483
  readonly name: string;
441
484
  }
442
485
  /**
443
- * A constructed materializer ready to be used with a {@link MaterializerRuntime}.
444
- * @experimental
445
- */
486
+ * A constructed materializer ready to be used with a {@link MaterializerRuntime}.
487
+ * @experimental
488
+ */
446
489
  interface Materializer<S> {
447
490
  /** Apply a single event entry through the reducer. */
448
491
  apply: (entry: EventLogEntry) => void;
@@ -455,141 +498,162 @@ interface Materializer<S> {
455
498
  readonly state: Readonly<S>;
456
499
  }
457
500
  /**
458
- * Declare a materializer — a named reducer that derives state from events.
459
- *
460
- * The returned {@link Materializer} object can be used standalone or passed
461
- * to a {@link MaterializerRuntime} for automatic log subscription.
462
- * @experimental
463
- */
501
+ * Declare a materializer — a named reducer that derives state from events.
502
+ *
503
+ * The returned {@link Materializer} object can be used standalone or passed
504
+ * to a {@link MaterializerRuntime} for automatic log subscription.
505
+ * @experimental
506
+ */
464
507
  declare const defineMaterializer: <S>(definition: MaterializerDef<S>) => Materializer<S>;
465
508
  /**
466
- * A materializer of any state shape. The {@link MaterializerRuntime} holds a
467
- * heterogeneous collection and only ever calls `apply(entry)` / `setState(...)`
468
- * (with cast values) / reads `def.name` — it never needs the concrete state
469
- * type. `Materializer&lt;unknown>` won't do: `setState(state: S)` makes
470
- * `Materializer&lt;S>` invariant in `S`, so `Materializer&lt;number>` isn't assignable
471
- * to `Materializer&lt;unknown>`. Erasing the type param is the idiomatic fix.
472
- */
509
+ * A materializer of any state shape. The {@link MaterializerRuntime} holds a
510
+ * heterogeneous collection and only ever calls `apply(entry)` / `setState(...)`
511
+ * (with cast values) / reads `def.name` — it never needs the concrete state
512
+ * type. `Materializer<unknown>` won't do: `setState(state: S)` makes
513
+ * `Materializer<S>` invariant in `S`, so `Materializer<number>` isn't assignable
514
+ * to `Materializer<unknown>`. Erasing the type param is the idiomatic fix.
515
+ */
473
516
  type AnyMaterializer = Materializer<any>;
474
517
  /**
475
- * Options for constructing a {@link MaterializerRuntime}.
476
- * @experimental
477
- */
518
+ * Options for constructing a {@link MaterializerRuntime}.
519
+ * @experimental
520
+ */
478
521
  interface MaterializerRuntimeOptions {
479
522
  /**
480
- * Optional EventLogDO client for persistent event log integration.
481
- *
482
- * When provided, the runtime can bootstrap from the DO on startup
483
- * (recover from snapshots → catch up via `getSince`) and append
484
- * new events through the DO automatically.
485
- */
523
+ * Optional EventLogDO client for persistent event log integration.
524
+ *
525
+ * When provided, the runtime can bootstrap from the DO on startup
526
+ * (recover from snapshots → catch up via `getSince`) and append
527
+ * new events through the DO automatically.
528
+ */
486
529
  doClient?: EventLogDOClient;
487
530
  /** Optional snapshot store for persisting/recovering materialized state. */
488
531
  snapshotStore?: SnapshotStore;
489
532
  /**
490
- * How to handle events whose type no materializer handles.
491
- * @default "warn"
492
- */
533
+ * How to handle events whose type no materializer handles.
534
+ * @default "warn"
535
+ */
493
536
  unknownEventHandling?: UnknownEventHandling;
494
537
  }
495
538
  /**
496
- * Runtime that drives one or more materializers from an event log.
497
- *
498
- * Handles:
499
- * - Replaying the full log on startup
500
- * - Applying new events as they arrive
501
- * - Periodic snapshot persistence
502
- * - Recovery from snapshots (replay only what's missing)
503
- * @experimental
504
- */
539
+ * Runtime that drives one or more materializers from an event log.
540
+ *
541
+ * Handles:
542
+ * - Replaying the full log on startup
543
+ * - Applying new events as they arrive
544
+ * - Periodic snapshot persistence
545
+ * - Recovery from snapshots (replay only what's missing)
546
+ * @experimental
547
+ */
505
548
  declare class MaterializerRuntime {
506
549
  #private;
507
550
  constructor(materializers: AnyMaterializer[], options?: MaterializerRuntimeOptions);
508
551
  /**
509
- * The sequence number of the last event applied to all materializers.
510
- */
552
+ * The lowest per-materializer watermark — the seq of the next event that
553
+ * at least one materializer has not yet applied. `0` when there are no
554
+ * materializers.
555
+ */
511
556
  get appliedSeq(): number;
512
557
  /**
513
- * Replay a batch of entries through all materializers.
514
- *
515
- * Entries with `seq < this.appliedSeq` are silently skipped (idempotent).
516
- * @returns The number of entries actually applied.
517
- */
558
+ * Replay a batch of entries, applying each entry only to the
559
+ * materializers whose own watermark is behind it — a materializer at or
560
+ * past an entry's seq (e.g. recovered from a snapshot, or already caught
561
+ * up) skips it, so no materializer ever double-applies an event.
562
+ * @returns The number of entries applied to at least one materializer.
563
+ */
518
564
  applyEntries(entries: ReadonlyArray<EventLogEntry>): number;
519
565
  /**
520
- * Attempt to recover materialized state from a snapshot store.
521
- *
522
- * When a snapshot is found for a materializer, its state is restored
523
- * and the snapshot's watermark (`appliedSeq`) is returned so the caller
524
- * can skip replaying entries up to that point.
525
- * @returns The highest `appliedSeq` across all recovered snapshots, or `0`.
526
- */
566
+ * Attempt to recover materialized state from a snapshot store.
567
+ *
568
+ * When a snapshot is found for a materializer, its state AND its own
569
+ * watermark are restored from that snapshot. A materializer with no
570
+ * snapshot keeps its current watermark (`0` for a fresh runtime) — it
571
+ * does NOT inherit another materializer's watermark, so it still catches
572
+ * up from the very beginning (REPLICA-04: previously a shared watermark
573
+ * was bumped to the MAX across snapshots, permanently skipping events 0..N
574
+ * for any un-snapshotted or lagging materializer).
575
+ * @returns The highest snapshot `appliedSeq` across all materializers, or
576
+ * `0` — kept for backward compatibility; callers that need the fetch
577
+ * watermark for catch-up should use the per-materializer minimum instead
578
+ * (see `initialize`).
579
+ */
527
580
  recoverFromSnapshots(): Promise<number>;
528
581
  /**
529
- * Persist the current state of all materializers as snapshots.
530
- */
582
+ * Persist the current state of all materializers as snapshots, each
583
+ * tagged with ITS OWN watermark (not a shared one).
584
+ */
531
585
  persistSnapshots(): Promise<void>;
532
586
  /**
533
- * Bootstrap the runtime from the EventLogDO.
534
- *
535
- * 1. Recover materialized state from snapshots (if a snapshotStore is
536
- * configured).
537
- * 2. Fetch all entries since the recovered watermark from the DO.
538
- * 3. Apply them through the materializers.
539
- *
540
- * Call this once on startup / after the DO binding is available.
541
- * @returns The number of entries applied during catch-up.
542
- */
587
+ * Bootstrap the runtime from the EventLogDO.
588
+ *
589
+ * 1. Recover materialized state from snapshots (if a snapshotStore is
590
+ * configured).
591
+ * 2. Fetch all entries since the MINIMUM per-materializer watermark from
592
+ * the DO — not the maximum — so a materializer with no snapshot (or a
593
+ * lower one) still receives every event it hasn't seen (REPLICA-04).
594
+ * 3. Apply them through the materializers; `applyEntries` skips each
595
+ * entry for any materializer already past it, so nothing is double-applied.
596
+ *
597
+ * Call this once on startup / after the DO binding is available.
598
+ * @returns The number of entries applied during catch-up.
599
+ */
543
600
  initialize(): Promise<number>;
544
601
  /**
545
- * Append an event to the EventLogDO and apply it through all
546
- * materializers.
547
- *
548
- * This is a convenience over calling `doClient.append(...)` +
549
- * `runtime.applyEntries(...)` yourself — it persists the event
550
- * **then** applies the returned entry (with its assigned seq).
551
- * @returns The persisted entry with its DO-assigned `seq`.
552
- */
602
+ * Append an event to the EventLogDO and apply it through all
603
+ * materializers.
604
+ *
605
+ * This is a convenience over calling `doClient.append(...)` +
606
+ * `runtime.applyEntries(...)` yourself — it persists the event
607
+ * **then** applies the returned entry (with its assigned seq).
608
+ * @returns The persisted entry with its DO-assigned `seq`.
609
+ */
553
610
  appendEvent(input: AppendEventInput): Promise<EventLogEntry>;
554
611
  /**
555
- * Reset all materializers to their initial state and clear snapshots.
556
- */
612
+ * Reset all materializers to their initial state and clear snapshots.
613
+ */
557
614
  reset(): void;
558
615
  /**
559
- * The list of registered materializers.
560
- */
616
+ * The list of registered materializers.
617
+ */
561
618
  get materializers(): ReadonlyArray<Materializer<unknown>>;
562
619
  }
563
620
  /**
564
- * Apply a {@link TableDiff} to the given SQLite database by translating
565
- * each row change into an INSERT, UPDATE, or DELETE statement.
566
- *
567
- * All statements are wrapped in a single transaction.
568
- * @param database SQLite adapter the statements run against.
569
- * @param diff The table diff to apply.
570
- * @param pkColumn Primary key column for DELETE/UPDATE (default `"id"`).
571
- * @experimental
572
- */
621
+ * Apply a {@link TableDiff} to the given SQLite database by translating
622
+ * each row change into an INSERT, UPDATE, or DELETE statement.
623
+ *
624
+ * All statements are wrapped in a single transaction.
625
+ * @param database SQLite adapter the statements run against.
626
+ * @param diff The table diff to apply.
627
+ * @param pkColumn Primary key column for DELETE/UPDATE (default `"id"`).
628
+ * @experimental
629
+ */
573
630
  declare const applyDiffToDatabase: (database: SqliteAdapter, diff: TableDiff, pkColumn?: string) => void;
574
631
  /**
575
- * Apply multiple diffs **in order** within a single transaction.
576
- *
577
- * Each diff uses `"id"` as the primary key column. For tables with a custom
578
- * PK, use {@link applyDiffToDatabase} per-diff and pass the PK explicitly.
579
- * @experimental
580
- */
632
+ * Apply multiple diffs **in order** within a single transaction.
633
+ *
634
+ * Each diff uses `"id"` as the primary key column. For tables with a custom
635
+ * PK, use {@link applyDiffToDatabase} per-diff and pass the PK explicitly.
636
+ * @experimental
637
+ */
581
638
  declare const applyDiffsToDatabase: (database: SqliteAdapter, diffs: ReadonlyArray<TableDiff>) => void;
582
639
  interface EventLogDOState {
583
640
  storage: {
584
641
  sql: {
585
642
  exec: (query: string, ...params: unknown[]) => unknown;
586
643
  };
644
+ /**
645
+ * The DO platform's native atomic-transaction primitive (async;
646
+ * commits on resolve, rolls back on throw/reject). Test doubles that
647
+ * omit it fall back to a bare (non-transactional) call — see
648
+ * `#handleAppend`.
649
+ */
650
+ transaction?: <T>(closure: () => Promise<T> | T) => Promise<T>;
587
651
  };
588
652
  }
589
653
  /**
590
- * `EventLogDO` is part of the experimental `@lunora/replica` API and may change without a major version bump.
591
- * @experimental
592
- */
654
+ * `EventLogDO` is part of the experimental `@lunora/replica` API and may change without a major version bump.
655
+ * @experimental
656
+ */
593
657
  declare class EventLogDO {
594
658
  #private;
595
659
  protected state: EventLogDOState;
@@ -598,10 +662,10 @@ declare class EventLogDO {
598
662
  fetch(request: Request): Promise<Response>;
599
663
  }
600
664
  /**
601
- * `next()` advances the middleware chain. Called with no argument it forwards
602
- * the current context unchanged; called with `{ ctx }` it shallow-merges the
603
- * extension, and the result type reflects the widened context.
604
- */
665
+ * `next()` advances the middleware chain. Called with no argument it forwards
666
+ * the current context unchanged; called with `{ ctx }` it shallow-merges the
667
+ * extension, and the result type reflects the widened context.
668
+ */
605
669
  interface MiddlewareNext<ContextIn> {
606
670
  (): Promise<ContextIn>;
607
671
  <Extension extends Record<string, unknown>>(options: {
@@ -609,46 +673,45 @@ interface MiddlewareNext<ContextIn> {
609
673
  }): Promise<ContextIn & Extension>;
610
674
  }
611
675
  /**
612
- * A middleware receives the current context and a `next` continuation. Its
613
- * return type becomes the builder's new context, so `return next({ ctx })`
614
- * propagates the extension into every downstream `.use()` and the handler.
615
- */
676
+ * A middleware receives the current context and a `next` continuation. Its
677
+ * return type becomes the builder's new context, so `return next({ ctx })`
678
+ * propagates the extension into every downstream `.use()` and the handler.
679
+ */
616
680
  type Middleware<ContextIn, ContextOut> = (options: {
617
681
  ctx: ContextIn;
618
682
  next: MiddlewareNext<ContextIn>;
619
683
  }) => ContextOut | Promise<ContextOut>;
620
- /** Options accepted by `initLunora.dataModel&lt;DM>().create(...)`. Reserved for transformer/error-formatter wiring. */
621
- /**
622
- * The per-request `ctx.events` facade that {@link eventsContext} attaches.
623
- *
624
- * Each method delegates to the corresponding {@link EventLogDOClient} method,
625
- * so handlers never need to import or reference the DO client directly.
626
- * @experimental
627
- */
684
+ /**
685
+ * The per-request `ctx.events` facade that {@link eventsContext} attaches.
686
+ *
687
+ * Each method delegates to the corresponding {@link EventLogDOClient} method,
688
+ * so handlers never need to import or reference the DO client directly.
689
+ * @experimental
690
+ */
628
691
  interface EventsFacade {
629
692
  /**
630
- * Append one or more events to the log.
631
- * @returns The persisted entries with their assigned `seq` numbers.
632
- */
693
+ * Append one or more events to the log.
694
+ * @returns The persisted entries with their assigned `seq` numbers.
695
+ */
633
696
  append: (events: {
634
697
  payload: unknown;
635
698
  timestamp?: number;
636
699
  type: string;
637
700
  }[]) => Promise<EventLogEntry[]>;
638
701
  /**
639
- * Fetch a paginated range of entries.
640
- * @returns `{ entries, hasMore }` — `hasMore` is `true` when another
641
- * page exists.
642
- */
702
+ * Fetch a paginated range of entries.
703
+ * @returns `{ entries, hasMore }` — `hasMore` is `true` when another
704
+ * page exists.
705
+ */
643
706
  getRange: (fromSeq: number, limit?: number) => Promise<{
644
707
  entries: EventLogEntry[];
645
708
  hasMore: boolean;
646
709
  }>;
647
710
  /**
648
- * Fetch all entries with `seq >= sinceSeq`.
649
- *
650
- * Pass `sinceSeq = 0` to fetch the entire log.
651
- */
711
+ * Fetch all entries with `seq >= sinceSeq`.
712
+ *
713
+ * Pass `sinceSeq = 0` to fetch the entire log.
714
+ */
652
715
  getSince: (sinceSeq: number) => Promise<EventLogEntry[]>;
653
716
  /** Return the total number of entries currently in the log. */
654
717
  getSize: () => Promise<number>;
@@ -659,47 +722,47 @@ interface EventsFacade {
659
722
  }>;
660
723
  }
661
724
  /**
662
- * The context shape produced by {@link eventsContext}.
663
- * @experimental
664
- */
725
+ * The context shape produced by {@link eventsContext}.
726
+ * @experimental
727
+ */
665
728
  interface EventsContextOutput {
666
729
  /** Typed event log facade backed by an {@link EventLogDOClient}. */
667
730
  readonly events: EventsFacade;
668
731
  }
669
732
  /**
670
- * Create a middleware that attaches a typed `ctx.events` facade backed by
671
- * the given {@link EventLogDOClient}.
672
- *
673
- * The facade surfaces `append`, `getSince`, `getRange`, `getSize`, and
674
- * `getState` — every method the DO client exposes — so handlers can read
675
- * and write the event log without reaching for the DO stub directly.
676
- *
677
- * The middleware is unopinionated about which context it extends — it works
678
- * with `MutationCtx`, `ActionCtx`, or `QueryCtx` equally.
679
- * @param client A configured {@link EventLogDOClient} instance.
680
- * @returns A Lunora middleware that injects `ctx.events`.
681
- *
682
- * ```ts
683
- * const client = new EventLogDOClient({
684
- * fetch: (req) => env.EVENTS.get(id).fetch(req),
685
- * });
686
- *
687
- * export const logEvent = mutation
688
- * .use(eventsContext(client))
689
- * .mutation(async ({ ctx, args }) => {
690
- * const [entry] = await ctx.events.append([{ type: "order.placed", payload: args }]);
691
- * return entry;
692
- * });
693
- * ```
694
- * @experimental
695
- */
733
+ * Create a middleware that attaches a typed `ctx.events` facade backed by
734
+ * the given {@link EventLogDOClient}.
735
+ *
736
+ * The facade surfaces `append`, `getSince`, `getRange`, `getSize`, and
737
+ * `getState` — every method the DO client exposes — so handlers can read
738
+ * and write the event log without reaching for the DO stub directly.
739
+ *
740
+ * The middleware is unopinionated about which context it extends — it works
741
+ * with `MutationCtx`, `ActionCtx`, or `QueryCtx` equally.
742
+ * @param client A configured {@link EventLogDOClient} instance.
743
+ * @returns A Lunora middleware that injects `ctx.events`.
744
+ *
745
+ * ```ts
746
+ * const client = new EventLogDOClient({
747
+ * fetch: (req) => env.EVENTS.get(id).fetch(req),
748
+ * });
749
+ *
750
+ * export const logEvent = mutation
751
+ * .use(eventsContext(client))
752
+ * .mutation(async ({ ctx, args }) => {
753
+ * const [entry] = await ctx.events.append([{ type: "order.placed", payload: args }]);
754
+ * return entry;
755
+ * });
756
+ * ```
757
+ * @experimental
758
+ */
696
759
  declare const eventsContext: <Context>(client: EventLogDOClient) => Middleware<Context, Context & EventsContextOutput>;
697
760
  /**
698
- * A dependency-light subscription sink interface that mirrors what
699
- * `LunoraClient.subscribe` expects, so the mirror helper doesn't
700
- * need to import `@lunora/client`.
701
- * @experimental
702
- */
761
+ * A dependency-light subscription sink interface that mirrors what
762
+ * `LunoraClient.subscribe` expects, so the mirror helper doesn't
763
+ * need to import `@lunora/client`.
764
+ * @experimental
765
+ */
703
766
  interface SubscriptionClient {
704
767
  subscribe: (functionRef: {
705
768
  __lunoraRef: string;
@@ -708,203 +771,212 @@ interface SubscriptionClient {
708
771
  }) => () => void;
709
772
  }
710
773
  /**
711
- * Subscribe a Lunora-query to the local mirror so every server push
712
- * is applied to the local SQLite store.
713
- *
714
- * Each frame from a Lunora live query is the FULL current result set, so the
715
- * callback treats it as a snapshot: it upserts every row present and emits a
716
- * `delete` for any id that was mirrored on a previous frame but is absent now —
717
- * otherwise rows that drop out of the server result would linger stale in the
718
- * local mirror. Rows are keyed by their `id` field (the mirror's default primary
719
- * key); a row without an `id` can't be reconciled on removal, and — because the
720
- * mirror table's `id` column is `NOT NULL` — will fail the insert.
721
- *
722
- * The mirror table name is derived from the function ref alone (not `args`), so
723
- * do NOT mirror two subscriptions to the same function with different `args`
724
- * into the same mirror: they'd share one table and the snapshot-delete pass of
725
- * one could remove rows still live in the other.
726
- *
727
- * Call the returned unsubscribe function to tear down both the client
728
- * subscription and future mirror writes.
729
- * @example
730
- * ```ts
731
- * const unsub = subscribeToMirror(client, mirror, api.todos.list, { userId });
732
- * // Later:
733
- * unsub();
734
- * ```
735
- * @experimental
736
- */
774
+ * Subscribe a Lunora-query to the local mirror so every server push
775
+ * is applied to the local SQLite store.
776
+ *
777
+ * Each frame from a Lunora live query is the FULL current result set, so the
778
+ * callback treats it as a snapshot: it upserts every row present and emits a
779
+ * `delete` for any id that was mirrored on a previous frame but is absent now —
780
+ * otherwise rows that drop out of the server result would linger stale in the
781
+ * local mirror. Rows are keyed by their `id` field (the mirror's default primary
782
+ * key); a row without an `id` can't be reconciled on removal, and — because the
783
+ * mirror table's `id` column is `NOT NULL` — will fail the insert.
784
+ *
785
+ * The mirror table name is derived from the function ref alone (not `args`), so
786
+ * do NOT mirror two subscriptions to the same function with different `args`
787
+ * into the same mirror: they'd share one table and the snapshot-delete pass of
788
+ * one could remove rows still live in the other.
789
+ *
790
+ * Call the returned unsubscribe function to tear down both the client
791
+ * subscription and future mirror writes.
792
+ * @example
793
+ * ```ts
794
+ * const unsub = subscribeToMirror(client, mirror, api.todos.list, { userId });
795
+ * // Later:
796
+ * unsub();
797
+ * ```
798
+ * @experimental
799
+ */
737
800
  declare const subscribeToMirror: (client: SubscriptionClient, mirror: LocalMirror, functionRef: {
738
801
  __lunoraRef: string;
739
802
  }, args: Record<string, unknown>, shardKey?: string) => (() => void);
740
803
  /**
741
- * Callback signature for state-change subscriptions.
742
- * @experimental
743
- */
804
+ * Callback signature for state-change subscriptions.
805
+ * @experimental
806
+ */
744
807
  type StateChangeCallback = (state: Readonly<Record<string, unknown>>) => void;
745
808
  /**
746
- * Callback signature for event-type subscriptions.
747
- * @experimental
748
- */
809
+ * Callback signature for event-type subscriptions.
810
+ * @experimental
811
+ */
749
812
  type EventCallback = (entry: EventLogEntry) => void;
750
813
  /**
751
- * Manages subscriptions to state changes and individual event types
752
- * for the event-sourcing runtime.
753
- *
754
- * Each subscription returns an unsubscribe function — the caller is
755
- * expected to call it during cleanup (e.g. in a React `useEffect`
756
- * return or a Svelte `onDestroy`).
757
- * @example
758
- * ```ts
759
- * const subs = new SubscriptionManager();
760
- *
761
- * // Subscribe to every state change
762
- * const unsub1 = subs.onStateChange((state) => console.log("new state", state));
763
- *
764
- * // Subscribe to a specific event type
765
- * const unsub2 = subs.onEvent("user-created", (entry) => console.log("user created", entry.payload));
766
- *
767
- * // Later, when state or events arrive:
768
- * subs.notifyState({ users: [] });
769
- * subs.notifyEvent({ seq: 1, type: "user-created", payload: { id: "1" }, timestamp: 100 });
770
- *
771
- * // Cleanup
772
- * unsub1();
773
- * unsub2();
774
- * ```
775
- * @experimental
776
- */
814
+ * Manages subscriptions to state changes and individual event types
815
+ * for the event-sourcing runtime.
816
+ *
817
+ * Each subscription returns an unsubscribe function — the caller is
818
+ * expected to call it during cleanup (e.g. in a React `useEffect`
819
+ * return or a Svelte `onDestroy`).
820
+ * @example
821
+ * ```ts
822
+ * const subs = new SubscriptionManager();
823
+ *
824
+ * // Subscribe to every state change
825
+ * const unsub1 = subs.onStateChange((state) => console.log("new state", state));
826
+ *
827
+ * // Subscribe to a specific event type
828
+ * const unsub2 = subs.onEvent("user-created", (entry) => console.log("user created", entry.payload));
829
+ *
830
+ * // Later, when state or events arrive:
831
+ * subs.notifyState({ users: [] });
832
+ * subs.notifyEvent({ seq: 1, type: "user-created", payload: { id: "1" }, timestamp: 100 });
833
+ *
834
+ * // Cleanup
835
+ * unsub1();
836
+ * unsub2();
837
+ * ```
838
+ * @experimental
839
+ */
777
840
  declare class SubscriptionManager {
778
841
  #private;
779
842
  /**
780
- * Subscribe to every state change emitted by the event source.
781
- * @returns Unsubscribe function.
782
- */
843
+ * Subscribe to every state change emitted by the event source.
844
+ * @returns Unsubscribe function.
845
+ */
783
846
  onStateChange(callback: StateChangeCallback): () => void;
784
847
  /**
785
- * Subscribe to a specific event type.
786
- * @param eventType The event type to listen for (matches `entry.type`).
787
- * @param callback Invoked with each matching entry.
788
- * @returns Unsubscribe function.
789
- */
848
+ * Subscribe to a specific event type.
849
+ * @param eventType The event type to listen for (matches `entry.type`).
850
+ * @param callback Invoked with each matching entry.
851
+ * @returns Unsubscribe function.
852
+ */
790
853
  onEvent(eventType: string, callback: EventCallback): () => void;
791
854
  /**
792
- * Notify all state-change subscribers with the current state.
793
- */
855
+ * Notify all state-change subscribers with the current state.
856
+ */
794
857
  notifyState(state: Readonly<Record<string, unknown>>): void;
795
858
  /**
796
- * Notify event-type subscribers whose `eventType` matches.
797
- */
859
+ * Notify event-type subscribers whose `eventType` matches.
860
+ */
798
861
  notifyEvent(entry: EventLogEntry): void;
799
862
  /**
800
- * Return the total number of active subscriptions.
801
- */
863
+ * Return the total number of active subscriptions.
864
+ */
802
865
  get size(): number;
803
866
  /**
804
- * Remove all subscriptions.
805
- */
867
+ * Remove all subscriptions.
868
+ */
806
869
  clear(): void;
807
870
  }
808
871
  /**
809
- * Options for constructing an {@link EventsSync}.
810
- * @experimental
811
- */
872
+ * Options for constructing an {@link EventsSync}.
873
+ * @experimental
874
+ */
812
875
  interface EventsSyncOptions {
813
876
  /**
814
- * Replay a batch of events through the derived-state machine.
815
- *
816
- * Called with every batch of new events fetched from the log. The
817
- * consumer should feed these events into their state machine
818
- * (e.g. an {@link import("@lunora/replica").EventSource | EventSource})
819
- * so that the machine's state reflects the latest log position.
820
- */
877
+ * Replay a batch of events through the derived-state machine.
878
+ *
879
+ * Called with every batch of new events fetched from the log. The
880
+ * consumer should feed these events into their state machine
881
+ * (e.g. an {@link import("@lunora/replica").EventSource | EventSource})
882
+ * so that the machine's state reflects the latest log position.
883
+ */
821
884
  applyEvents: (events: ReadonlyArray<EventLogEntry>) => void;
822
885
  /**
823
- * Fetch all events whose `seq >= sinceSeq`.
824
- *
825
- * In a server-side context, this typically wraps
826
- * {@link import("@lunora/replica").EventLogDOClient.getSince |
827
- * EventLogDOClient.getSince()}.
828
- * In a client context it could call a Lunora action that proxies to the
829
- * event log, or read from an IndexedDB cache.
830
- *
831
- * Return an empty array when there are no new events.
832
- */
886
+ * Fetch all events whose `seq >= sinceSeq`.
887
+ *
888
+ * In a server-side context, this typically wraps
889
+ * {@link import("@lunora/replica").EventLogDOClient.getSince |
890
+ * EventLogDOClient.getSince()}.
891
+ * In a client context it could call a Lunora action that proxies to the
892
+ * event log, or read from an IndexedDB cache.
893
+ *
894
+ * Return an empty array when there are no new events.
895
+ */
833
896
  fetchEventsSince: (sinceSeq: number) => Promise<ReadonlyArray<EventLogEntry>>;
834
897
  /**
835
- * Produce {@link TableDiff | TableDiffs} from the current derived state.
836
- *
837
- * Called after every batch of events has been applied. The consumer
838
- * compares the state _before_ and _after_ the batch and returns the
839
- * diffs needed to bring the LocalMirror up to date.
840
- *
841
- * Return an empty array when there are no changes to push to the mirror.
842
- */
898
+ * Produce {@link TableDiff | TableDiffs} from the current derived state.
899
+ *
900
+ * Called after every batch of events has been applied. The consumer
901
+ * **recomputes a full diff from the current mirror-vs-source state** and
902
+ * returns the diffs needed to bring the LocalMirror up to date.
903
+ *
904
+ * **MUST be idempotent** — it must NOT advance a one-shot cursor as a side
905
+ * effect. A batch that fails partway (a `mirror.applyDiff` throws) is
906
+ * retried on the next poll from the same watermark; if this call consumed a
907
+ * cursor on the first attempt it would return `[]` on the retry and the
908
+ * un-mirrored diffs would be lost forever. Recompute-from-current-state has
909
+ * no such hazard: calling it again with no new events returns the same
910
+ * diffs, and calling it after a partial mirror write returns exactly the
911
+ * diffs still missing from the mirror.
912
+ *
913
+ * Return an empty array when there are no changes to push to the mirror.
914
+ */
843
915
  getTableDiffs: () => TableDiff[];
844
916
  /**
845
- * The local SQLite mirror to apply diffs to.
846
- */
917
+ * The local SQLite mirror to apply diffs to.
918
+ */
847
919
  mirror: LocalMirror;
848
920
  /**
849
- * Called when an error occurs during a poll cycle.
850
- *
851
- * Defaults to `console.error`. Set to a no-op to suppress error logging.
852
- */
921
+ * Called when an error occurs during a poll cycle.
922
+ *
923
+ * Defaults to `console.error`. Set to a no-op to suppress error logging.
924
+ */
853
925
  onError?: (error: unknown) => void;
854
926
  /**
855
- * How often to poll for new events (in milliseconds).
856
- * @default 5000
857
- */
927
+ * How often to poll for new events (in milliseconds).
928
+ * @default 5000
929
+ */
858
930
  pollInterval?: number;
859
931
  }
860
932
  /**
861
- * Periodically polls an event log, replays events through a state machine,
862
- * converts the resulting state into {@link TableDiff | TableDiffs}, and
863
- * applies them to a {@link LocalMirror}.
864
- *
865
- * The class is **transport-agnostic** — it accepts a generic
866
- * `fetchEventsSince` function rather than coupling to a specific source
867
- * (EventLogDO, WebSocket push, IndexedDB, etc.).
868
- *
869
- * ## Lifecycle
870
- *
871
- * 1. Call `start()` to begin periodic polling.
872
- * 2. Call `sync()` to perform an immediate one-shot sync.
873
- * 3. Call `stop()` to halt polling.
874
- *
875
- * The current watermark is exposed via `watermark` and advances
876
- * monotonically as events are applied.
877
- * @experimental
878
- */
933
+ * Periodically polls an event log, replays events through a state machine,
934
+ * converts the resulting state into {@link TableDiff | TableDiffs}, and
935
+ * applies them to a {@link LocalMirror}.
936
+ *
937
+ * The class is **transport-agnostic** — it accepts a generic
938
+ * `fetchEventsSince` function rather than coupling to a specific source
939
+ * (EventLogDO, WebSocket push, IndexedDB, etc.).
940
+ *
941
+ * ## Lifecycle
942
+ *
943
+ * 1. Call `start()` to begin periodic polling.
944
+ * 2. Call `sync()` to perform an immediate one-shot sync.
945
+ * 3. Call `stop()` to halt polling.
946
+ *
947
+ * The current watermark is exposed via `watermark` and advances
948
+ * monotonically as events are applied.
949
+ * @experimental
950
+ */
879
951
  declare class EventsSync {
880
952
  #private;
881
953
  constructor(options: EventsSyncOptions);
882
954
  /**
883
- * The current watermark — the next `seq` the sync will fetch from.
884
- *
885
- * Starts at `0` (fetch everything). Advances to `max(seq) + 1` after
886
- * each successful poll cycle.
887
- */
955
+ * The current watermark — the next `seq` the sync will fetch from.
956
+ *
957
+ * Starts at `0` (fetch everything). Advances to `max(seq) + 1` after
958
+ * each successful poll cycle.
959
+ */
888
960
  get watermark(): number;
889
961
  /**
890
- * Start polling for new events on the configured interval.
891
- *
892
- * Does nothing if polling is already active.
893
- * Does **not** perform an initial sync — call {@link sync} once if you
894
- * need to catch up immediately.
895
- */
962
+ * Start polling for new events on the configured interval.
963
+ *
964
+ * Does nothing if polling is already active.
965
+ * Does **not** perform an initial sync — call {@link sync} once if you
966
+ * need to catch up immediately.
967
+ */
896
968
  start(): void;
897
969
  /**
898
- * Stop polling for new events.
899
- *
900
- * Safe to call when not started.
901
- */
970
+ * Stop polling for new events.
971
+ *
972
+ * Safe to call when not started.
973
+ */
902
974
  stop(): void;
903
975
  /**
904
- * Perform a one-shot sync: fetch events since the current watermark,
905
- * apply them through the state machine, and push diffs to the mirror.
906
- * @returns The number of events that were fetched and applied.
907
- */
976
+ * Perform a one-shot sync: fetch events since the current watermark,
977
+ * apply them through the state machine, and push diffs to the mirror.
978
+ * @returns The number of events that were fetched and applied.
979
+ */
908
980
  sync(): Promise<number>;
909
981
  }
910
- export { type AppendEventInput, type AppendOptions, type EventCallback, EventEmitter, type EventFactory, EventLog, EventLogDO, EventLogDOClient, type EventLogDOClientOptions, type EventLogEntry, type EventNamespace, type EventReducer, EventSource, type EventSourceEvents, type EventSourceOptions, type EventsContextOutput, type EventsDefinition, type EventsFacade, EventsSync, type EventsSyncOptions, InMemorySnapshotStore, type InputEvent, LocalMirror, type Materializer, type MaterializerDef, type MaterializerReducer, MaterializerRuntime, type MaterializerRuntimeOptions, type Seq, type SnapshotStore, type SqliteAdapter, type StateChangeCallback, type SubscriptionClient, SubscriptionManager, type TableDiff, type UnknownEventHandling, applyDiff, applyDiffToDatabase as applyDiffToDb, applyDiffToSnapshot, applyDiffs, applyDiffsToDatabase as applyDiffsToDb, defineEvents, defineMaterializer, eventsContext, subscribeToMirror };
982
+ export { type AppendEventInput, type AppendOptions, type EventCallback, EventEmitter, type EventFactory, EventLog, EventLogDO, EventLogDOClient, type EventLogDOClientOptions, type EventLogEntry, type EventNamespace, type EventReducer, EventSource, type EventSourceEvents, type EventSourceOptions, type EventsContextOutput, type EventsDefinition, type EventsFacade, EventsSync, type EventsSyncOptions, InMemorySnapshotStore, type InputEvent, LocalMirror, type Materializer, type MaterializerDef, type MaterializerReducer, MaterializerRuntime, type MaterializerRuntimeOptions, type Seq, type SnapshotStore, type SqliteAdapter, type StateChangeCallback, type SubscriptionClient, SubscriptionManager, type TableDiff, UNHANDLED, type UnknownEventHandling, applyDiff, applyDiffToDatabase as applyDiffToDb, applyDiffToSnapshot, applyDiffs, applyDiffsToDatabase as applyDiffsToDb, defineEvents, defineMaterializer, eventsContext, subscribeToMirror };