@hexaijs/core 0.4.0 → 0.5.1

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 (74) hide show
  1. package/README.md +79 -0
  2. package/dist/{message.d.ts → event-store-DQXtakLF.d.ts} +28 -9
  3. package/dist/index.d.ts +67 -5
  4. package/dist/index.js +212 -19
  5. package/dist/index.js.map +1 -1
  6. package/dist/test/index.d.ts +38 -7
  7. package/dist/test/index.js +314 -42
  8. package/dist/test/index.js.map +1 -1
  9. package/package.json +6 -7
  10. package/dist/config.d.ts +0 -2
  11. package/dist/config.d.ts.map +0 -1
  12. package/dist/config.js +0 -5
  13. package/dist/config.js.map +0 -1
  14. package/dist/domain/aggregate-root.d.ts +0 -11
  15. package/dist/domain/aggregate-root.d.ts.map +0 -1
  16. package/dist/domain/aggregate-root.js +0 -21
  17. package/dist/domain/aggregate-root.js.map +0 -1
  18. package/dist/domain/domain-error.d.ts +0 -11
  19. package/dist/domain/domain-error.d.ts.map +0 -1
  20. package/dist/domain/domain-error.js +0 -25
  21. package/dist/domain/domain-error.js.map +0 -1
  22. package/dist/domain/domain-event.d.ts +0 -5
  23. package/dist/domain/domain-event.d.ts.map +0 -1
  24. package/dist/domain/domain-event.js +0 -11
  25. package/dist/domain/domain-event.js.map +0 -1
  26. package/dist/domain/identifiable.d.ts +0 -11
  27. package/dist/domain/identifiable.d.ts.map +0 -1
  28. package/dist/domain/identifiable.js +0 -18
  29. package/dist/domain/identifiable.js.map +0 -1
  30. package/dist/domain/index.d.ts +0 -6
  31. package/dist/domain/index.d.ts.map +0 -1
  32. package/dist/domain/index.js +0 -22
  33. package/dist/domain/index.js.map +0 -1
  34. package/dist/domain/repository.d.ts +0 -16
  35. package/dist/domain/repository.d.ts.map +0 -1
  36. package/dist/domain/repository.js +0 -25
  37. package/dist/domain/repository.js.map +0 -1
  38. package/dist/event-store.d.ts +0 -13
  39. package/dist/event-store.d.ts.map +0 -1
  40. package/dist/event-store.js +0 -3
  41. package/dist/event-store.js.map +0 -1
  42. package/dist/index.d.ts.map +0 -1
  43. package/dist/message.d.ts.map +0 -1
  44. package/dist/message.js +0 -120
  45. package/dist/message.js.map +0 -1
  46. package/dist/test/dummy-message.d.ts +0 -8
  47. package/dist/test/dummy-message.d.ts.map +0 -1
  48. package/dist/test/dummy-message.js +0 -22
  49. package/dist/test/dummy-message.js.map +0 -1
  50. package/dist/test/expect.d.ts +0 -3
  51. package/dist/test/expect.d.ts.map +0 -1
  52. package/dist/test/expect.js +0 -13
  53. package/dist/test/expect.js.map +0 -1
  54. package/dist/test/in-memory-event-store.d.ts +0 -11
  55. package/dist/test/in-memory-event-store.d.ts.map +0 -1
  56. package/dist/test/in-memory-event-store.js +0 -38
  57. package/dist/test/in-memory-event-store.js.map +0 -1
  58. package/dist/test/index.d.ts.map +0 -1
  59. package/dist/test/matchers.d.ts +0 -5
  60. package/dist/test/matchers.d.ts.map +0 -1
  61. package/dist/test/matchers.js +0 -77
  62. package/dist/test/matchers.js.map +0 -1
  63. package/dist/test/partial-match.d.ts +0 -4
  64. package/dist/test/partial-match.d.ts.map +0 -1
  65. package/dist/test/partial-match.js +0 -33
  66. package/dist/test/partial-match.js.map +0 -1
  67. package/dist/test/utils.d.ts +0 -5
  68. package/dist/test/utils.d.ts.map +0 -1
  69. package/dist/test/utils.js +0 -25
  70. package/dist/test/utils.js.map +0 -1
  71. package/dist/unit-of-work.d.ts +0 -13
  72. package/dist/unit-of-work.d.ts.map +0 -1
  73. package/dist/unit-of-work.js +0 -10
  74. package/dist/unit-of-work.js.map +0 -1
