effect-cqrs 0.1.0 → 0.2.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 (59) hide show
  1. package/README.md +34 -6
  2. package/dist/Aggregate.d.ts +47 -6
  3. package/dist/Aggregate.d.ts.map +1 -1
  4. package/dist/Aggregate.js +45 -1
  5. package/dist/Aggregate.js.map +1 -1
  6. package/dist/AggregateService.d.ts +83 -11
  7. package/dist/AggregateService.d.ts.map +1 -1
  8. package/dist/AggregateService.js +261 -35
  9. package/dist/AggregateService.js.map +1 -1
  10. package/dist/Causation.d.ts +34 -0
  11. package/dist/Causation.d.ts.map +1 -0
  12. package/dist/Causation.js +32 -0
  13. package/dist/Causation.js.map +1 -0
  14. package/dist/EventStore.d.ts +22 -0
  15. package/dist/EventStore.d.ts.map +1 -1
  16. package/dist/EventStore.js +30 -10
  17. package/dist/EventStore.js.map +1 -1
  18. package/dist/EventVersions.d.ts +64 -0
  19. package/dist/EventVersions.d.ts.map +1 -0
  20. package/dist/EventVersions.js +55 -0
  21. package/dist/EventVersions.js.map +1 -0
  22. package/dist/Fixture.d.ts +40 -5
  23. package/dist/Fixture.d.ts.map +1 -1
  24. package/dist/Fixture.js +44 -3
  25. package/dist/Fixture.js.map +1 -1
  26. package/dist/Metadata.d.ts +42 -0
  27. package/dist/Metadata.d.ts.map +1 -0
  28. package/dist/Metadata.js +39 -0
  29. package/dist/Metadata.js.map +1 -0
  30. package/dist/PostgresEventStore.d.ts.map +1 -1
  31. package/dist/PostgresEventStore.js +22 -13
  32. package/dist/PostgresEventStore.js.map +1 -1
  33. package/dist/Saga.d.ts +105 -0
  34. package/dist/Saga.d.ts.map +1 -0
  35. package/dist/Saga.js +97 -0
  36. package/dist/Saga.js.map +1 -0
  37. package/dist/SqliteEventStore.d.ts.map +1 -1
  38. package/dist/SqliteEventStore.js +32 -13
  39. package/dist/SqliteEventStore.js.map +1 -1
  40. package/dist/ViewModel.d.ts.map +1 -1
  41. package/dist/ViewModel.js +3 -1
  42. package/dist/ViewModel.js.map +1 -1
  43. package/dist/index.d.ts +4 -0
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +4 -0
  46. package/dist/index.js.map +1 -1
  47. package/package.json +5 -3
  48. package/src/Aggregate.ts +81 -9
  49. package/src/AggregateService.ts +418 -55
  50. package/src/Causation.ts +48 -0
  51. package/src/EventStore.ts +47 -10
  52. package/src/EventVersions.ts +104 -0
  53. package/src/Fixture.ts +92 -7
  54. package/src/Metadata.ts +52 -0
  55. package/src/PostgresEventStore.ts +24 -13
  56. package/src/Saga.ts +176 -0
  57. package/src/SqliteEventStore.ts +43 -13
  58. package/src/ViewModel.ts +3 -1
  59. package/src/index.ts +4 -0
package/README.md CHANGED
@@ -89,6 +89,19 @@ event, several, or `[]` to record nothing. It can use services, fail with typed
89
89
  errors, and may run more than once, so it should only decide. Projections and
90
90
  handlers must not mutate the state, which is kept between commands.
91
91
 
92
+ When an event's schema changes, the stored events keep their old shape. The aggregate
93
+ declares the older shapes and how each becomes the next, and they are upcast as they
94
+ are read:
95
+
96
+ ```ts
97
+ const Todo = Aggregate.make<TodoState>()({
98
+ // ...
99
+ versions: {
100
+ TodoCreated: EventVersions.from(TodoCreatedV1).next(TodoEvent.cases.TodoCreated, (v1) => ({ ...v1, dueDate: null }))
101
+ }
102
+ })
103
+ ```
104
+
92
105
  ## Run commands
