@hexaijs/core 0.5.0 → 0.6.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.
- package/README.md +107 -0
- package/dist/{event-store-BDib72ud.d.ts → event-store-UbTJSE4H.d.ts} +19 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +37 -12
- package/dist/index.js.map +1 -1
- package/dist/test/index.d.ts +1 -1
- package/dist/test/index.js +38 -13
- package/dist/test/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,6 +51,106 @@ 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: { correlation: { id: "corr-abc", type: "HttpRequest" } } }
|
|
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
|
+
.withCorrelation({ id: "corr-abc", type: "HttpRequest" })
|
|
125
|
+
.withHeader("source", "api-gateway");
|
|
126
|
+
|
|
127
|
+
command.getCorrelation(); // { id: "corr-abc", type: "HttpRequest" }
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`withHeader()` returns a new immutable instance - the original message is not modified.
|
|
131
|
+
|
|
132
|
+
#### Message Tracing
|
|
133
|
+
|
|
134
|
+
Messages support built-in correlation and causation tracing for distributed message flows:
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
import { Message, MessageTrace } from "@hexaijs/core";
|
|
138
|
+
|
|
139
|
+
// Get message identity as trace
|
|
140
|
+
const trace: MessageTrace = command.asTrace();
|
|
141
|
+
// { id: "msg-uuid", type: "order.create-order" }
|
|
142
|
+
|
|
143
|
+
// Set correlation (root message in chain)
|
|
144
|
+
const correlated = command.withCorrelation({ id: "req-123", type: "HttpRequest" });
|
|
145
|
+
correlated.getCorrelation(); // { id: "req-123", type: "HttpRequest" }
|
|
146
|
+
|
|
147
|
+
// Set causation (direct parent message)
|
|
148
|
+
const caused = event.withCausation(command.asTrace());
|
|
149
|
+
caused.getCausation(); // { id: "cmd-uuid", type: "order.create-order" }
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
When events are published through `ApplicationContext.publish()`, causation and correlation headers are set automatically.
|
|
153
|
+
|
|
54
154
|
### DomainEvent
|
|
55
155
|
|
|
56
156
|
`DomainEvent` extends `Message` for events that represent something that happened in your domain.
|
|
@@ -257,6 +357,13 @@ throw new DuplicateObjectError("Order with this ID already exists");
|
|
|
257
357
|
| Export | Description |
|
|
258
358
|
|--------|-------------|
|
|
259
359
|
| `Message<P>` | Base message class with headers and typed payload |
|
|
360
|
+
| `MessageOptions` | Options for Message constructor (`{ headers? }`) |
|
|
361
|
+
| `MessageTrace` | Interface for message identity (`{ id, type }`) used in tracing |
|
|
362
|
+
| `Message.asTrace()` | Returns this message's identity as `MessageTrace` |
|
|
363
|
+
| `Message.getCausation()` | Gets the direct parent message trace |
|
|
364
|
+
| `Message.getCorrelation()` | Gets the root message trace in the chain |
|
|
365
|
+
| `Message.withCausation(trace)` | Sets causation, returns new instance |
|
|
366
|
+
| `Message.withCorrelation(trace)` | Sets correlation, returns new instance |
|
|
260
367
|
| `DomainEvent<P>` | Message subclass for domain events |
|
|
261
368
|
| `AggregateRoot<T>` | Base class for aggregates with event collection |
|
|
262
369
|
| `Id<T>` | Value object for typed identities |
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
type Version = string | number | undefined;
|
|
2
|
+
interface MessageTrace {
|
|
3
|
+
id: string;
|
|
4
|
+
type: string;
|
|
5
|
+
}
|
|
2
6
|
interface MessageHeaders {
|
|
3
7
|
id: string;
|
|
4
8
|
type: string;
|
|
@@ -11,6 +15,9 @@ type ExtraHeaderField = Exclude<keyof MessageHeaders, "id" | "type" | "intent" |
|
|
|
11
15
|
type RawMessageHeaders = Omit<MessageHeaders, "createdAt"> & {
|
|
12
16
|
createdAt: string | Date;
|
|
13
17
|
};
|
|
18
|
+
interface MessageOptions {
|
|
19
|
+
headers?: Record<string, unknown>;
|
|
20
|
+
}
|
|
14
21
|
declare class Message<Payload = any> {
|
|
15
22
|
protected readonly payload: Payload;
|
|
16
23
|
protected headers: MessageHeaders;
|
|
@@ -21,10 +28,11 @@ declare class Message<Payload = any> {
|
|
|
21
28
|
static from(rawPayload: Record<string, unknown>, headers?: RawMessageHeaders): Message;
|
|
22
29
|
protected static deserializeRawPayload(rawPayload: any): any;
|
|
23
30
|
protected static deserializeRawHeaders(headers: RawMessageHeaders): MessageHeaders;
|
|
24
|
-
constructor(payload: Payload,
|
|
31
|
+
constructor(payload: Payload, options?: MessageOptions);
|
|
25
32
|
protected static mergeHeaders(headers: Record<string, unknown>): MessageHeaders;
|
|
26
33
|
withHeader(field: ExtraHeaderField, value: unknown): this;
|
|
27
34
|
protected clone(): this;
|
|
35
|
+
protected cloneWithHeaders(headers: Record<string, unknown>): this;
|
|
28
36
|
getHeader<T = string>(field: string): T | undefined;
|
|
29
37
|
getHeaders(): MessageHeaders;
|
|
30
38
|
getPayload(): Payload;
|
|
@@ -33,13 +41,21 @@ declare class Message<Payload = any> {
|
|
|
33
41
|
getSchemaVersion(): Version | undefined;
|
|
34
42
|
getTimestamp(): Date;
|
|
35
43
|
getIntent(): string | undefined;
|
|
44
|
+
toJSON(): {
|
|
45
|
+
headers: MessageHeaders;
|
|
46
|
+
payload: unknown;
|
|
47
|
+
};
|
|
36
48
|
serialize(): {
|
|
37
49
|
headers: MessageHeaders;
|
|
38
50
|
payload: Record<string, unknown>;
|
|
39
51
|
};
|
|
40
|
-
private doSerialize;
|
|
41
52
|
protected serializePayload(payload: Payload): unknown;
|
|
42
53
|
asType<M extends MessageClass>(cls: M): InstanceType<M>;
|
|
54
|
+
asTrace(): MessageTrace;
|
|
55
|
+
getCausation(): MessageTrace | undefined;
|
|
56
|
+
getCorrelation(): MessageTrace | undefined;
|
|
57
|
+
withCausation(trace: MessageTrace): this;
|
|
58
|
+
withCorrelation(trace: MessageTrace): this;
|
|
43
59
|
}
|
|
44
60
|
type AnyMessage = Message;
|
|
45
61
|
type MessageClass<T extends Message = Message> = {
|
|
@@ -63,4 +79,4 @@ interface EventStore {
|
|
|
63
79
|
fetch(afterPosition: number, limit?: number): Promise<EventStoreFetchResult>;
|
|
64
80
|
}
|
|
65
81
|
|
|
66
|
-
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 };
|
|
82
|
+
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, type MessageTrace as e };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { M as Message } from './event-store-
|
|
2
|
-
export { A as AnyMessage, E as EventStore, a as EventStoreFetchResult, b as MessageClass, c as MessageHeaders, P as PayloadOf, S as StoredEvent } from './event-store-
|
|
1
|
+
import { M as Message } from './event-store-UbTJSE4H.js';
|
|
2
|
+
export { A as AnyMessage, E as EventStore, a as EventStoreFetchResult, b as MessageClass, c as MessageHeaders, d as MessageOptions, e as MessageTrace, P as PayloadOf, S as StoredEvent } from './event-store-UbTJSE4H.js';
|
|
3
3
|
|
|
4
4
|
declare class DomainEvent<P extends Record<string, any> = Record<string, unknown>> extends Message<P> {
|
|
5
5
|
static getIntent(): string;
|
package/dist/index.js
CHANGED
|
@@ -35,10 +35,10 @@ var ValidationError = class extends InvariantNotSatisfiedError {
|
|
|
35
35
|
}
|
|
36
36
|
};
|
|
37
37
|
var Message = class {
|
|
38
|
-
constructor(payload,
|
|
38
|
+
constructor(payload, options) {
|
|
39
39
|
this.payload = payload;
|
|
40
40
|
this.headers = Object.freeze(
|
|
41
|
-
this.constructor.mergeHeaders(headers)
|
|
41
|
+
this.constructor.mergeHeaders(options?.headers ?? {})
|
|
42
42
|
);
|
|
43
43
|
if (payload && typeof payload === "object") {
|
|
44
44
|
Object.freeze(payload);
|
|
@@ -59,10 +59,9 @@ var Message = class {
|
|
|
59
59
|
}
|
|
60
60
|
static from(rawPayload, headers) {
|
|
61
61
|
const payload = this.deserializeRawPayload(rawPayload);
|
|
62
|
-
return new this(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
);
|
|
62
|
+
return new this(payload, {
|
|
63
|
+
headers: headers ? this.deserializeRawHeaders(headers) : this.newHeaders()
|
|
64
|
+
});
|
|
66
65
|
}
|
|
67
66
|
static deserializeRawPayload(rawPayload) {
|
|
68
67
|
return rawPayload;
|
|
@@ -79,10 +78,21 @@ var Message = class {
|
|
|
79
78
|
}
|
|
80
79
|
withHeader(field, value) {
|
|
81
80
|
const newHeaders = { ...this.headers, [field]: value };
|
|
82
|
-
return
|
|
81
|
+
return this.cloneWithHeaders(newHeaders);
|
|
83
82
|
}
|
|
84
83
|
clone() {
|
|
85
|
-
|
|
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;
|
|
86
96
|
}
|
|
87
97
|
getHeader(field) {
|
|
88
98
|
return this.headers[field];
|
|
@@ -108,15 +118,15 @@ var Message = class {
|
|
|
108
118
|
getIntent() {
|
|
109
119
|
return this.constructor.getIntent();
|
|
110
120
|
}
|
|
111
|
-
|
|
112
|
-
return JSON.parse(JSON.stringify(this.doSerialize()));
|
|
113
|
-
}
|
|
114
|
-
doSerialize() {
|
|
121
|
+
toJSON() {
|
|
115
122
|
return {
|
|
116
123
|
headers: { ...this.headers },
|
|
117
124
|
payload: this.serializePayload(this.payload)
|
|
118
125
|
};
|
|
119
126
|
}
|
|
127
|
+
serialize() {
|
|
128
|
+
return JSON.parse(JSON.stringify(this.toJSON()));
|
|
129
|
+
}
|
|
120
130
|
serializePayload(payload) {
|
|
121
131
|
return payload;
|
|
122
132
|
}
|
|
@@ -124,6 +134,21 @@ var Message = class {
|
|
|
124
134
|
const { headers, payload } = this.serialize();
|
|
125
135
|
return cls.from(payload, headers);
|
|
126
136
|
}
|
|
137
|
+
asTrace() {
|
|
138
|
+
return { id: this.getMessageId(), type: this.getMessageType() };
|
|
139
|
+
}
|
|
140
|
+
getCausation() {
|
|
141
|
+
return this.getHeader("causation");
|
|
142
|
+
}
|
|
143
|
+
getCorrelation() {
|
|
144
|
+
return this.getHeader("correlation");
|
|
145
|
+
}
|
|
146
|
+
withCausation(trace) {
|
|
147
|
+
return this.withHeader("causation", trace);
|
|
148
|
+
}
|
|
149
|
+
withCorrelation(trace) {
|
|
150
|
+
return this.withHeader("correlation", trace);
|
|
151
|
+
}
|
|
127
152
|
};
|
|
128
153
|
function generateHeaderFor(cls, ...excludes) {
|
|
129
154
|
const headers = {};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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 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(\n payload,\n headers ? this.deserializeRawHeaders(headers) : 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 headers: Record<string, unknown> = {}\n ) {\n this.headers = Object.freeze(\n (this.constructor as any).mergeHeaders(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 new (this.constructor as any)(this.payload, newHeaders);\n }\n\n protected clone(): this {\n return new (this.constructor as any)(this.payload, { ...this.headers });\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 serialize(): {\n headers: MessageHeaders;\n payload: Record<string, unknown>;\n } {\n // we do this to convert the Date object to a string\n // and also to remove any reference to the original object\n return JSON.parse(JSON.stringify(this.doSerialize()));\n }\n\n private doSerialize(): {\n headers: MessageHeaders;\n payload: unknown;\n } {\n return {\n headers: { ...this.headers },\n payload: this.serializePayload(this.payload),\n };\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
|
+
{"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 MessageTrace {\n id: string;\n type: string;\n}\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 public asTrace(): MessageTrace {\n return { id: this.getMessageId(), type: this.getMessageType() };\n }\n\n public getCausation(): MessageTrace | undefined {\n return this.getHeader<MessageTrace>(\"causation\");\n }\n\n public getCorrelation(): MessageTrace | undefined {\n return this.getHeader<MessageTrace>(\"correlation\");\n }\n\n public withCausation(trace: MessageTrace): this {\n return this.withHeader(\"causation\", trace);\n }\n\n public withCorrelation(trace: MessageTrace): this {\n return this.withHeader(\"correlation\", trace);\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"]}
|
package/dist/test/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { M as Message, b as MessageClass, c as MessageHeaders, E as EventStore, S as StoredEvent, a as EventStoreFetchResult } from '../event-store-
|
|
1
|
+
import { M as Message, b as MessageClass, c as MessageHeaders, E as EventStore, S as StoredEvent, a as EventStoreFetchResult } from '../event-store-UbTJSE4H.js';
|
|
2
2
|
|
|
3
3
|
declare function expectMessagesToBeFullyEqual(messages: Message[], expectedMessages: Message[]): void;
|
|
4
4
|
declare function expectMessagesToContain(messages: Message[], expectedMessages: Message[]): void;
|
package/dist/test/index.js
CHANGED
|
@@ -139,10 +139,10 @@ function countMatchedKeys(actual, expected) {
|
|
|
139
139
|
return matched;
|
|
140
140
|
}
|
|
141
141
|
var Message = class {
|
|
142
|
-
constructor(payload,
|
|
142
|
+
constructor(payload, options) {
|
|
143
143
|
this.payload = payload;
|
|
144
144
|
this.headers = Object.freeze(
|
|
145
|
-
this.constructor.mergeHeaders(headers)
|
|
145
|
+
this.constructor.mergeHeaders(options?.headers ?? {})
|
|
146
146
|
);
|
|
147
147
|
if (payload && typeof payload === "object") {
|
|
148
148
|
Object.freeze(payload);
|
|
@@ -163,10 +163,9 @@ var Message = class {
|
|
|
163
163
|
}
|
|
164
164
|
static from(rawPayload, headers) {
|
|
165
165
|
const payload = this.deserializeRawPayload(rawPayload);
|
|
166
|
-
return new this(
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
);
|
|
166
|
+
return new this(payload, {
|
|
167
|
+
headers: headers ? this.deserializeRawHeaders(headers) : this.newHeaders()
|
|
168
|
+
});
|
|
170
169
|
}
|
|
171
170
|
static deserializeRawPayload(rawPayload) {
|
|
172
171
|
return rawPayload;
|
|
@@ -183,10 +182,21 @@ var Message = class {
|
|
|
183
182
|
}
|
|
184
183
|
withHeader(field, value) {
|
|
185
184
|
const newHeaders = { ...this.headers, [field]: value };
|
|
186
|
-
return
|
|
185
|
+
return this.cloneWithHeaders(newHeaders);
|
|
187
186
|
}
|
|
188
187
|
clone() {
|
|
189
|
-
|
|
188
|
+
const cloned = Object.create(Object.getPrototypeOf(this));
|
|
189
|
+
Object.assign(cloned, this);
|
|
190
|
+
return cloned;
|
|
191
|
+
}
|
|
192
|
+
cloneWithHeaders(headers) {
|
|
193
|
+
const cloned = this.clone();
|
|
194
|
+
Object.defineProperty(cloned, "headers", {
|
|
195
|
+
value: Object.freeze(headers),
|
|
196
|
+
writable: false,
|
|
197
|
+
configurable: true
|
|
198
|
+
});
|
|
199
|
+
return cloned;
|
|
190
200
|
}
|
|
191
201
|
getHeader(field) {
|
|
192
202
|
return this.headers[field];
|
|
@@ -212,15 +222,15 @@ var Message = class {
|
|
|
212
222
|
getIntent() {
|
|
213
223
|
return this.constructor.getIntent();
|
|
214
224
|
}
|
|
215
|
-
|
|
216
|
-
return JSON.parse(JSON.stringify(this.doSerialize()));
|
|
217
|
-
}
|
|
218
|
-
doSerialize() {
|
|
225
|
+
toJSON() {
|
|
219
226
|
return {
|
|
220
227
|
headers: { ...this.headers },
|
|
221
228
|
payload: this.serializePayload(this.payload)
|
|
222
229
|
};
|
|
223
230
|
}
|
|
231
|
+
serialize() {
|
|
232
|
+
return JSON.parse(JSON.stringify(this.toJSON()));
|
|
233
|
+
}
|
|
224
234
|
serializePayload(payload) {
|
|
225
235
|
return payload;
|
|
226
236
|
}
|
|
@@ -228,6 +238,21 @@ var Message = class {
|
|
|
228
238
|
const { headers, payload } = this.serialize();
|
|
229
239
|
return cls.from(payload, headers);
|
|
230
240
|
}
|
|
241
|
+
asTrace() {
|
|
242
|
+
return { id: this.getMessageId(), type: this.getMessageType() };
|
|
243
|
+
}
|
|
244
|
+
getCausation() {
|
|
245
|
+
return this.getHeader("causation");
|
|
246
|
+
}
|
|
247
|
+
getCorrelation() {
|
|
248
|
+
return this.getHeader("correlation");
|
|
249
|
+
}
|
|
250
|
+
withCausation(trace) {
|
|
251
|
+
return this.withHeader("causation", trace);
|
|
252
|
+
}
|
|
253
|
+
withCorrelation(trace) {
|
|
254
|
+
return this.withHeader("correlation", trace);
|
|
255
|
+
}
|
|
231
256
|
};
|
|
232
257
|
function generateHeaderFor(cls, ...excludes) {
|
|
233
258
|
const headers = {};
|
|
@@ -265,7 +290,7 @@ var DummyMessage = class extends Message {
|
|
|
265
290
|
return _.times(number, () => this.create());
|
|
266
291
|
}
|
|
267
292
|
static from(_4, headers) {
|
|
268
|
-
return new this({}, headers);
|
|
293
|
+
return new this({}, { headers });
|
|
269
294
|
}
|
|
270
295
|
};
|
|
271
296
|
|
package/dist/test/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/test/matchers.ts","../../src/test/partial-match.ts","../../src/test/utils.ts","../../src/test/expect.ts","../../src/message.ts","../../src/test/dummy-message.ts","../../src/test/in-memory-event-store.ts"],"names":["_","uuid"],"mappings":"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","file":"index.js","sourcesContent":["import _ from \"lodash\";\n\nimport { Message, MessageClass } from \"@/message\";\nimport { partialMatch } from \"./utils\";\nimport { expect } from \"./expect\";\n\nexport function expectMessagesToBeFullyEqual(\n messages: Message[],\n expectedMessages: Message[]\n): void {\n const actualSummary = formatMessagesSummary(messages);\n const expectedSummary = formatMessagesSummary(expectedMessages);\n\n expect(actualSummary, \"Messages should match\").toEqual(expectedSummary);\n\n for (let i = 0; i < Math.max(messages.length, expectedMessages.length); i++) {\n const actual = messages[i]?.serialize();\n const expected = expectedMessages[i]?.serialize();\n\n expect(actual, `message[${i}]`).toEqual(expected);\n }\n}\n\nexport function expectMessagesToContain(\n messages: Message[],\n expectedMessages: Message[]\n): void {\n for (const message of expectedMessages) {\n expectMessageToMatch(\n messages,\n message.getMessageType(),\n message.getPayload()\n );\n }\n}\n\nexport function expectMessageToMatch(\n messages: Message[],\n messageType: string | MessageClass<any>,\n payload: Record<string, unknown> = {}\n): void {\n const resolvedMessageType =\n typeof messageType === \"string\" ? messageType : messageType.getType();\n const sameTypeMessages = messages.filter(\n (msg) => msg.getMessageType() === resolvedMessageType\n );\n\n if (sameTypeMessages.length === 0) {\n const availableTypes = [...new Set(messages.map((m) => m.getMessageType()))];\n expect.fail(\n `Message not found: \"${resolvedMessageType}\"\\n\\n` +\n `Available message types:\\n` +\n (availableTypes.length === 0\n ? \" (none)\"\n : availableTypes.map((t) => ` - ${t}`).join(\"\\n\"))\n );\n }\n\n const found = sameTypeMessages.find((msg) =>\n partialMatch(msg.getPayload(), payload)\n );\n\n if (!found) {\n const closestMatch = findClosestMatch(sameTypeMessages, payload);\n\n expect(\n closestMatch.payload,\n `Found ${sameTypeMessages.length} message(s) of type \"${resolvedMessageType}\", ` +\n `but payload did not match.\\n` +\n `Showing closest match (${closestMatch.matchedKeys}/${closestMatch.totalKeys} keys matched):`\n ).toMatchObject(payload);\n }\n}\n\nfunction formatMessagesSummary(messages: Message[]): Array<{ type: string; payload: unknown }> {\n return messages.map((msg) => ({\n type: msg.getMessageType(),\n payload: msg.getPayload(),\n }));\n}\n\nfunction findClosestMatch(\n messages: Message[],\n expectedPayload: Record<string, unknown>\n): { payload: Record<string, unknown>; matchedKeys: number; totalKeys: number } {\n const expectedKeys = Object.keys(expectedPayload);\n let bestMatch = {\n payload: messages[0]?.getPayload() ?? {},\n matchedKeys: 0,\n totalKeys: expectedKeys.length,\n };\n\n for (const msg of messages) {\n const actualPayload = msg.getPayload();\n const matchedKeys = countMatchedKeys(actualPayload, expectedPayload);\n\n if (matchedKeys > bestMatch.matchedKeys) {\n bestMatch = { payload: actualPayload, matchedKeys, totalKeys: expectedKeys.length };\n }\n }\n\n return bestMatch;\n}\n\nfunction countMatchedKeys(\n actual: Record<string, unknown>,\n expected: Record<string, unknown>\n): number {\n let matched = 0;\n for (const key of Object.keys(expected)) {\n if (_.isEqual(actual[key], expected[key])) {\n matched++;\n }\n }\n return matched;\n}\n","import _ from \"lodash\";\n\nexport const anyString = Symbol.for(\"string\");\n\nexport const anyDate = Symbol.for(\"date\");\n\nexport function partialMatch(\n source: Record<any, any>,\n target: Record<any, any>\n): boolean {\n for (const key of Object.keys(target)) {\n const shouldRecurse =\n _.isObject(source[key]) && _.isObject(target[key]);\n\n if (shouldRecurse) {\n if (!partialMatch(source[key], target[key])) {\n return false;\n }\n } else {\n if (target[key] === anyString && typeof source[key] === \"string\") {\n continue;\n }\n\n if (target[key] === anyDate && source[key] instanceof Date) {\n continue;\n }\n\n if (!_.isEqual(source[key], target[key])) {\n return false;\n }\n }\n }\n\n return true;\n}\n","export { partialMatch } from \"./partial-match\";\n\nexport async function waitForTicks(number = 10): Promise<void> {\n for (let i = 0; i < number; i++) {\n await new Promise((resolve) => setTimeout(resolve, 0));\n }\n}\n\nexport async function waitForMs(number = 10): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, number));\n}\n\nexport async function waitFor(\n type: \"ticks\" | \"ms\" = \"ticks\",\n number = 10\n): Promise<void> {\n if (type === \"ticks\") {\n await waitForTicks(number);\n } else {\n await waitForMs(number);\n }\n}\n","import { RUNNING_HEXAI_TEST } from \"@/config\";\n\nexport let expect!: any;\n\n// if (RUNNING_HEXAI_TEST) {\n// import(\"vitest\").then(({ expect: expectStatic }) => {\n// expect = expectStatic;\n// });\n// }\n\nexport function setExpect(expectStatic: any) {\n expect = expectStatic;\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 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(\n payload,\n headers ? this.deserializeRawHeaders(headers) : 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 headers: Record<string, unknown> = {}\n ) {\n this.headers = Object.freeze(\n (this.constructor as any).mergeHeaders(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 new (this.constructor as any)(this.payload, newHeaders);\n }\n\n protected clone(): this {\n return new (this.constructor as any)(this.payload, { ...this.headers });\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 serialize(): {\n headers: MessageHeaders;\n payload: Record<string, unknown>;\n } {\n // we do this to convert the Date object to a string\n // and also to remove any reference to the original object\n return JSON.parse(JSON.stringify(this.doSerialize()));\n }\n\n private doSerialize(): {\n headers: MessageHeaders;\n payload: unknown;\n } {\n return {\n headers: { ...this.headers },\n payload: this.serializePayload(this.payload),\n };\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 _ from \"lodash\";\n\nimport { Message, MessageHeaders } from \"@/message\";\n\nexport class DummyMessage extends Message<Record<never, never>> {\n static type = \"test.dummy-message\";\n\n public static create() {\n return new this({});\n }\n\n public static createMany(number: number) {\n return _.times(number, () => this.create());\n }\n\n public static from(\n _: Record<never, never>,\n headers?: MessageHeaders\n ): DummyMessage {\n return new this({}, headers);\n }\n}\n","import { EventStore, EventStoreFetchResult, StoredEvent } from \"@/event-store\";\nimport { Message } from \"@/message\";\n\nexport class InMemoryEventStore implements EventStore {\n private events: StoredEvent[] = [];\n\n async store(event: Message): Promise<StoredEvent> {\n const position = this.events.length + 1;\n const storedEvent: StoredEvent = { position, event };\n this.events.push(storedEvent);\n return storedEvent;\n }\n\n async storeAll(events: Message[]): Promise<StoredEvent[]> {\n const storedEvents: StoredEvent[] = [];\n for (const event of events) {\n storedEvents.push(await this.store(event));\n }\n return storedEvents;\n }\n\n async fetch(\n afterPosition: number,\n limit?: number\n ): Promise<EventStoreFetchResult> {\n const lastPosition = await this.getLastPosition();\n let filtered = this.events.filter((e) => e.position > afterPosition);\n\n if (limit !== undefined) {\n filtered = filtered.slice(0, limit);\n }\n\n return {\n events: filtered,\n lastPosition,\n };\n }\n\n async getLastPosition(): Promise<number> {\n return this.events.length;\n }\n\n clear(): void {\n this.events = [];\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/test/matchers.ts","../../src/test/partial-match.ts","../../src/test/utils.ts","../../src/test/expect.ts","../../src/message.ts","../../src/test/dummy-message.ts","../../src/test/in-memory-event-store.ts"],"names":["_","uuid"],"mappings":"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","file":"index.js","sourcesContent":["import _ from \"lodash\";\n\nimport { Message, MessageClass } from \"@/message\";\nimport { partialMatch } from \"./utils\";\nimport { expect } from \"./expect\";\n\nexport function expectMessagesToBeFullyEqual(\n messages: Message[],\n expectedMessages: Message[]\n): void {\n const actualSummary = formatMessagesSummary(messages);\n const expectedSummary = formatMessagesSummary(expectedMessages);\n\n expect(actualSummary, \"Messages should match\").toEqual(expectedSummary);\n\n for (let i = 0; i < Math.max(messages.length, expectedMessages.length); i++) {\n const actual = messages[i]?.serialize();\n const expected = expectedMessages[i]?.serialize();\n\n expect(actual, `message[${i}]`).toEqual(expected);\n }\n}\n\nexport function expectMessagesToContain(\n messages: Message[],\n expectedMessages: Message[]\n): void {\n for (const message of expectedMessages) {\n expectMessageToMatch(\n messages,\n message.getMessageType(),\n message.getPayload()\n );\n }\n}\n\nexport function expectMessageToMatch(\n messages: Message[],\n messageType: string | MessageClass<any>,\n payload: Record<string, unknown> = {}\n): void {\n const resolvedMessageType =\n typeof messageType === \"string\" ? messageType : messageType.getType();\n const sameTypeMessages = messages.filter(\n (msg) => msg.getMessageType() === resolvedMessageType\n );\n\n if (sameTypeMessages.length === 0) {\n const availableTypes = [...new Set(messages.map((m) => m.getMessageType()))];\n expect.fail(\n `Message not found: \"${resolvedMessageType}\"\\n\\n` +\n `Available message types:\\n` +\n (availableTypes.length === 0\n ? \" (none)\"\n : availableTypes.map((t) => ` - ${t}`).join(\"\\n\"))\n );\n }\n\n const found = sameTypeMessages.find((msg) =>\n partialMatch(msg.getPayload(), payload)\n );\n\n if (!found) {\n const closestMatch = findClosestMatch(sameTypeMessages, payload);\n\n expect(\n closestMatch.payload,\n `Found ${sameTypeMessages.length} message(s) of type \"${resolvedMessageType}\", ` +\n `but payload did not match.\\n` +\n `Showing closest match (${closestMatch.matchedKeys}/${closestMatch.totalKeys} keys matched):`\n ).toMatchObject(payload);\n }\n}\n\nfunction formatMessagesSummary(messages: Message[]): Array<{ type: string; payload: unknown }> {\n return messages.map((msg) => ({\n type: msg.getMessageType(),\n payload: msg.getPayload(),\n }));\n}\n\nfunction findClosestMatch(\n messages: Message[],\n expectedPayload: Record<string, unknown>\n): { payload: Record<string, unknown>; matchedKeys: number; totalKeys: number } {\n const expectedKeys = Object.keys(expectedPayload);\n let bestMatch = {\n payload: messages[0]?.getPayload() ?? {},\n matchedKeys: 0,\n totalKeys: expectedKeys.length,\n };\n\n for (const msg of messages) {\n const actualPayload = msg.getPayload();\n const matchedKeys = countMatchedKeys(actualPayload, expectedPayload);\n\n if (matchedKeys > bestMatch.matchedKeys) {\n bestMatch = { payload: actualPayload, matchedKeys, totalKeys: expectedKeys.length };\n }\n }\n\n return bestMatch;\n}\n\nfunction countMatchedKeys(\n actual: Record<string, unknown>,\n expected: Record<string, unknown>\n): number {\n let matched = 0;\n for (const key of Object.keys(expected)) {\n if (_.isEqual(actual[key], expected[key])) {\n matched++;\n }\n }\n return matched;\n}\n","import _ from \"lodash\";\n\nexport const anyString = Symbol.for(\"string\");\n\nexport const anyDate = Symbol.for(\"date\");\n\nexport function partialMatch(\n source: Record<any, any>,\n target: Record<any, any>\n): boolean {\n for (const key of Object.keys(target)) {\n const shouldRecurse =\n _.isObject(source[key]) && _.isObject(target[key]);\n\n if (shouldRecurse) {\n if (!partialMatch(source[key], target[key])) {\n return false;\n }\n } else {\n if (target[key] === anyString && typeof source[key] === \"string\") {\n continue;\n }\n\n if (target[key] === anyDate && source[key] instanceof Date) {\n continue;\n }\n\n if (!_.isEqual(source[key], target[key])) {\n return false;\n }\n }\n }\n\n return true;\n}\n","export { partialMatch } from \"./partial-match\";\n\nexport async function waitForTicks(number = 10): Promise<void> {\n for (let i = 0; i < number; i++) {\n await new Promise((resolve) => setTimeout(resolve, 0));\n }\n}\n\nexport async function waitForMs(number = 10): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, number));\n}\n\nexport async function waitFor(\n type: \"ticks\" | \"ms\" = \"ticks\",\n number = 10\n): Promise<void> {\n if (type === \"ticks\") {\n await waitForTicks(number);\n } else {\n await waitForMs(number);\n }\n}\n","import { RUNNING_HEXAI_TEST } from \"@/config\";\n\nexport let expect!: any;\n\n// if (RUNNING_HEXAI_TEST) {\n// import(\"vitest\").then(({ expect: expectStatic }) => {\n// expect = expectStatic;\n// });\n// }\n\nexport function setExpect(expectStatic: any) {\n expect = expectStatic;\n}\n","import { v4 as uuid } from \"uuid\";\n\ntype Version = string | number | undefined;\n\nexport interface MessageTrace {\n id: string;\n type: string;\n}\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 public asTrace(): MessageTrace {\n return { id: this.getMessageId(), type: this.getMessageType() };\n }\n\n public getCausation(): MessageTrace | undefined {\n return this.getHeader<MessageTrace>(\"causation\");\n }\n\n public getCorrelation(): MessageTrace | undefined {\n return this.getHeader<MessageTrace>(\"correlation\");\n }\n\n public withCausation(trace: MessageTrace): this {\n return this.withHeader(\"causation\", trace);\n }\n\n public withCorrelation(trace: MessageTrace): this {\n return this.withHeader(\"correlation\", trace);\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 _ from \"lodash\";\n\nimport { Message, MessageHeaders } from \"@/message\";\n\nexport class DummyMessage extends Message<Record<never, never>> {\n static type = \"test.dummy-message\";\n\n public static create() {\n return new this({});\n }\n\n public static createMany(number: number) {\n return _.times(number, () => this.create());\n }\n\n public static from(\n _: Record<never, never>,\n headers?: MessageHeaders\n ): DummyMessage {\n return new this({}, { headers });\n }\n}\n","import { EventStore, EventStoreFetchResult, StoredEvent } from \"@/event-store\";\nimport { Message } from \"@/message\";\n\nexport class InMemoryEventStore implements EventStore {\n private events: StoredEvent[] = [];\n\n async store(event: Message): Promise<StoredEvent> {\n const position = this.events.length + 1;\n const storedEvent: StoredEvent = { position, event };\n this.events.push(storedEvent);\n return storedEvent;\n }\n\n async storeAll(events: Message[]): Promise<StoredEvent[]> {\n const storedEvents: StoredEvent[] = [];\n for (const event of events) {\n storedEvents.push(await this.store(event));\n }\n return storedEvents;\n }\n\n async fetch(\n afterPosition: number,\n limit?: number\n ): Promise<EventStoreFetchResult> {\n const lastPosition = await this.getLastPosition();\n let filtered = this.events.filter((e) => e.position > afterPosition);\n\n if (limit !== undefined) {\n filtered = filtered.slice(0, limit);\n }\n\n return {\n events: filtered,\n lastPosition,\n };\n }\n\n async getLastPosition(): Promise<number> {\n return this.events.length;\n }\n\n clear(): void {\n this.events = [];\n }\n}\n"]}
|