package/README.md CHANGED
@@ -51,6 +51,84 @@ command.getPayload(); // the typed payload object
51
51
 
52
52
  Every message automatically receives headers including a unique ID and timestamp. The `type` static property follows the convention `"bounded-context.message-name"`.
53
53
 
54
+ #### MessageOptions
55
+
56
+ The constructor accepts an optional `MessageOptions` object for passing custom headers:
57
+
58
+ ```typescript
59
+ interface MessageOptions {
60
+ headers?: Record<string, unknown>;
61
+ }
62
+
63
+ // Pass custom headers
64
+ const command = new CreateOrderCommand(
65
+ { customerId: "customer-123", items: [] },
66
+ { headers: { correlationId: "corr-abc" } }
67
+ );
68
+ ```
69
+
70
+ #### Serialization
71
+
72
+ Messages provide two serialization methods:
73
+
74
+ ```typescript
75
+ // toJSON() - preserves Date objects, suitable for structured output
76
+ const json = command.toJSON();
77
+ // { headers: { id, type, createdAt: Date, ... }, payload: { ... } }
78
+
79
+ // serialize() - fully serialized plain object (dates become strings)
80
+ const plain = command.serialize();
81
+ // { headers: { id, type, createdAt: "2026-...", ... }, payload: { ... } }
82
+
83
+ // JSON.stringify uses toJSON() automatically
84
+ JSON.stringify(command);
85
+ ```
86
+
87
+ Override `serializePayload()` to customize how the payload is serialized:
88
+
89
+ ```typescript
90
+ class MyEvent extends DomainEvent<{ date: Temporal.PlainDate }> {
91
+ protected serializePayload(payload: { date: Temporal.PlainDate }) {
92
+ return { date: payload.date.toString() };
93
+ }
94
+ }
95
+ ```
96
+
97
+ #### Deserialization
98
+
99
+ Use the static `from()` method to reconstruct a message from serialized data:
100
+
101
+ ```typescript
102
+ const raw = { customerId: "c-123", items: [] };
103
+ const headers = { id: "msg-1", type: "order.create-order", createdAt: "2026-01-01T00:00:00Z" };
104
+
105
+ const command = CreateOrderCommand.from(raw, headers);
106
+ ```
107
+
108
+ Override `deserializeRawPayload()` for custom deserialization:
109
+
110
+ ```typescript
111
+ class MyEvent extends DomainEvent<{ date: Temporal.PlainDate }> {
112
+ protected static deserializeRawPayload(raw: any) {
113
+ return { date: Temporal.PlainDate.from(raw.date) };
114
+ }
115
+ }
116
+ ```
117
+
118
+ #### Fluent Header API
119
+
120
+ Use `withHeader()` to create a new message instance with an additional header:
121
+
122
+ ```typescript
123
+ const command = new CreateOrderCommand({ customerId: "c-123", items: [] })
124
+ .withHeader("correlationId", "corr-abc")
125
+ .withHeader("source", "api-gateway");
126
+
127
+ command.getHeader("correlationId"); // "corr-abc"
128
+ ```
129
+
130
+ `withHeader()` returns a new immutable instance - the original message is not modified.
131
+
54
132
  ### DomainEvent
55
133
 
56
134
  `DomainEvent` extends `Message` for events that represent something that happened in your domain.
@@ -257,6 +335,7 @@ throw new DuplicateObjectError("Order with this ID already exists");
257
335
  | Export | Description |
258
336
  |--------|-------------|
259
337
  | `Message<P>` | Base message class with headers and typed payload |
338
+ | `MessageOptions` | Options for Message constructor (`{ headers? }`) |
260
339
  | `DomainEvent<P>` | Message subclass for domain events |
261
340
  | `AggregateRoot<T>` | Base class for aggregates with event collection |
262
341
  | `Id<T>` | Value object for typed identities |
@@ -1,5 +1,5 @@
1
1
  type Version = string | number | undefined;