93
106
 
94
107
  ```ts
@@ -116,7 +129,18 @@ state and decides again, up to `maxRetries` times (5 by default), then fails wit
116
129
  `ConcurrencyConflict`.
117
130
 
118
131
  The service remembers the state of recent aggregates (`stateCacheSize`, 10,000 by
119
- default), so a command only reads the events it hasn't seen.
132
+ default), so a command only reads the events it hasn't seen. With
133
+ `snapshots: { every, schema, version }` it also saves states through a `KeyValueStore`
134
+ from `effect/persistence`, so a restart replays only what came after the last one.
135
+
136
+ Every event records a `correlationId` and a `causationId`. A command a view model runs
137
+ gets the handled event as its cause, so a chain of reactions can be traced back to the
138
+ request that started it. `Causation.withCausation` sets the ids from outside.
139
+
140
+ Commands can also carry metadata, a JSON object for what the domain doesn't decide on,
141
+ such as the software version or the user who sent them. It is recorded on every event they
142
+ write. `Metadata.layer({ appVersion })` sets it for the whole application and
143
+ `Metadata.withMetadata` adds to it per request.
120
144
 
121
145
  ## Project into view models
122
146
 
@@ -203,6 +227,10 @@ it.effect("rejects deleting twice", () =>
203
227
  library works.
204
228
  - Yielding the chain gives `{ events, state, version, fixture }` for the last
205
229
  command, if you prefer plain assertions.
230
+ - `givenEvents` also takes events in an older schema version, built with
231
+ `Aggregate.historical(Todo, "TodoCreated", 1, { ... })`, to test upcasting.
232
+ - `checkInvariants({ invariant })` runs random command sequences generated from the
233
+ payload schemas and reports the shortest one that breaks the predicate.
206
234
 
207
235
  `it.effect` runs on a test clock stopped at zero, so timestamps need no mocking: an
208
236
  event created by `DateTime.now` has `DateTime.makeUnsafe(0)` until
@@ -292,8 +320,8 @@ store, so `replay` is for rebuilding, not for recovery.
292
320
  point to wire into your own HTTP or RPC layer.
293
321
  - **SQLite, PostgreSQL and memory only.** There are no adapters for MongoDB or MySQL.
294
322
  - **No code generator.** There is no equivalent of `cqrs generate`.
295
- - **No persistent snapshots.** Recent state is only kept in memory, so after a restart
296
- each stream is replayed the first time it is used, at a cost that grows with its
297
- length.
298
- - **No schema migration.** A stored event that no longer decodes fails with
299
- `EventDecodeError`, so evolve event schemas compatibly.
323
+ - **Snapshots are opt-in.** Without `snapshots`, recent state is only kept in memory, so
324
+ after a restart each stream is replayed the first time it is used. A changed state
325
+ needs a new snapshot `version` by hand.
326
+ - **Event upcasts are pure.** Older event shapes declared with `EventVersions` are
327
+ upcast on read, but an upcast can't read a service or fail with its own error.
@@ -5,7 +5,8 @@
5
5
  * An aggregate is plain data. {@link AggregateService} gives it a store to run
6
6
  * against, and `Fixture` runs it in tests.
7
7
  */
8
- import type { DateTime, Effect, Schema } from "effect";
8
+ import { type DateTime, type Effect, Schema } from "effect";
9
+ import * as EventVersions from "./EventVersions.ts";
9
10
  export interface Tagged {
10
11
  readonly _tag: string;
11
12
  }
@@ -25,6 +26,12 @@ export interface EventMeta {
25
26
  readonly version: number;
26
27
  readonly position: number;
27
28
  readonly timestamp: DateTime.Utc;
29
+ /** Shared by everything that follows from one original request, see `Causation`. */
30
+ readonly correlationId: string | null;
31
+ /** What directly caused the command that recorded the event. */
32
+ readonly causationId: string | null;
33
+ /** What the command carried beside its payload, such as the software version, see `Metadata`. */
34
+ readonly metadata: Schema.JsonObject;
28
35
  }
29
36
  export interface CommandContext {
30
37
  readonly aggregateId: string;
@@ -50,19 +57,29 @@ export interface AnyCommand {
50
57
  readonly payload: PayloadSchema;
51
58
  readonly handler: CommandHandler<any, any, any, any, any>;
52
59
  }
53
- export interface Aggregate<Name extends string, State, Events extends EventSchema<any>, Commands extends Record<string, AnyCommand>> {
60
+ /**
61
+ * The older shapes of some events, keyed by tag. Each history has to end in the
62
+ * event's current shape.
63
+ */
64
+ export type Versions<Event extends Tagged> = {
65
+ readonly [Tag in Event["_tag"]]?: EventVersions.Any<Extract<Event, {
66
+ readonly _tag: Tag;
67
+ }>>;
68
+ };
69
+ export interface Aggregate<Name extends string, State, Events extends EventSchema<any>, Commands extends Record<string, AnyCommand>, V extends Versions<Events["Type"]> = {}> {
54
70
  readonly name: Name;
55
71
  readonly events: Events;
56
72
  readonly initial: State;
57
73
  readonly projection: Projection<State, Events["Type"]>;
58
74
  readonly commands: Commands;
75
+ readonly versions: V;
59
76
  /** Returns a new aggregate that also accepts this command. */
60
77
  command<const CommandName extends string, Payload extends PayloadSchema, E = never, R = never>(name: CommandName, options: {
61
78
  readonly payload: Payload;
62
79
  readonly handler: CommandHandler<State, Payload["Type"], Events["Type"], E, R>;
63
- }): Aggregate<Name, State, Events, Commands & Record<CommandName, Command<Payload, State, Events["Type"], E, R>>>;
80
+ }): Aggregate<Name, State, Events, Commands & Record<CommandName, Command<Payload, State, Events["Type"], E, R>>, V>;
64
81
  }
65
- export type Any = Aggregate<string, any, EventSchema<any>, Record<string, AnyCommand>>;
82
+ export type Any = Aggregate<string, any, EventSchema<any>, Record<string, AnyCommand>, any>;
66
83
  export type Name<A extends Any> = A["name"];
67
84
  export type State<A extends Any> = A["initial"];
68
85
  export type Event<A extends Any> = A["events"]["Type"];
@@ -75,12 +92,36 @@ export type Context<A extends Any> = A["commands"][CommandName<A>] extends Comma
75
92
  * The state is given explicitly, `Aggregate.make<State>()({ ... })`, so that the
76
93
  * projection's return values are checked against it rather than widened.
77
94
  */
78
- export declare const make: <State>() => <const Name extends string, Events extends EventSchema<any>>(options: {
95
+ export declare const make: <State>() => <const Name extends string, Events extends EventSchema<any>, const V extends Versions<Events["Type"]> = {}>(options: {
79
96
  readonly name: Name;
80
97
  readonly events: Events;
81
98
  readonly initial: State;
82
99
  readonly projection: Projection<State, Events["Type"]>;
83
- }) => Aggregate<Name, State, Events, {}>;
100
+ /** Older shapes of events already in the store, see `EventVersions`. */
101
+ readonly versions?: V | undefined;
102
+ }) => Aggregate<Name, State, Events, {}, V>;
84
103
  /** Folds one event into the state. */
85
104
  export declare const evolve: <A extends Any>(aggregate: A, state: State<A>, event: Event<A>, meta: EventMeta) => State<A>;
105
+ /** The schema version new events with this tag are written with. */
106
+ export declare const schemaVersion: (aggregate: Any, tag: string) => number;
107
+ /**
108
+ * An event as it was stored in the past, in an older version of its schema.
109
+ * Construct one directly to replay JSON taken from a database.
110
+ */
111
+ export declare class Historical {
112
+ readonly type: string;
113
+ readonly schemaVersion: number;
114
+ readonly payload: Schema.Json;
115
+ constructor(options: {
116
+ readonly type: string;
117
+ readonly schemaVersion: number;
118
+ readonly payload: Schema.Json;
119
+ });
120
+ }
121
+ /**
122
+ * Encodes an event in an older version of its schema, as code from that time
123
+ * would have stored it. The value is checked against that version, so a test
124
+ * can't seed a shape that never existed.
125
+ */
126
+ export declare const historical: <A extends Any, const Tag extends keyof A["versions"] & string, const Version extends number>(aggregate: A, tag: Tag, version: Version, value: EventVersions.SchemaAt<NonNullable<A["versions"][Tag]>, Version>["Type"]) => Historical;
86
127
  //# sourceMappingURL=Aggregate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Aggregate.d.ts","sourceRoot":"","sources":["../src/Aggregate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Aggregate.d.ts","sourceRoot":"","sources":["../src/Aggregate.ts"],"names":[],"mappings":"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"}
package/dist/Aggregate.js CHANGED
@@ -1,3 +1,12 @@
1
+ /**
2
+ * The write side of the domain: a schema of events, a projection that folds them
3
+ * into state, and commands that inspect that state and decide on new events.
4
+ *
5
+ * An aggregate is plain data. {@link AggregateService} gives it a store to run
6
+ * against, and `Fixture` runs it in tests.
7
+ */
8
+ import { Predicate, Schema } from "effect";
9
+ import * as EventVersions from "./EventVersions.js";
1
10
  const build = (definition) => ({
2
11
  ...definition,
3
12
  command: (name, options) => build({
@@ -9,7 +18,42 @@ const build = (definition) => ({
9
18
  * The state is given explicitly, `Aggregate.make<State>()({ ... })`, so that the
10
19
  * projection's return values are checked against it rather than widened.
11
20
  */
12
- export const make = () => (options) => build({ ...options, commands: {} });
21
+ export const make = () => (options) => build({ ...options, versions: options.versions ?? {}, commands: {} });
13
22
  /** Folds one event into the state. */
14
23
  export const evolve = (aggregate, state, event, meta) => aggregate.projection[event._tag](state, event, meta);
24
+ /** The schema version new events with this tag are written with. */
25
+ export const schemaVersion = (aggregate, tag) => EventVersions.current(aggregate.versions[tag]);
26
+ /**
27
+ * An event as it was stored in the past, in an older version of its schema.
28
+ * Construct one directly to replay JSON taken from a database.
29
+ */
30
+ export class Historical {
31
+ type;
32
+ schemaVersion;
33
+ payload;
34
+ constructor(options) {
35
+ this.type = options.type;
36
+ this.schemaVersion = options.schemaVersion;
37
+ this.payload = options.payload;
38
+ }
39
+ }
40
+ /**
41
+ * Encodes an event in an older version of its schema, as code from that time
42
+ * would have stored it. The value is checked against that version, so a test
43
+ * can't seed a shape that never existed.
44
+ */
45
+ export const historical = (aggregate, tag, version, value) => {
46
+ const versions = aggregate.versions[tag];
47
+ const schema = versions?.schemas[version - 1];
48
+ if (schema === undefined) {
49
+ throw new Error(`${aggregate.name} has no version ${version} of ${tag}`);
50
+ }
51
+ const payload = Schema.encodeSync(Schema.toCodecJson(schema))(value);
52
+ return new Historical({
53
+ type: tag,
54
+ schemaVersion: version,
55
+ // Events were always stored with their tag, whatever the schema of the time said.
56
+ payload: Predicate.isObject(payload) ? { ...payload, _tag: tag } : payload
57
+ });
58
+ };
15
59
  //# sourceMappingURL=Aggregate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Aggregate.js","sourceRoot":"","sources":["../src/Aggregate.ts"],"names":[],"mappings":"AAkGA,MAAM,KAAK,GAAG,CAMZ,UAAqH,EAC3E,EAAE,CAAC,CAAC;IAC9C,GAAG,UAAU;IACb,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CACzB,KAAK,CAAC;QACJ,GAAG,UAAU;QACb,QAAQ,EAAE,EAAE,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,EAAS;KAC7D,CAAC;CACL,CAAC,CAAA;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,GAAU,EAAE,CAChC,CAA6D,OAK5D,EAAsC,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAA;AAE7E,sCAAsC;AACtC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAgB,SAAY,EAAE,KAAe,EAAE,KAAe,EAAE,IAAe,EAAY,EAAE,CAChH,SAAS,CAAC,UAA8F,CAAC,KAAK,CAAC,IAAI,CAAE,CACpH,KAAK,EACL,KAAK,EACL,IAAI,CACL,CAAA"}
1
+ {"version":3,"file":"Aggregate.js","sourceRoot":"","sources":["../src/Aggregate.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAA8B,SAAS,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACtE,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAA;AA2GnD,MAAM,KAAK,GAAG,CAOZ,UAGC,EAC4C,EAAE,CAAC,CAAC;IACjD,GAAG,UAAU;IACb,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CACzB,KAAK,CAAC;QACJ,GAAG,UAAU;QACb,QAAQ,EAAE,EAAE,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,EAAS;KAC7D,CAAC;CACL,CAAC,CAAA;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,GAAU,EAAE,CAChC,CAA4G,OAO3G,EAAyC,EAAE,CAC1C,KAAK,CAAC,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAK,EAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAA;AAE9E,sCAAsC;AACtC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAgB,SAAY,EAAE,KAAe,EAAE,KAAe,EAAE,IAAe,EAAY,EAAE,CAChH,SAAS,CAAC,UAA8F,CAAC,KAAK,CAAC,IAAI,CAAE,CACpH,KAAK,EACL,KAAK,EACL,IAAI,CACL,CAAA;AAEH,oEAAoE;AACpE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,SAAc,EAAE,GAAW,EAAU,EAAE,CACnE,aAAa,CAAC,OAAO,CAAE,SAAS,CAAC,QAA0D,CAAC,GAAG,CAAC,CAAC,CAAA;AAEnG;;;GAGG;AACH,MAAM,OAAO,UAAU;IACZ,IAAI,CAAQ;IACZ,aAAa,CAAQ;IACrB,OAAO,CAAa;IAC7B,YAAY,OAAiG;QAC3G,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAA;QACxB,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,CAAA;QAC1C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAA;IAChC,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAKxB,SAAY,EACZ,GAAQ,EACR,OAAgB,EAChB,KAA+E,EACnE,EAAE;IACd,MAAM,QAAQ,GAAI,SAAS,CAAC,QAA0D,CAAC,GAAG,CAAC,CAAA;IAC3F,MAAM,MAAM,GAAG,QAAQ,EAAE,OAAO,CAAC,OAAO,GAAG,CAAC,CAAC,CAAA;IAC7C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,GAAG,SAAS,CAAC,IAAI,mBAAmB,OAAO,OAAO,GAAG,EAAE,CAAC,CAAA;IAC1E,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAgB,CAAA;IACnF,OAAO,IAAI,UAAU,CAAC;QACpB,IAAI,EAAE,GAAG;QACT,aAAa,EAAE,OAAO;QACtB,kFAAkF;QAClF,OAAO,EAAE,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,GAAI,OAAkB,EAAE,IAAI,EAAE,GAAG,EAAiB,CAAC,CAAC,CAAC,OAAO;KACtG,CAAC,CAAA;AACJ,CAAC,CAAA"}
@@ -2,20 +2,22 @@
2
2
  * Runs an aggregate against the {@link EventStore}: the `command`, `read-model`
3
3
  * and `history` actions of moleculer-cqrs, as a typed service.
4
4
  */
5
- import { type DateTime, Effect, Schema } from "effect";
5
+ import { Cause, type DateTime, Effect, Schema, type Scope } from "effect";
6
+ import { KeyValueStore } from "effect/persistence";
6
7
  import * as Aggregate from "./Aggregate.ts";
7
8
  import { ConcurrencyConflict, EventStore, type EventStoreError, type StoredEvent } from "./EventStore.ts";
9
+ import { Metadata } from "./Metadata.ts";
8
10
  declare const UnknownCommand_base: Schema.Class<UnknownCommand, Schema.TaggedStruct<"UnknownCommand", {
9
11
  readonly aggregateName: Schema.String;
10
12
  readonly type: Schema.String;
11
- }>, import("effect/Cause").YieldableError>;
13
+ }>, Cause.YieldableError>;
12
14
  export declare class UnknownCommand extends UnknownCommand_base {
13
15
  }
14
16
  declare const InvalidCommand_base: Schema.Class<InvalidCommand, Schema.TaggedStruct<"InvalidCommand", {
15
17
  readonly aggregateName: Schema.String;
16
18
  readonly type: Schema.String;
17
19
  readonly message: Schema.String;
18
- }>, import("effect/Cause").YieldableError>;
20
+ }>, Cause.YieldableError>;
19
21
  export declare class InvalidCommand extends InvalidCommand_base {
20
22
  }
21
23
  declare const EventDecodeError_base: Schema.Class<EventDecodeError, Schema.TaggedStruct<"EventDecodeError", {
@@ -23,9 +25,13 @@ declare const EventDecodeError_base: Schema.Class<EventDecodeError, Schema.Tagge
23
25
  readonly aggregateId: Schema.String;
24
26
  readonly version: Schema.Int;
25
27
  readonly type: Schema.String;
28
+ readonly schemaVersion: Schema.Int;
26
29
  readonly message: Schema.String;
27
- }>, import("effect/Cause").YieldableError>;
28
- /** A stored event no longer matches the schema, which means the data needs a migration. */
30
+ }>, Cause.YieldableError>;
31
+ /**
32
+ * A stored event doesn't match the schema of its version, or was written in a
33
+ * version the aggregate doesn't declare. Old shapes are declared with `EventVersions`.
34
+ */
29
35
  export declare class EventDecodeError extends EventDecodeError_base {
30
36
  }
31
37
  export type ReadError = EventStoreError | EventDecodeError;
@@ -39,11 +45,16 @@ export interface CommandResult<Event> {
39
45
  /** The store position of the last event, to pass to `ViewModels.caughtUp`. */
40
46
  readonly position: number;
41
47
  readonly events: ReadonlyArray<Event>;
48
+ /** Recorded on the events, see `Causation`. */
49
+ readonly correlationId: string;
42
50
  }
43
51
  export interface HistoryEntry<Event> {
44
52
  readonly version: number;
45
53
  readonly timestamp: DateTime.Utc;
46
54
  readonly type: string;
55
+ readonly correlationId: string | null;
56
+ readonly causationId: string | null;
57
+ readonly metadata: Metadata;
47
58
  readonly payload?: Event;
48
59
  }
49
60
  export interface AggregateService<A extends Aggregate.Any> {
@@ -65,18 +76,79 @@ export interface AggregateService<A extends Aggregate.Any> {
65
76
  readonly finishTime?: DateTime.Utc | undefined;
66
77
  }) => Effect.Effect<ReadonlyArray<HistoryEntry<Aggregate.Event<A>>>, ReadError>;
67
78
  }
68
- /** Decodes a stored event with the schema of the aggregate it belongs to. */
79
+ /**
80
+ * Decodes a stored event with the schema of the aggregate it belongs to. An
81
+ * event stored in an older version is upcast to the current one on the way.
82
+ */
69
83
  export declare const makeEventDecoder: <A extends Aggregate.Any>(aggregate: A) => (stored: StoredEvent) => Effect.Effect<Aggregate.Event<A>, EventDecodeError>;
70
- /** Encodes events into the JSON form the store keeps. */
84
+ /** Encodes events into the JSON form the store keeps, in the current version of their schema. */
71
85
  export declare const makeEventEncoder: <A extends Aggregate.Any>(aggregate: A) => (event: Aggregate.Event<A>) => Effect.Effect<{
72
86
  type: any;
73
87
  payload: Schema.Json;
88
+ schemaVersion: number;
74
89
  }, never, never>;
75
- export declare const make: <A extends Aggregate.Any>(aggregate: A, options?: {
90
+ /** Saves the state of each aggregate every so often, so a cold start replays only what came after. */
91
+ export interface SnapshotOptions<State> {
92
+ /** How many events to fold after a snapshot before saving the next one. */
93
+ readonly every: number;
94
+ /** How the state is stored. It is encoded as JSON. */
95
+ readonly schema: Schema.Codec<State, any, never, never>;
96
+ /**
97
+ * Part of every key. Change it whenever the state or the projection changes,
98
+ * so that snapshots of the old state are ignored and rebuilt from the log.
99
+ * Defaults to `1`.
100
+ */
101
+ readonly version?: string | number | undefined;
102
+ }
103
+ export interface Options {
76
104
  /** How many times a command is re-decided after losing a race. Defaults to 5. */
77
- readonly maxRetries?: number;
105
+ readonly maxRetries?: number | undefined;
78
106
  /** How many aggregates keep their state in memory between commands. Defaults to 10,000. */
79
- readonly stateCacheSize?: number;
80
- } | undefined) => Effect.Effect<AggregateService<A>, never, EventStore | Aggregate.Context<A>>;
107
+ readonly stateCacheSize?: number | undefined;
108
+ }
109
+ /**
110
+ * The names of the metrics every aggregate service records through Effect's
111
+ * `Metric` module. Each series carries an `aggregate` attribute with the
112
+ * aggregate's name. Read them with `Metric.snapshot`, or send them on with an
113
+ * exporter such as `OtlpMetrics` from `effect/observability`.
114
+ */
115
+ export declare const MetricNames: {
116
+ /**
117
+ * Timer: how long a command took, including its wait for an earlier command on
118
+ * the same stream, by `command` and `outcome`. The outcome is `success`, the tag
119
+ * of the error, `defect` or `interrupted`. A payload that doesn't decode, or a
120
+ * type the aggregate doesn't know, fails before this point and isn't recorded.
121
+ */
122
+ readonly commandDuration: "cqrs_command_duration";
123
+ /**
124
+ * Counter: where loading the current state found a state to start from, by
125
+ * `source`: `memory`, `snapshot`, or `replay` when it starts from the first event.
126
+ */
127
+ readonly stateLoads: "cqrs_state_loads_total";
128
+ /** Histogram: how many events a load read from the store on top of that state. */
129
+ readonly eventsReplayed: "cqrs_events_replayed";
130
+ /** Gauge: how many states are remembered in memory. */
131
+ readonly stateCacheSize: "cqrs_state_cache_size";
132
+ /** Counter: states dropped from memory to make room for others, see `stateCacheSize`. */
133
+ readonly stateCacheEvictions: "cqrs_state_cache_evictions_total";
134
+ /** Counter: snapshots saved, by `result`: `success` or `failure`. */
135
+ readonly snapshotSaves: "cqrs_snapshot_saves_total";
136
+ /** Counter: snapshots that couldn't be read, so the stream was replayed instead. */
137
+ readonly snapshotReadFailures: "cqrs_snapshot_read_failures_total";
138
+ /** Counter: appends that lost a race with a writer in another process. Each is retried until `maxRetries` runs out. */
139
+ readonly concurrencyConflicts: "cqrs_concurrency_conflicts_total";
140
+ };
141
+ /**
142
+ * Builds the service for one aggregate. With `snapshots` it saves states through
143
+ * a `KeyValueStore` from `effect/persistence`, which has layers for memory, files,
144
+ * SQL and the browser's `localStorage`. Saves run in the background, and closing
145
+ * the scope waits for the ones still running.
146
+ */
147
+ export declare const make: {
148
+ <A extends Aggregate.Any>(aggregate: A, options: Options & {
149
+ readonly snapshots: SnapshotOptions<Aggregate.State<A>>;
150
+ }): Effect.Effect<AggregateService<A>, never, EventStore | KeyValueStore.KeyValueStore | Scope.Scope | Aggregate.Context<A>>;
151
+ <A extends Aggregate.Any>(aggregate: A, options?: Options): Effect.Effect<AggregateService<A>, never, EventStore | Aggregate.Context<A>>;
152
+ };
81
153
  export {};
82
154
  //# sourceMappingURL=AggregateService.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AggregateService.d.ts","sourceRoot":"","sources":["../src/AggregateService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AggregateService.d.ts","sourceRoot":"","sources":["../src/AggregateService.ts"],"names":[],"mappings":"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"}