2
- export interface MessageHeaders {
2
+ interface MessageHeaders {
3
3
  id: string;
4
4
  type: string;
5
5
  intent?: string;
@@ -11,7 +11,10 @@ type ExtraHeaderField = Exclude<keyof MessageHeaders, "id" | "type" | "intent" |
11
11
  type RawMessageHeaders = Omit<MessageHeaders, "createdAt"> & {
12
12
  createdAt: string | Date;
13
13
  };
14
- export declare class Message<Payload = any> {
14
+ interface MessageOptions {
15
+ headers?: Record<string, unknown>;
16
+ }
17
+ declare class Message<Payload = any> {
15
18
  protected readonly payload: Payload;
16
19
  protected headers: MessageHeaders;
17
20
  static getSchemaVersion(): Version;
@@ -21,10 +24,11 @@ export declare class Message<Payload = any> {
21
24
  static from(rawPayload: Record<string, unknown>, headers?: RawMessageHeaders): Message;
22
25
  protected static deserializeRawPayload(rawPayload: any): any;
23
26
  protected static deserializeRawHeaders(headers: RawMessageHeaders): MessageHeaders;
24
- constructor(payload: Payload, headers?: Record<string, unknown>);
27
+ constructor(payload: Payload, options?: MessageOptions);
25
28
  protected static mergeHeaders(headers: Record<string, unknown>): MessageHeaders;
26
29
  withHeader(field: ExtraHeaderField, value: unknown): this;
27
30
  protected clone(): this;
31
+ protected cloneWithHeaders(headers: Record<string, unknown>): this;
28
32
  getHeader<T = string>(field: string): T | undefined;
29
33
  getHeaders(): MessageHeaders;
30
34
  getPayload(): Payload;
@@ -33,22 +37,37 @@ export declare class Message<Payload = any> {
33
37
  getSchemaVersion(): Version | undefined;
34
38
  getTimestamp(): Date;
35
39
  getIntent(): string | undefined;
40
+ toJSON(): {
41
+ headers: MessageHeaders;
42
+ payload: unknown;
43
+ };
36
44
  serialize(): {
37
45
  headers: MessageHeaders;
38
46
  payload: Record<string, unknown>;
39
47
  };
40
- private doSerialize;
41
48
  protected serializePayload(payload: Payload): unknown;
42
49
  asType<M extends MessageClass>(cls: M): InstanceType<M>;
43
50
  }
44
- export type AnyMessage = Message;
45
- export type MessageClass<T extends Message = Message> = {
51
+ type AnyMessage = Message;
52
+ type MessageClass<T extends Message = Message> = {
46
53
  getSchemaVersion(): Version;
47
54
  getType(): string;
48
55
  getIntent(): string | undefined;
49
56
  from: (rawPayload: any, header?: MessageHeaders) => T;
50
57
  new (...args: any[]): T;
51
58
  };
52
- export type PayloadOf<M> = M extends Message<infer P> ? P : never;
53
- export {};
54
- //# sourceMappingURL=message.d.ts.map
59
+ type PayloadOf<M> = M extends Message<infer P> ? P : never;
60
+
61
+ interface StoredEvent {
62
+ position: number;
63
+ event: Message;
64
+ }
65
+ interface EventStoreFetchResult {
66
+ events: StoredEvent[];
67
+ lastPosition: number;
68
+ }
69
+ interface EventStore {
70
+ fetch(afterPosition: number, limit?: number): Promise<EventStoreFetchResult>;
71
+ }
72
+
73
+ export { type AnyMessage as A, type EventStore as E, Message as M, type PayloadOf as P, type StoredEvent as S, type EventStoreFetchResult as a, type MessageClass as b, type MessageHeaders as c, type MessageOptions as d };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,67 @@
1
- export * from "./domain";
2
- export * from "./unit-of-work";
3
- export * from "./message";
4
- export * from "./event-store";
5
- //# sourceMappingURL=index.d.ts.map
1
+ import { M as Message } from './event-store-DQXtakLF.js';
2
+ export { A as AnyMessage, E as EventStore, a as EventStoreFetchResult, b as MessageClass, c as MessageHeaders, d as MessageOptions, P as PayloadOf, S as StoredEvent } from './event-store-DQXtakLF.js';
3
+
4
+ declare class DomainEvent<P extends Record<string, any> = Record<string, unknown>> extends Message<P> {
5
+ static getIntent(): string;
6
+ }
7
+
8
+ declare class Id<T extends string | number> {
9
+ private readonly value;
10
+ constructor(value: T);
11
+ getValue(): T;
12
+ equals(other: Id<T>): boolean;
13
+ }
14
+ type IdOf<T> = T extends Identifiable<infer Id> ? Id : never;
15
+ interface Identifiable<T extends Id<string | number> = Id<string>> {
16
+ getId(): T;
17
+ }
18
+
19
+ declare class AggregateRoot<T extends Id<string | number>> implements Identifiable<T> {
20
+ protected readonly id: T;
21
+ protected events: DomainEvent[];
22
+ constructor(id: T);
23
+ getId(): T;
24
+ protected raise(event: DomainEvent): void;
25
+ getEventsOccurred(): DomainEvent[];
26
+ }
27
+
28
+ declare class DomainError extends Error {
29
+ }
30
+ declare class InvariantNotSatisfiedError extends DomainError {
31
+ readonly code: string;
32
+ constructor(code: string, message?: string);
33
+ }
34
+ declare class ValidationError extends InvariantNotSatisfiedError {
35
+ readonly field: string;
36
+ constructor(field: string, code: string, message?: string);
37
+ }
38
+
39
+ interface Repository<T extends Identifiable<any>> {
40
+ get(id: IdOf<T>): Promise<T>;
41
+ add(entity: T): Promise<void>;
42
+ update(entity: T): Promise<void>;
43
+ }
44
+ declare class RepositoryError extends Error {
45
+ constructor(message: string);
46
+ }
47
+ declare class DuplicateObjectError extends RepositoryError {
48
+ constructor(message: string);
49
+ }
50
+ declare class ObjectNotFoundError extends RepositoryError {
51
+ constructor(message: string);
52
+ }
53
+
54
+ declare enum Propagation {
55
+ NEW = "new",
56
+ EXISTING = "existing",
57
+ NESTED = "nested"
58
+ }
59
+ interface BaseUnitOfWorkOptions {
60
+ propagation: Propagation;
61
+ }
62
+ interface UnitOfWork<Client = unknown, Options extends BaseUnitOfWorkOptions = BaseUnitOfWorkOptions> {
63
+ getClient(): Client;
64
+ wrap<T>(fn: (client: Client) => Promise<T>, options?: Partial<Options>): Promise<T>;
65
+ }
66
+
67
+ export { AggregateRoot, type BaseUnitOfWorkOptions, DomainError, DomainEvent, DuplicateObjectError, Id, type IdOf, type Identifiable, InvariantNotSatisfiedError, Message, ObjectNotFoundError, Propagation, type Repository, RepositoryError, type UnitOfWork, ValidationError };
package/dist/index.js CHANGED
@@ -1,21 +1,214 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
1
+ import { v4 } from 'uuid';
2
+
3
+ // src/domain/aggregate-root.ts
4
+ var AggregateRoot = class {
5
+ constructor(id) {
6
+ this.id = id;
7
+ }
8
+ events = [];
9
+ getId() {
10
+ return this.id;
11
+ }
12
+ raise(event) {
13
+ this.events.push(event);
14
+ }
15
+ getEventsOccurred() {
16
+ return [...this.events];
17
+ }
18
+ };
19
+
20
+ // src/domain/domain-error.ts
21
+ var DomainError = class extends Error {
22
+ };
23
+ var InvariantNotSatisfiedError = class extends DomainError {
24
+ constructor(code, message = "") {
25
+ super(message);
26
+ this.code = code;
27
+ this.name = "InvariantNotSatisfiedError";
28
+ }
29
+ };
30
+ var ValidationError = class extends InvariantNotSatisfiedError {
31
+ constructor(field, code, message = "") {
32
+ super(code, message);
33
+ this.field = field;
34
+ this.name = "ValidationError";
35
+ }
36
+ };
37
+ var Message = class {
38
+ constructor(payload, options) {
39
+ this.payload = payload;
40
+ this.headers = Object.freeze(
41
+ this.constructor.mergeHeaders(options?.headers ?? {})
42
+ );
43
+ if (payload && typeof payload === "object") {
44
+ Object.freeze(payload);
45
+ }
46
+ }
47
+ headers;
48
+ static getSchemaVersion() {
49
+ return this.schemaVersion ?? void 0;
50
+ }
51
+ static getType() {
52
+ return this.type ?? this.name;
53
+ }
54
+ static getIntent() {
55
+ return this.intent ?? void 0;
56
+ }
57
+ static newHeaders(...excludes) {
58
+ return generateHeaderFor(this, ...excludes);
59
+ }
60
+ static from(rawPayload, headers) {
61
+ const payload = this.deserializeRawPayload(rawPayload);
62
+ return new this(payload, {
63
+ headers: headers ? this.deserializeRawHeaders(headers) : this.newHeaders()
64
+ });
65
+ }
66
+ static deserializeRawPayload(rawPayload) {
67
+ return rawPayload;
68
+ }
69
+ static deserializeRawHeaders(headers) {
70
+ headers.createdAt = new Date(headers.createdAt);
71
+ return headers;
72
+ }
73
+ static mergeHeaders(headers) {
74
+ return {
75
+ ...this.newHeaders(...Object.keys(headers)),
76
+ ...headers
77
+ };
78
+ }
79
+ withHeader(field, value) {
80
+ const newHeaders = { ...this.headers, [field]: value };
81
+ return this.cloneWithHeaders(newHeaders);
82
+ }
83
+ clone() {
84
+ const cloned = Object.create(Object.getPrototypeOf(this));
85
+ Object.assign(cloned, this);
86
+ return cloned;
87
+ }
88
+ cloneWithHeaders(headers) {
89
+ const cloned = this.clone();
90
+ Object.defineProperty(cloned, "headers", {
91
+ value: Object.freeze(headers),
92
+ writable: false,
93
+ configurable: true
94
+ });
95
+ return cloned;
96
+ }
97
+ getHeader(field) {
98
+ return this.headers[field];
99
+ }
100
+ getHeaders() {
101
+ return Object.freeze({ ...this.headers });
102
+ }
103
+ getPayload() {
104
+ return this.payload;
105
+ }
106
+ getMessageId() {
107
+ return this.headers.id;
108
+ }
109
+ getMessageType() {
110
+ return this.headers.type;
111
+ }
112
+ getSchemaVersion() {
113
+ return this.headers.schemaVersion;
114
+ }
115
+ getTimestamp() {
116
+ return this.headers.createdAt;
117
+ }
118
+ getIntent() {
119
+ return this.constructor.getIntent();
120
+ }
121
+ toJSON() {
122
+ return {
123
+ headers: { ...this.headers },
124
+ payload: this.serializePayload(this.payload)
125
+ };
126
+ }
127
+ serialize() {
128
+ return JSON.parse(JSON.stringify(this.toJSON()));
129
+ }
130
+ serializePayload(payload) {
131
+ return payload;
132
+ }
133
+ asType(cls) {
134
+ const { headers, payload } = this.serialize();
135
+ return cls.from(payload, headers);
136
+ }
137
+ };
138
+ function generateHeaderFor(cls, ...excludes) {
139
+ const headers = {};
140
+ if (!excludes.includes("id")) {
141
+ headers.id = v4();
142
+ }
143
+ if (!excludes.includes("type")) {
144
+ headers.type = cls.getType();
145
+ }
146
+ if (!excludes.includes("intent")) {
147
+ const intent = cls.getIntent();
148
+ if (intent !== void 0) {
149
+ headers.intent = intent;
7
150
  }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./domain"), exports);
18
- __exportStar(require("./unit-of-work"), exports);
19
- __exportStar(require("./message"), exports);
20
- __exportStar(require("./event-store"), exports);
151
+ }
152
+ if (!excludes.includes("schemaVersion")) {
153
+ const schemaVersion = cls.getSchemaVersion();
154
+ if (schemaVersion !== void 0) {
155
+ headers.schemaVersion = schemaVersion;
156
+ }
157
+ }
158
+ if (!excludes.includes("createdAt")) {
159
+ headers.createdAt = /* @__PURE__ */ new Date();
160
+ }
161
+ return headers;
162
+ }
163
+
164
+ // src/domain/domain-event.ts
165
+ var DomainEvent = class extends Message {
166
+ static getIntent() {
167
+ return "event";
168
+ }
169
+ };
170
+
171
+ // src/domain/identifiable.ts
172
+ var Id = class {
173
+ constructor(value) {
174
+ this.value = value;
175
+ }
176
+ getValue() {
177
+ return this.value;
178
+ }
179
+ equals(other) {
180
+ return this.constructor === other.constructor && this.getValue() === other.getValue();
181
+ }
182
+ };
183
+
184
+ // src/domain/repository.ts
185
+ var RepositoryError = class extends Error {
186
+ constructor(message) {
187
+ super(message);
188
+ this.name = "RepositoryError";
189
+ }
190
+ };
191
+ var DuplicateObjectError = class extends RepositoryError {
192
+ constructor(message) {
193
+ super(message);
194
+ this.name = "DuplicateObjectError";
195
+ }
196
+ };
197
+ var ObjectNotFoundError = class extends RepositoryError {
198
+ constructor(message) {
199
+ super(message);
200
+ this.name = "ObjectNotFoundError";
201
+ }
202
+ };
203
+
204
+ // src/unit-of-work.ts
205
+ var Propagation = /* @__PURE__ */ ((Propagation2) => {
206
+ Propagation2["NEW"] = "new";
207
+ Propagation2["EXISTING"] = "existing";
208
+ Propagation2["NESTED"] = "nested";
209
+ return Propagation2;
210
+ })(Propagation || {});
211
+
212
+ export { AggregateRoot, DomainError, DomainEvent, DuplicateObjectError, Id, InvariantNotSatisfiedError, Message, ObjectNotFoundError, Propagation, RepositoryError, ValidationError };
213
+ //# sourceMappingURL=index.js.map
21
214
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,iDAA+B;AAC/B,4CAA0B;AAC1B,gDAA8B"}
1
+ {"version":3,"sources":["../src/domain/aggregate-root.ts","../src/domain/domain-error.ts","../src/message.ts","../src/domain/domain-event.ts","../src/domain/identifiable.ts","../src/domain/repository.ts","../src/unit-of-work.ts"],"names":["uuid","Propagation"],"mappings":"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","file":"index.js","sourcesContent":["import { DomainEvent } from \"./domain-event\";\nimport { Id, Identifiable } from \"./identifiable\";\n\nexport class AggregateRoot<T extends Id<string | number>>\n implements Identifiable<T>\n{\n protected events: DomainEvent[] = [];\n\n constructor(protected readonly id: T) {}\n\n public getId(): T {\n return this.id;\n }\n\n protected raise(event: DomainEvent): void {\n this.events.push(event);\n }\n\n public getEventsOccurred(): DomainEvent[] {\n return [...this.events];\n }\n}\n","export class DomainError extends Error {}\n\nexport class InvariantNotSatisfiedError extends DomainError {\n constructor(\n public readonly code: string,\n message: string = \"\"\n ) {\n super(message);\n this.name = \"InvariantNotSatisfiedError\";\n }\n}\n\nexport class ValidationError extends InvariantNotSatisfiedError {\n constructor(\n public readonly field: string,\n code: string,\n message: string = \"\"\n ) {\n super(code, message);\n\n this.name = \"ValidationError\";\n }\n}\n","import { v4 as uuid } from \"uuid\";\n\ntype Version = string | number | undefined;\n\nexport interface MessageHeaders {\n id: string;\n type: string;\n intent?: string;\n schemaVersion?: Version;\n createdAt: Date;\n\n [key: string]: unknown;\n}\n\ntype ExtraHeaderField = Exclude<\n keyof MessageHeaders,\n \"id\" | \"type\" | \"intent\" | \"schemaVersion\" | \"createdAt\"\n>;\n\ntype RawMessageHeaders = Omit<MessageHeaders, \"createdAt\"> & {\n createdAt: string | Date;\n};\n\nexport interface MessageOptions {\n headers?: Record<string, unknown>;\n}\n\nexport class Message<Payload = any> {\n protected headers!: MessageHeaders;\n\n public static getSchemaVersion(): Version {\n return (this as any).schemaVersion ?? undefined;\n }\n\n public static getType(): string {\n return (this as any).type ?? this.name;\n }\n\n public static getIntent(): string | undefined {\n return (this as any).intent ?? undefined;\n }\n\n protected static newHeaders(...excludes: string[]): MessageHeaders {\n return generateHeaderFor(this as any, ...excludes);\n }\n\n public static from(\n rawPayload: Record<string, unknown>,\n headers?: RawMessageHeaders\n ): Message {\n const payload = this.deserializeRawPayload(rawPayload);\n return new this(payload, {\n headers: headers\n ? this.deserializeRawHeaders(headers)\n : this.newHeaders(),\n });\n }\n\n protected static deserializeRawPayload(rawPayload: any): any {\n return rawPayload;\n }\n\n protected static deserializeRawHeaders(\n headers: RawMessageHeaders\n ): MessageHeaders {\n headers.createdAt = new Date(headers.createdAt);\n\n return headers as MessageHeaders;\n }\n\n constructor(\n protected readonly payload: Payload,\n options?: MessageOptions\n ) {\n this.headers = Object.freeze(\n (this.constructor as any).mergeHeaders(options?.headers ?? {})\n );\n\n if (payload && typeof payload === \"object\") {\n Object.freeze(payload);\n }\n }\n\n protected static mergeHeaders(\n headers: Record<string, unknown>\n ): MessageHeaders {\n return {\n ...this.newHeaders(...Object.keys(headers)),\n ...headers,\n };\n }\n\n public withHeader(field: ExtraHeaderField, value: unknown): this {\n const newHeaders = { ...this.headers, [field]: value };\n return this.cloneWithHeaders(newHeaders);\n }\n\n protected clone(): this {\n const cloned = Object.create(Object.getPrototypeOf(this));\n Object.assign(cloned, this);\n return cloned;\n }\n\n protected cloneWithHeaders(headers: Record<string, unknown>): this {\n const cloned = this.clone();\n Object.defineProperty(cloned, \"headers\", {\n value: Object.freeze(headers),\n writable: false,\n configurable: true,\n });\n return cloned;\n }\n\n public getHeader<T = string>(field: string): T | undefined {\n return this.headers[field] as any;\n }\n\n public getHeaders(): MessageHeaders {\n return Object.freeze({ ...this.headers });\n }\n\n public getPayload(): Payload {\n return this.payload;\n }\n\n public getMessageId(): string {\n return this.headers.id;\n }\n\n public getMessageType(): string {\n return this.headers.type;\n }\n\n public getSchemaVersion(): Version | undefined {\n return this.headers.schemaVersion;\n }\n\n public getTimestamp(): Date {\n return this.headers.createdAt;\n }\n\n public getIntent(): string | undefined {\n return (this.constructor as MessageClass).getIntent();\n }\n\n public toJSON(): {\n headers: MessageHeaders;\n payload: unknown;\n } {\n return {\n headers: { ...this.headers },\n payload: this.serializePayload(this.payload),\n };\n }\n\n public serialize(): {\n headers: MessageHeaders;\n payload: Record<string, unknown>;\n } {\n return JSON.parse(JSON.stringify(this.toJSON()));\n }\n\n protected serializePayload(payload: Payload): unknown {\n return payload;\n }\n\n public asType<M extends MessageClass>(cls: M): InstanceType<M> {\n const { headers, payload } = this.serialize();\n return cls.from(payload, headers) as InstanceType<M>;\n }\n}\n\nexport type AnyMessage = Message;\n\nexport type MessageClass<T extends Message = Message> = {\n getSchemaVersion(): Version;\n getType(): string;\n getIntent(): string | undefined;\n from: (rawPayload: any, header?: MessageHeaders) => T;\n new (...args: any[]): T;\n};\n\nfunction generateHeaderFor(\n cls: MessageClass,\n ...excludes: string[]\n): MessageHeaders {\n const headers: Partial<MessageHeaders> = {};\n\n if (!excludes.includes(\"id\")) {\n headers.id = uuid();\n }\n\n if (!excludes.includes(\"type\")) {\n headers.type = cls.getType();\n }\n\n if (!excludes.includes(\"intent\")) {\n const intent = cls.getIntent();\n if (intent !== undefined) {\n headers.intent = intent;\n }\n }\n\n if (!excludes.includes(\"schemaVersion\")) {\n const schemaVersion = cls.getSchemaVersion();\n if (schemaVersion !== undefined) {\n headers.schemaVersion = schemaVersion;\n }\n }\n\n if (!excludes.includes(\"createdAt\")) {\n headers.createdAt = new Date();\n }\n\n return headers as MessageHeaders;\n}\n\nexport type PayloadOf<M> = M extends Message<infer P> ? P : never;\n","import { Message } from \"@/message\";\n\nexport class DomainEvent<\n P extends Record<string, any> = Record<string, unknown>,\n> extends Message<P> {\n static override getIntent() {\n return \"event\";\n }\n}\n","export class Id<T extends string | number> {\n public constructor(private readonly value: T) {}\n\n public getValue(): T {\n return this.value;\n }\n\n public equals(other: Id<T>): boolean {\n return (\n this.constructor === other.constructor &&\n this.getValue() === other.getValue()\n );\n }\n}\n\nexport type IdOf<T> = T extends Identifiable<infer Id> ? Id : never;\n\nexport interface Identifiable<T extends Id<string | number> = Id<string>> {\n getId(): T;\n}\n","import { Identifiable, IdOf } from \"./identifiable\";\n\nexport interface Repository<T extends Identifiable<any>> {\n get(id: IdOf<T>): Promise<T>;\n add(entity: T): Promise<void>;\n update(entity: T): Promise<void>;\n}\n\nexport class RepositoryError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"RepositoryError\";\n }\n}\n\nexport class DuplicateObjectError extends RepositoryError {\n constructor(message: string) {\n super(message);\n this.name = \"DuplicateObjectError\";\n }\n}\n\nexport class ObjectNotFoundError extends RepositoryError {\n constructor(message: string) {\n super(message);\n this.name = \"ObjectNotFoundError\";\n }\n}\n","export enum Propagation {\n NEW = \"new\",\n EXISTING = \"existing\",\n NESTED = \"nested\",\n}\n\nexport interface BaseUnitOfWorkOptions {\n propagation: Propagation;\n}\n\nexport interface UnitOfWork<\n Client = unknown,\n Options extends BaseUnitOfWorkOptions = BaseUnitOfWorkOptions,\n> {\n getClient(): Client;\n wrap<T>(\n fn: (client: Client) => Promise<T>,\n options?: Partial<Options>\n ): Promise<T>;\n}\n\n"]}
@@ -1,7 +1,38 @@
1
- export * as matchers from "./matchers";
2
- export * from "./matchers";
3
- export * from "./dummy-message";
4
- export { setExpect } from "./expect";
5
- export * from "./utils";
6
- export * from "./in-memory-event-store";
7
- //# sourceMappingURL=index.d.ts.map
1
+ import { M as Message, b as MessageClass, c as MessageHeaders, E as EventStore, S as StoredEvent, a as EventStoreFetchResult } from '../event-store-DQXtakLF.js';
2
+
3
+ declare function expectMessagesToBeFullyEqual(messages: Message[], expectedMessages: Message[]): void;
4
+ declare function expectMessagesToContain(messages: Message[], expectedMessages: Message[]): void;
5
+ declare function expectMessageToMatch(messages: Message[], messageType: string | MessageClass<any>, payload?: Record<string, unknown>): void;
6
+
7
+ declare const matchers_expectMessageToMatch: typeof expectMessageToMatch;
8
+ declare const matchers_expectMessagesToBeFullyEqual: typeof expectMessagesToBeFullyEqual;
9
+ declare const matchers_expectMessagesToContain: typeof expectMessagesToContain;
10
+ declare namespace matchers {
11
+ export { matchers_expectMessageToMatch as expectMessageToMatch, matchers_expectMessagesToBeFullyEqual as expectMessagesToBeFullyEqual, matchers_expectMessagesToContain as expectMessagesToContain };
12
+ }
13
+
14
+ declare class DummyMessage extends Message<Record<never, never>> {
15
+ static type: string;
16
+ static create(): DummyMessage;
17
+ static createMany(number: number): DummyMessage[];
18
+ static from(_: Record<never, never>, headers?: MessageHeaders): DummyMessage;
19
+ }
20
+
21
+ declare function setExpect(expectStatic: any): void;
22
+
23
+ declare function partialMatch(source: Record<any, any>, target: Record<any, any>): boolean;
24
+
25
+ declare function waitForTicks(number?: number): Promise<void>;
26
+ declare function waitForMs(number?: number): Promise<void>;
27
+ declare function waitFor(type?: "ticks" | "ms", number?: number): Promise<void>;
28
+
29
+ declare class InMemoryEventStore implements EventStore {
30
+ private events;
31
+ store(event: Message): Promise<StoredEvent>;
32
+ storeAll(events: Message[]): Promise<StoredEvent[]>;
33
+ fetch(afterPosition: number, limit?: number): Promise<EventStoreFetchResult>;
34
+ getLastPosition(): Promise<number>;
35
+ clear(): void;
36
+ }
37
+
38
+ export { DummyMessage, InMemoryEventStore, expectMessageToMatch, expectMessagesToBeFullyEqual, expectMessagesToContain, matchers, partialMatch, setExpect, waitFor, waitForMs, waitForTicks };