@l-etabli/events 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.
Files changed (58) hide show
  1. package/README.md +146 -155
  2. package/dist/adapters/in-memory/InMemoryEventBus.cjs +8 -3
  3. package/dist/adapters/in-memory/InMemoryEventBus.cjs.map +1 -1
  4. package/dist/adapters/in-memory/InMemoryEventBus.d.cts +10 -2
  5. package/dist/adapters/in-memory/InMemoryEventBus.d.ts +10 -2
  6. package/dist/adapters/in-memory/InMemoryEventBus.mjs +11 -4
  7. package/dist/adapters/in-memory/InMemoryEventBus.mjs.map +1 -1
  8. package/dist/adapters/in-memory/index.d.cts +1 -0
  9. package/dist/adapters/in-memory/index.d.ts +1 -0
  10. package/dist/adapters/kysely/KyselyEventQueries.cjs +2 -0
  11. package/dist/adapters/kysely/KyselyEventQueries.cjs.map +1 -1
  12. package/dist/adapters/kysely/KyselyEventQueries.mjs +2 -0
  13. package/dist/adapters/kysely/KyselyEventQueries.mjs.map +1 -1
  14. package/dist/adapters/kysely/KyselyEventRepository.cjs +5 -1
  15. package/dist/adapters/kysely/KyselyEventRepository.cjs.map +1 -1
  16. package/dist/adapters/kysely/KyselyEventRepository.mjs +5 -1
  17. package/dist/adapters/kysely/KyselyEventRepository.mjs.map +1 -1
  18. package/dist/adapters/kysely/migration.cjs +1 -1
  19. package/dist/adapters/kysely/migration.cjs.map +1 -1
  20. package/dist/adapters/kysely/migration.mjs +1 -1
  21. package/dist/adapters/kysely/migration.mjs.map +1 -1
  22. package/dist/adapters/kysely/types.cjs.map +1 -1
  23. package/dist/adapters/kysely/types.d.cts +7 -3
  24. package/dist/adapters/kysely/types.d.ts +7 -3
  25. package/dist/createNewEvent.cjs +19 -12
  26. package/dist/createNewEvent.cjs.map +1 -1
  27. package/dist/createNewEvent.d.cts +43 -39
  28. package/dist/createNewEvent.d.ts +43 -39
  29. package/dist/createNewEvent.mjs +19 -12
  30. package/dist/createNewEvent.mjs.map +1 -1
  31. package/dist/eventDefinitions.cjs +32 -0
  32. package/dist/eventDefinitions.cjs.map +1 -0
  33. package/dist/eventDefinitions.d.cts +20 -0
  34. package/dist/eventDefinitions.d.ts +20 -0
  35. package/dist/eventDefinitions.mjs +7 -0
  36. package/dist/eventDefinitions.mjs.map +1 -0
  37. package/dist/index.cjs +5 -1
  38. package/dist/index.cjs.map +1 -1
  39. package/dist/index.d.cts +3 -2
  40. package/dist/index.d.ts +3 -2
  41. package/dist/index.mjs +2 -0
  42. package/dist/index.mjs.map +1 -1
  43. package/dist/types.cjs +37 -0
  44. package/dist/types.cjs.map +1 -1
  45. package/dist/types.d.cts +42 -3
  46. package/dist/types.d.ts +42 -3
  47. package/dist/types.mjs +25 -0
  48. package/dist/types.mjs.map +1 -1
  49. package/package.json +1 -1
  50. package/src/adapters/in-memory/InMemoryEventBus.ts +63 -9
  51. package/src/adapters/kysely/KyselyEventQueries.ts +2 -0
  52. package/src/adapters/kysely/KyselyEventRepository.ts +5 -1
  53. package/src/adapters/kysely/migration.ts +3 -1
  54. package/src/adapters/kysely/types.ts +7 -2
  55. package/src/createNewEvent.ts +116 -48
  56. package/src/eventDefinitions.ts +53 -0
  57. package/src/index.ts +2 -1
  58. package/src/types.ts +74 -2
package/README.md CHANGED
@@ -1,44 +1,80 @@
1
1
  # @l-etabli/events
2
2
 
3
- Event-driven architecture library implementing the **outbox pattern** for TypeScript.
3
+ TypeScript library for event-driven architecture with the **outbox pattern**.
4
4
 
5
- Events are persisted in the same transaction as your domain changes, then reliably published asynchronously. No lost events, even on failures.
5
+ Events are persisted in the same transaction as your domain changes, then published asynchronously with retry support.
6
6
 
7
7
  ## Installation
8
8
 
9
9
  ```bash
10
- pnpm add @l-etabli/events
10
+ bun add @l-etabli/events
11
11
  ```
12
12
 
13
- For Kysely adapter (PostgreSQL):
13
+ For Kysely/PostgreSQL:
14
14
 
15
15
  ```bash
16
- pnpm add @l-etabli/events kysely pg
16
+ bun add @l-etabli/events kysely pg
17
17
  ```
18
18
 
19
- ## Quick Start
19
+ ## Recommended API
20
20
 
21
- ### 1. Define Your Events
21
+ The recommended way to model events is now a single canonical definitions object.
22
22
 
23
- ```typescript
24
- import { GenericEvent } from "@l-etabli/events";
23
+ ```ts
24
+ import {
25
+ defineEvent,
26
+ defineEvents,
27
+ type InferEventsFromDefinitions,
28
+ } from "@l-etabli/events";
25
29
 
26
- type MyEvents =
27
- | GenericEvent<"UserCreated", { userId: string; email: string }>
28
- | GenericEvent<"OrderPlaced", { orderId: string; amount: number }>;
30
+ type Project = { id: string; name: string };
31
+ type ProjectContext = { projectId: string };
32
+ type ProjectMemberContext = { projectId: string; memberId: string };
33
+ type ProjectRole = "admin" | "editor";
34
+
35
+ const eventDefinitions = defineEvents({
36
+ ProjectCreated: defineEvent<{ project: Project }, ProjectContext>({
37
+ priority: 1,
38
+ }),
39
+ ProjectUpdated: defineEvent<{ project: Project }, ProjectContext>(),
40
+ UserAddedToProject: defineEvent<
41
+ { projectId: string; userId: string; role: ProjectRole },
42
+ ProjectMemberContext
43
+ >({
44
+ priority: 20,
45
+ }),
46
+ PingSent: defineEvent<{ at: Date }>(),
47
+ });
48
+
49
+ type AppEvents = InferEventsFromDefinitions<typeof eventDefinitions>;
29
50
  ```
30
51
 
31
- ### 2. Setup Event Infrastructure
52
+ Benefits:
53
+
54
+ - one object to maintain
55
+ - topics derived from object keys
56
+ - `priority` lives in the same canonical definition
57
+ - no handwritten `GenericEvent<...> | ...` union in the app
58
+
59
+ ## Quick Start
60
+
61
+ ### 1. Setup infrastructure
32
62
 
33
- ```typescript
63
+ ```ts
34
64
  import {
65
+ createUserActor,
66
+ createWorkerActor,
67
+ createEventCrawler,
35
68
  createInMemoryEventBus,
36
69
  createInMemoryEventRepositoryAndQueries,
37
- createEventCrawler,
38
70
  } from "@l-etabli/events";
39
71
 
40
- const { eventQueries, withUow } = createInMemoryEventRepositoryAndQueries<MyEvents>();
41
- const { eventBus, createNewEvent } = createInMemoryEventBus<MyEvents>(withUow);
72
+ const { eventQueries, withUow } =
73
+ createInMemoryEventRepositoryAndQueries<AppEvents>();
74
+
75
+ const { eventBus, createNewEvent } = createInMemoryEventBus(withUow, {
76
+ eventDefinitions,
77
+ });
42
78
 
43
79
  const crawler = createEventCrawler({
44
80
  withUow,
@@ -47,47 +83,47 @@ const crawler = createEventCrawler({
47
83
  });
48
84
  ```
49
85
 
50
- ### 3. Subscribe to Events
86
+ ### 2. Subscribe to events
51
87
 
52
- ```typescript
88
+ ```ts
53
89
  eventBus.subscribe({
54
- topic: "OrderPlaced",
55
- subscriptionId: "send-confirmation-email",
90
+ topic: "ProjectCreated",
91
+ subscriptionId: "send-project-created-email",
56
92
  callBack: async (event) => {
57
- await emailService.sendOrderConfirmation(event.payload.orderId);
93
+ await emailService.send(event.payload.project.id);
58
94
  },
59
95
  });
60
96
  ```
61
97
 
62
- ### 4. Emit Events (in a use case)
98
+ ### 3. Emit events
63
99
 
64
- ```typescript
100
+ ```ts
65
101
  await withUow(async (uow) => {
66
- // Save your domain entity
67
- await orderRepository.save(order);
102
+ await projectRepository.save(project);
68
103
 
69
- // Emit event in the same transaction
70
104
  await uow.eventRepository.saveNewEventsBatch([
71
105
  createNewEvent({
72
- topic: "OrderPlaced",
73
- payload: { orderId: order.id, amount: order.total },
74
- triggeredByUserId: currentUserId,
106
+ topic: "ProjectCreated",
107
+ payload: { project },
108
+ context: { projectId: project.id },
109
+ triggeredByActor: createUserActor(currentUserId),
110
+ flowId: requestId,
75
111
  }),
76
112
  ]);
77
113
  });
78
114
  ```
79
115
 
80
- ### 5. Process Events
116
+ ### 4. Process events
81
117
 
82
- **Traditional server** - start background polling:
118
+ Traditional server:
83
119
 
84
- ```typescript
120
+ ```ts
85
121
  crawler.start();
86
122
  ```
87
123
 
88
- **Serverless** - trigger on-demand after commit:
124
+ Serverless:
89
125
 
90
- ```typescript
126
+ ```ts
91
127
  await withUow(
92
128
  async (uow) => {
93
129
  await uow.eventRepository.saveNewEventsBatch([event]);
@@ -96,117 +132,107 @@ await withUow(
96
132
  afterCommit: async () => {
97
133
  await crawler.triggerProcessing();
98
134
  },
99
- }
135
+ },
100
136
  );
101
-
102
- ### Returning Values from Transactions
103
-
104
- The `withUow` function supports returning values from your transaction callback:
105
-
106
- ```typescript
107
- const result = await withUow(async (uow) => {
108
- const order = await orderRepository.save(newOrder);
109
-
110
- await uow.eventRepository.saveNewEventsBatch([
111
- createNewEvent({
112
- topic: "OrderPlaced",
113
- payload: { orderId: order.id, amount: order.total },
114
- triggeredByUserId: currentUserId,
115
- }),
116
- ]);
117
-
118
- return { orderId: order.id, createdAt: order.createdAt };
119
- });
120
-
121
- console.log(result.orderId); // Access the returned value
122
137
  ```
123
138
 
124
- ## Event Lifecycle
139
+ ## Event shape
125
140
 
126
- ```
127
- never-published → in-process → published
128
- ↘ failed-but-will-retry → published
129
- ↘ quarantined (after maxRetries)
130
- ```
131
-
132
- - `never-published` - New event, not yet processed
133
- - `in-process` - Currently being published
134
- - `published` - Successfully delivered to all subscribers
135
- - `failed-but-will-retry` - Some subscribers failed, will retry
136
- - `quarantined` - Exceeded max retries, requires manual intervention
137
- - `to-republish` - Force republish to all subscribers
138
-
139
- ## API Reference
140
-
141
- ### Types
141
+ `GenericEvent` remains the base type.
142
142
 
143
- ```typescript
144
- // Define events with topic, payload, and optional context
145
- type GenericEvent<Topic, Payload, Context?> = {
143
+ ```ts
144
+ type GenericEvent<Topic, Payload, Context = undefined> = {
146
145
  id: EventId;
146
+ occurredAt: Date;
147
147
  topic: Topic;
148
148
  payload: Payload;
149
149
  status: EventStatus;
150
- occurredAt: Date;
151
- triggeredByUserId: UserId;
152
150
  publications: EventPublication[];
153
- context?: Context;
151
+ triggeredByActor: Actor;
152
+ flowId?: string;
153
+ causedByEventId?: EventId;
154
154
  priority?: number;
155
+ context?: Context;
155
156
  };
157
+
158
+ type Actor =
159
+ | UserActor
160
+ | SystemActor
161
+ | WorkerActor
162
+ | ApiKeyActor
163
+ | AnonymousActor;
164
+ type UserActor<Id extends string = string> = { kind: "user"; id: Id };
165
+ type SystemActor = { kind: "system" };
166
+ type WorkerActor<Id extends string = string> = { kind: "worker"; id?: Id };
167
+ type ApiKeyActor<Id extends string = string> = { kind: "api-key"; id: Id };
168
+ type AnonymousActor = { kind: "anonymous" };
156
169
  ```
157
170
 
158
- ### `makeCreateNewEvent<Events>(options?)`
171
+ Rules:
159
172
 
160
- Creates a type-safe event factory. Payload is validated against topic at compile time.
173
+ - `payload` is always required
174
+ - `context` is only required at the call site for topics that declare one
175
+ - `priority` is injected automatically from `eventDefinitions` when provided
161
176
 
162
- ```typescript
163
- const createEvent = makeCreateNewEvent<MyEvents>({
164
- getNow: () => new Date(), // optional, for testing
165
- generateId: () => crypto.randomUUID(), // optional, for testing
166
- });
177
+ ## Creating events
167
178
 
168
- // Type-safe: payload must match topic
169
- createEvent({ topic: "UserCreated", payload: { userId: "1", email: "a@b.com" }, triggeredByUserId: "u1" });
170
- ```
179
+ ### From event definitions
171
180
 
172
- ### `createInMemoryEventBus<Events>(withUow, options?)`
181
+ ```ts
182
+ import { createUserActor, makeCreateNewEvent } from "@l-etabli/events";
173
183
 
174
- Creates an in-memory event bus with a typed `createNewEvent` function.
184
+ const createNewEvent = makeCreateNewEvent({
185
+ eventDefinitions,
186
+ });
175
187
 
176
- ```typescript
177
- const { eventBus, createNewEvent } = createInMemoryEventBus<MyEvents>(withUow, {
178
- maxRetries: 3, // default
188
+ createNewEvent({
189
+ topic: "ProjectCreated",
190
+ payload: { project },
191
+ context: { projectId: project.id },
192
+ triggeredByActor: createUserActor(currentUserId),
193
+ });
194
+
195
+ createNewEvent({
196
+ topic: "PingSent",
197
+ payload: { at: new Date() },
198
+ triggeredByActor: createWorkerActor("nightly-sync"),
179
199
  });
180
200
  ```
181
201
 
182
- ### `createEventCrawler(config)`
202
+ ### From an existing union
183
203
 
184
- Creates a background processor for publishing events.
204
+ The previous union-based approach still works.
185
205
 
186
- ```typescript
187
- const crawler = createEventCrawler({
188
- withUow,
189
- eventQueries,
190
- eventBus,
191
- options: {
192
- batchSize: 100, // events per batch (default: 100)
193
- maxParallelProcessing: 1, // parallel publishes (default: 1)
194
- newEventsIntervalMs: 10000, // polling interval (default: 10s)
195
- failedEventsIntervalMs: 60000, // retry interval (default: 60s)
196
- },
197
- });
206
+ ```ts
207
+ import { type GenericEvent, makeCreateNewEvent } from "@l-etabli/events";
208
+
209
+ type LegacyEvents =
210
+ | GenericEvent<"UserCreated", { userId: string; email: string }>
211
+ | GenericEvent<"OrderPlaced", { orderId: string }, { tenantId: string }>;
212
+
213
+ const createNewEvent = makeCreateNewEvent<LegacyEvents>();
214
+ ```
215
+
216
+ ## Event lifecycle
198
217
 
199
- crawler.start(); // Start background polling
200
- crawler.processNewEvents(); // Manual: process new events
201
- crawler.retryFailedEvents(); // Manual: retry failed events
202
- crawler.triggerProcessing(); // Manual: process new + retry failed
218
+ ```text
219
+ never-published -> in-process -> published
220
+ \-> failed-but-will-retry -> published
221
+ \-> quarantined
203
222
  ```
204
223
 
205
- ## Database Setup (Kysely/PostgreSQL)
224
+ Statuses:
206
225
 
207
- ### Migration
226
+ - `never-published`
227
+ - `to-republish`
228
+ - `in-process`
229
+ - `published`
230
+ - `failed-but-will-retry`
231
+ - `quarantined`
208
232
 
209
- ```typescript
233
+ ## Kysely migration helper
234
+
235
+ ```ts
210
236
  import type { Kysely } from "kysely";
211
237
 
212
238
  export async function up(db: Kysely<unknown>): Promise<void> {
@@ -217,51 +243,16 @@ export async function up(db: Kysely<unknown>): Promise<void> {
217
243
  .addColumn("payload", "jsonb", (col) => col.notNull())
218
244
  .addColumn("context", "jsonb")
219
245
  .addColumn("status", "text", (col) => col.notNull())
220
- .addColumn("triggeredByUserId", "text", (col) => col.notNull())
246
+ .addColumn("triggeredByActor", "jsonb", (col) => col.notNull())
247
+ .addColumn("flowId", "text")
248
+ .addColumn("causedByEventId", "text")
221
249
  .addColumn("occurredAt", "timestamptz", (col) => col.notNull())
222
250
  .addColumn("publications", "jsonb", (col) => col.notNull().defaultTo("[]"))
223
251
  .addColumn("priority", "integer")
224
252
  .execute();
225
-
226
- await db.schema
227
- .createIndex("events_status_idx")
228
- .on("events")
229
- .column("status")
230
- .execute();
231
-
232
- await db.schema
233
- .createIndex("events_topic_idx")
234
- .on("events")
235
- .column("topic")
236
- .execute();
237
- }
238
-
239
- export async function down(db: Kysely<unknown>): Promise<void> {
240
- await db.schema.dropTable("events").execute();
241
253
  }
242
254
  ```
243
255
 
244
- ### Usage with Kysely
245
-
246
- ```typescript
247
- import { createInMemoryEventBus, createEventCrawler } from "@l-etabli/events";
248
- import {
249
- KyselyEventRepository,
250
- KyselyEventQueries,
251
- createKyselyMigration,
252
- } from "@l-etabli/events/kysely";
253
-
254
- // See examples/kysely/ for complete implementation
255
- ```
256
-
257
256
  ## Examples
258
257
 
259
- See the [`examples/`](./examples/) directory for complete implementations:
260
-
261
- - **[kysely-adapter.ts](./examples/kysely/kysely-adapter.ts)** - Kysely adapter with transaction support
262
- - **[serverless-usage.ts](./examples/kysely/serverless-usage.ts)** - AWS Lambda / serverless deployment
263
- - **[cascading-events.ts](./examples/kysely/cascading-events.ts)** - Transactional event chains
264
-
265
- ## License
266
-
267
- MIT
258
+ See [`examples/`](./examples/) for Kysely integration, cascading events and serverless usage.
@@ -23,9 +23,14 @@ __export(InMemoryEventBus_exports, {
23
23
  module.exports = __toCommonJS(InMemoryEventBus_exports);
24
24
  var import_createNewEvent = require("../../createNewEvent.ts");
25
25
  var import_subscriptions = require("../../subscriptions.ts");
26
- const createInMemoryEventBus = (withUow, options = {}) => {
26
+ function createInMemoryEventBus(withUow, options = {}) {
27
27
  const maxRetries = options.maxRetries ?? 3;
28
- const createNewEvent = (0, import_createNewEvent.makeCreateNewEvent)({
28
+ const eventDefinitions = "eventDefinitions" in options ? options.eventDefinitions : void 0;
29
+ const createNewEvent = eventDefinitions ? (0, import_createNewEvent.makeCreateNewEvent)({
30
+ getNow: options.getNow,
31
+ generateId: options.generateId,
32
+ eventDefinitions
33
+ }) : (0, import_createNewEvent.makeCreateNewEvent)({
29
34
  getNow: options.getNow,
30
35
  generateId: options.generateId
31
36
  });
@@ -133,7 +138,7 @@ const createInMemoryEventBus = (withUow, options = {}) => {
133
138
  subscribeAll,
134
139
  subscribeGlobal
135
140
  };
136
- };
141
+ }
137
142
  // Annotate the CommonJS export names for ESM import in node:
138
143
  0 && (module.exports = {
139
144
  createInMemoryEventBus
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/adapters/in-memory/InMemoryEventBus.ts"],"sourcesContent":["import { makeCreateNewEvent } from \"../../createNewEvent.ts\";\nimport type { EventBus } from \"../../ports/EventBus.ts\";\nimport type { WithEventsUow } from \"../../ports/EventRepository.ts\";\nimport {\n type GlobalSubscriberConfig,\n subscribeByTopic,\n subscribeGlobalToTopics,\n type TopicSubscriptions,\n} from \"../../subscriptions.ts\";\nimport type {\n DefaultContext,\n EventId,\n EventPublication,\n GenericEvent,\n SubscriptionId,\n} from \"../../types.ts\";\n\ntype SubscriptionsForTopic = Record<\n string,\n (event: GenericEvent<string, unknown, DefaultContext>) => Promise<void>\n>;\n\ntype CreateInMemoryEventBusOptions = {\n maxRetries?: number;\n getNow?: () => Date;\n generateId?: () => EventId;\n};\n\nexport const createInMemoryEventBus = <\n Event extends GenericEvent<string, unknown, DefaultContext>,\n>(\n withUow: WithEventsUow<Event>,\n options: CreateInMemoryEventBusOptions = {},\n) => {\n const maxRetries = options.maxRetries ?? 3;\n const createNewEvent = makeCreateNewEvent<Event>({\n getNow: options.getNow,\n generateId: options.generateId,\n });\n const subscriptions: Partial<Record<string, SubscriptionsForTopic>> = {};\n\n const executeCallback = async (\n event: Event,\n subscriptionId: string,\n callback: (\n event: GenericEvent<string, unknown, DefaultContext>,\n ) => Promise<void>,\n ): Promise<\n { subscriptionId: string; errorMessage: string; stack?: string } | undefined\n > => {\n try {\n await callback(event);\n } catch (error) {\n return {\n subscriptionId,\n errorMessage: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n };\n }\n };\n\n const getSubscriptionIdsToPublish = (\n event: Event,\n callbacksBySubscriptionId: SubscriptionsForTopic,\n ): string[] => {\n const allSubscriptionIds = Object.keys(callbacksBySubscriptionId);\n\n if (event.publications.length === 0 || event.status === \"to-republish\") {\n return allSubscriptionIds;\n }\n\n const lastPublication = event.publications.reduce((latest, current) =>\n current.publishedAt > latest.publishedAt ? current : latest,\n );\n const failedSubscriptionIds = (lastPublication.failures ?? []).map(\n (failure) => failure.subscriptionId,\n );\n\n return allSubscriptionIds.filter((id) =>\n failedSubscriptionIds.includes(id),\n );\n };\n\n const eventBus: EventBus<Event> = {\n publish: async (event) => {\n const publishedAt = new Date();\n const topic = event.topic;\n\n const callbacksBySubscriptionSlug = subscriptions[topic];\n\n if (!callbacksBySubscriptionSlug) {\n event.publications.push({\n publishedAt,\n publishedSubscribers: [],\n });\n event.status = \"published\";\n await withUow(async (uow) => {\n await uow.eventRepository.save(event);\n });\n return;\n }\n\n const subscriptionIdsToPublish = getSubscriptionIdsToPublish(\n event,\n callbacksBySubscriptionSlug,\n );\n\n const failuresOrUndefined = await Promise.all(\n subscriptionIdsToPublish.map((subscriptionId) =>\n executeCallback(\n event,\n subscriptionId,\n callbacksBySubscriptionSlug[subscriptionId],\n ),\n ),\n );\n\n const failures = failuresOrUndefined.filter(\n (\n f,\n ): f is {\n subscriptionId: string;\n errorMessage: string;\n stack?: string;\n } => f !== undefined,\n );\n\n const publications: EventPublication[] = [\n ...event.publications,\n {\n publishedAt,\n publishedSubscribers: subscriptionIdsToPublish.map(\n (id) => id as SubscriptionId,\n ),\n ...(failures.length > 0 && { failures }),\n },\n ];\n\n if (failures.length === 0) {\n event.status = \"published\";\n } else {\n const wasMaxNumberOfErrorsReached = publications.length >= maxRetries;\n event.status = wasMaxNumberOfErrorsReached\n ? \"quarantined\"\n : \"failed-but-will-retry\";\n }\n\n event.publications = publications;\n\n await withUow(async (uow) => {\n await uow.eventRepository.save(event);\n });\n },\n\n subscribe: ({ topic, subscriptionId, callBack }) => {\n if (!subscriptions[topic]) {\n subscriptions[topic] = {};\n }\n\n const subscriptionsForTopic = subscriptions[topic];\n if (subscriptionsForTopic) {\n subscriptionsForTopic[subscriptionId] = callBack as (\n event: GenericEvent<string, unknown, DefaultContext>,\n ) => Promise<void>;\n }\n },\n };\n\n /**\n * Identity function for type inference when defining subscription maps.\n * Ensures all topics are covered and handlers have correct payload types.\n *\n * @example\n * ```typescript\n * const subscriptions = defineSubscriptions({\n * OrderCreated: [{ subscriptionId: \"notify\", handler: async (e) => {...} }],\n * OrderShipped: [], // Required even if empty\n * });\n * ```\n */\n const defineSubscriptions = (\n subscriptions: TopicSubscriptions<Event>,\n ): TopicSubscriptions<Event> => subscriptions;\n\n /**\n * Subscribe all handlers from a topic subscription map to this event bus.\n *\n * @example\n * ```typescript\n * const subscriptions = defineSubscriptions({...});\n * subscribeAll(subscriptions);\n * ```\n */\n const subscribeAll = (subscriptions: TopicSubscriptions<Event>): void => {\n subscribeByTopic(eventBus, subscriptions);\n };\n\n /**\n * Subscribe a global handler to multiple topics with optional filtering.\n *\n * @example\n * ```typescript\n * subscribeGlobal(subscriptions, {\n * subscriptionId: \"audit-log\",\n * handler: async (event) => auditLog.record(event),\n * filter: { exclude: [\"NotificationAdded\"] },\n * });\n * ```\n */\n const subscribeGlobal = (\n subscriptions: TopicSubscriptions<Event>,\n config: GlobalSubscriberConfig<Event>,\n ): void => {\n subscribeGlobalToTopics(eventBus, subscriptions, config);\n };\n\n return {\n eventBus,\n createNewEvent,\n defineSubscriptions,\n subscribeAll,\n subscribeGlobal,\n };\n};\n"],"mappings":"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","names":["subscriptions"]}
1
+ {"version":3,"sources":["../../../src/adapters/in-memory/InMemoryEventBus.ts"],"sourcesContent":["import {\n type CreateNewEvent,\n type CreateNewEventFromDefinitions,\n makeCreateNewEvent,\n} from \"../../createNewEvent.ts\";\nimport type {\n EventDefinitions,\n InferEventsFromDefinitions,\n} from \"../../eventDefinitions.ts\";\nimport type { EventBus } from \"../../ports/EventBus.ts\";\nimport type { WithEventsUow } from \"../../ports/EventRepository.ts\";\nimport {\n type GlobalSubscriberConfig,\n subscribeByTopic,\n subscribeGlobalToTopics,\n type TopicSubscriptions,\n} from \"../../subscriptions.ts\";\nimport type {\n DefaultContext,\n EventId,\n EventPublication,\n GenericEvent,\n SubscriptionId,\n} from \"../../types.ts\";\n\ntype SubscriptionsForTopic = Record<\n string,\n (event: GenericEvent<string, unknown, DefaultContext>) => Promise<void>\n>;\n\ntype CreateInMemoryEventBusOptions = {\n maxRetries?: number;\n getNow?: () => Date;\n generateId?: () => EventId;\n};\n\ntype CreateInMemoryEventBusFromDefinitionsOptions<\n Definitions extends EventDefinitions,\n> = CreateInMemoryEventBusOptions & {\n eventDefinitions: Definitions;\n};\n\ntype CreateInMemoryEventBusResult<\n Event extends GenericEvent<string, unknown, DefaultContext>,\n> = {\n eventBus: EventBus<Event>;\n createNewEvent: CreateNewEvent<Event>;\n defineSubscriptions: (\n subscriptions: TopicSubscriptions<Event>,\n ) => TopicSubscriptions<Event>;\n subscribeAll: (subscriptions: TopicSubscriptions<Event>) => void;\n subscribeGlobal: (\n subscriptions: TopicSubscriptions<Event>,\n config: GlobalSubscriberConfig<Event>,\n ) => void;\n};\n\nexport function createInMemoryEventBus<\n Event extends GenericEvent<string, unknown, DefaultContext>,\n>(\n withUow: WithEventsUow<Event>,\n options?: CreateInMemoryEventBusOptions,\n): CreateInMemoryEventBusResult<Event>;\nexport function createInMemoryEventBus<Definitions extends EventDefinitions>(\n withUow: WithEventsUow<InferEventsFromDefinitions<Definitions>>,\n options: CreateInMemoryEventBusFromDefinitionsOptions<Definitions>,\n): Omit<\n CreateInMemoryEventBusResult<InferEventsFromDefinitions<Definitions>>,\n \"createNewEvent\"\n> & {\n createNewEvent: CreateNewEventFromDefinitions<Definitions>;\n};\nexport function createInMemoryEventBus<\n Event extends GenericEvent<string, unknown, DefaultContext>,\n>(\n withUow: WithEventsUow<Event>,\n options:\n | CreateInMemoryEventBusOptions\n | CreateInMemoryEventBusFromDefinitionsOptions<EventDefinitions> = {},\n) {\n const maxRetries = options.maxRetries ?? 3;\n const eventDefinitions =\n \"eventDefinitions\" in options ? options.eventDefinitions : undefined;\n const createNewEvent = eventDefinitions\n ? makeCreateNewEvent({\n getNow: options.getNow,\n generateId: options.generateId,\n eventDefinitions,\n })\n : makeCreateNewEvent<Event>({\n getNow: options.getNow,\n generateId: options.generateId,\n });\n const subscriptions: Partial<Record<string, SubscriptionsForTopic>> = {};\n\n const executeCallback = async (\n event: Event,\n subscriptionId: string,\n callback: (\n event: GenericEvent<string, unknown, DefaultContext>,\n ) => Promise<void>,\n ): Promise<\n { subscriptionId: string; errorMessage: string; stack?: string } | undefined\n > => {\n try {\n await callback(event);\n } catch (error) {\n return {\n subscriptionId,\n errorMessage: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n };\n }\n };\n\n const getSubscriptionIdsToPublish = (\n event: Event,\n callbacksBySubscriptionId: SubscriptionsForTopic,\n ): string[] => {\n const allSubscriptionIds = Object.keys(callbacksBySubscriptionId);\n\n if (event.publications.length === 0 || event.status === \"to-republish\") {\n return allSubscriptionIds;\n }\n\n const lastPublication = event.publications.reduce((latest, current) =>\n current.publishedAt > latest.publishedAt ? current : latest,\n );\n const failedSubscriptionIds = (lastPublication.failures ?? []).map(\n (failure) => failure.subscriptionId,\n );\n\n return allSubscriptionIds.filter((id) =>\n failedSubscriptionIds.includes(id),\n );\n };\n\n const eventBus: EventBus<Event> = {\n publish: async (event) => {\n const publishedAt = new Date();\n const topic = event.topic;\n\n const callbacksBySubscriptionSlug = subscriptions[topic];\n\n if (!callbacksBySubscriptionSlug) {\n event.publications.push({\n publishedAt,\n publishedSubscribers: [],\n });\n event.status = \"published\";\n await withUow(async (uow) => {\n await uow.eventRepository.save(event);\n });\n return;\n }\n\n const subscriptionIdsToPublish = getSubscriptionIdsToPublish(\n event,\n callbacksBySubscriptionSlug,\n );\n\n const failuresOrUndefined = await Promise.all(\n subscriptionIdsToPublish.map((subscriptionId) =>\n executeCallback(\n event,\n subscriptionId,\n callbacksBySubscriptionSlug[subscriptionId],\n ),\n ),\n );\n\n const failures = failuresOrUndefined.filter(\n (\n f,\n ): f is {\n subscriptionId: string;\n errorMessage: string;\n stack?: string;\n } => f !== undefined,\n );\n\n const publications: EventPublication[] = [\n ...event.publications,\n {\n publishedAt,\n publishedSubscribers: subscriptionIdsToPublish.map(\n (id) => id as SubscriptionId,\n ),\n ...(failures.length > 0 && { failures }),\n },\n ];\n\n if (failures.length === 0) {\n event.status = \"published\";\n } else {\n const wasMaxNumberOfErrorsReached = publications.length >= maxRetries;\n event.status = wasMaxNumberOfErrorsReached\n ? \"quarantined\"\n : \"failed-but-will-retry\";\n }\n\n event.publications = publications;\n\n await withUow(async (uow) => {\n await uow.eventRepository.save(event);\n });\n },\n\n subscribe: ({ topic, subscriptionId, callBack }) => {\n if (!subscriptions[topic]) {\n subscriptions[topic] = {};\n }\n\n const subscriptionsForTopic = subscriptions[topic];\n if (subscriptionsForTopic) {\n subscriptionsForTopic[subscriptionId] = callBack as (\n event: GenericEvent<string, unknown, DefaultContext>,\n ) => Promise<void>;\n }\n },\n };\n\n /**\n * Identity function for type inference when defining subscription maps.\n * Ensures all topics are covered and handlers have correct payload types.\n *\n * @example\n * ```typescript\n * const subscriptions = defineSubscriptions({\n * OrderCreated: [{ subscriptionId: \"notify\", handler: async (e) => {...} }],\n * OrderShipped: [], // Required even if empty\n * });\n * ```\n */\n const defineSubscriptions = (\n subscriptions: TopicSubscriptions<Event>,\n ): TopicSubscriptions<Event> => subscriptions;\n\n /**\n * Subscribe all handlers from a topic subscription map to this event bus.\n *\n * @example\n * ```typescript\n * const subscriptions = defineSubscriptions({...});\n * subscribeAll(subscriptions);\n * ```\n */\n const subscribeAll = (subscriptions: TopicSubscriptions<Event>): void => {\n subscribeByTopic(eventBus, subscriptions);\n };\n\n /**\n * Subscribe a global handler to multiple topics with optional filtering.\n *\n * @example\n * ```typescript\n * subscribeGlobal(subscriptions, {\n * subscriptionId: \"audit-log\",\n * handler: async (event) => auditLog.record(event),\n * filter: { exclude: [\"NotificationAdded\"] },\n * });\n * ```\n */\n const subscribeGlobal = (\n subscriptions: TopicSubscriptions<Event>,\n config: GlobalSubscriberConfig<Event>,\n ): void => {\n subscribeGlobalToTopics(eventBus, subscriptions, config);\n };\n\n return {\n eventBus,\n createNewEvent,\n defineSubscriptions,\n subscribeAll,\n subscribeGlobal,\n };\n}\n"],"mappings":"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","names":["subscriptions"]}
@@ -1,4 +1,5 @@
1
- import { CreateNewEvent } from '../../createNewEvent.cjs';
1
+ import { CreateNewEvent, CreateNewEventFromDefinitions } from '../../createNewEvent.cjs';
2
+ import { EventDefinitions, InferEventsFromDefinitions } from '../../eventDefinitions.cjs';
2
3
  import { EventBus } from '../../ports/EventBus.cjs';
3
4
  import { WithEventsUow } from '../../ports/EventRepository.cjs';
4
5
  import { TopicSubscriptions, GlobalSubscriberConfig } from '../../subscriptions.cjs';
@@ -9,12 +10,19 @@ type CreateInMemoryEventBusOptions = {
9
10
  getNow?: () => Date;
10
11
  generateId?: () => EventId;
11
12
  };
12
- declare const createInMemoryEventBus: <Event extends GenericEvent<string, unknown, DefaultContext>>(withUow: WithEventsUow<Event>, options?: CreateInMemoryEventBusOptions) => {
13
+ type CreateInMemoryEventBusFromDefinitionsOptions<Definitions extends EventDefinitions> = CreateInMemoryEventBusOptions & {
14
+ eventDefinitions: Definitions;
15
+ };
16
+ type CreateInMemoryEventBusResult<Event extends GenericEvent<string, unknown, DefaultContext>> = {
13
17
  eventBus: EventBus<Event>;
14
18
  createNewEvent: CreateNewEvent<Event>;
15
19
  defineSubscriptions: (subscriptions: TopicSubscriptions<Event>) => TopicSubscriptions<Event>;
16
20
  subscribeAll: (subscriptions: TopicSubscriptions<Event>) => void;
17
21
  subscribeGlobal: (subscriptions: TopicSubscriptions<Event>, config: GlobalSubscriberConfig<Event>) => void;
18
22
  };
23
+ declare function createInMemoryEventBus<Event extends GenericEvent<string, unknown, DefaultContext>>(withUow: WithEventsUow<Event>, options?: CreateInMemoryEventBusOptions): CreateInMemoryEventBusResult<Event>;
24
+ declare function createInMemoryEventBus<Definitions extends EventDefinitions>(withUow: WithEventsUow<InferEventsFromDefinitions<Definitions>>, options: CreateInMemoryEventBusFromDefinitionsOptions<Definitions>): Omit<CreateInMemoryEventBusResult<InferEventsFromDefinitions<Definitions>>, "createNewEvent"> & {
25
+ createNewEvent: CreateNewEventFromDefinitions<Definitions>;
26
+ };
19
27
 
20
28
  export { createInMemoryEventBus };
@@ -1,4 +1,5 @@
1
- import { CreateNewEvent } from '../../createNewEvent.js';
1
+ import { CreateNewEvent, CreateNewEventFromDefinitions } from '../../createNewEvent.js';
2
+ import { EventDefinitions, InferEventsFromDefinitions } from '../../eventDefinitions.js';
2
3
  import { EventBus } from '../../ports/EventBus.js';
3
4
  import { WithEventsUow } from '../../ports/EventRepository.js';
4
5
  import { TopicSubscriptions, GlobalSubscriberConfig } from '../../subscriptions.js';
@@ -9,12 +10,19 @@ type CreateInMemoryEventBusOptions = {
9
10
  getNow?: () => Date;
10
11
  generateId?: () => EventId;
11
12
  };
12
- declare const createInMemoryEventBus: <Event extends GenericEvent<string, unknown, DefaultContext>>(withUow: WithEventsUow<Event>, options?: CreateInMemoryEventBusOptions) => {
13
+ type CreateInMemoryEventBusFromDefinitionsOptions<Definitions extends EventDefinitions> = CreateInMemoryEventBusOptions & {
14
+ eventDefinitions: Definitions;
15
+ };
16
+ type CreateInMemoryEventBusResult<Event extends GenericEvent<string, unknown, DefaultContext>> = {
13
17
  eventBus: EventBus<Event>;
14
18
  createNewEvent: CreateNewEvent<Event>;
15
19
  defineSubscriptions: (subscriptions: TopicSubscriptions<Event>) => TopicSubscriptions<Event>;
16
20
  subscribeAll: (subscriptions: TopicSubscriptions<Event>) => void;
17
21
  subscribeGlobal: (subscriptions: TopicSubscriptions<Event>, config: GlobalSubscriberConfig<Event>) => void;
18
22
  };
23
+ declare function createInMemoryEventBus<Event extends GenericEvent<string, unknown, DefaultContext>>(withUow: WithEventsUow<Event>, options?: CreateInMemoryEventBusOptions): CreateInMemoryEventBusResult<Event>;
24
+ declare function createInMemoryEventBus<Definitions extends EventDefinitions>(withUow: WithEventsUow<InferEventsFromDefinitions<Definitions>>, options: CreateInMemoryEventBusFromDefinitionsOptions<Definitions>): Omit<CreateInMemoryEventBusResult<InferEventsFromDefinitions<Definitions>>, "createNewEvent"> & {
25
+ createNewEvent: CreateNewEventFromDefinitions<Definitions>;
26
+ };
19
27
 
20
28
  export { createInMemoryEventBus };
@@ -1,11 +1,18 @@
1
- import { makeCreateNewEvent } from "../../createNewEvent.mjs";
1
+ import {
2
+ makeCreateNewEvent
3
+ } from "../../createNewEvent.mjs";
2
4
  import {
3
5
  subscribeByTopic,
4
6
  subscribeGlobalToTopics
5
7
  } from "../../subscriptions.mjs";
6
- const createInMemoryEventBus = (withUow, options = {}) => {
8
+ function createInMemoryEventBus(withUow, options = {}) {
7
9
  const maxRetries = options.maxRetries ?? 3;
8
- const createNewEvent = makeCreateNewEvent({
10
+ const eventDefinitions = "eventDefinitions" in options ? options.eventDefinitions : void 0;
11
+ const createNewEvent = eventDefinitions ? makeCreateNewEvent({
12
+ getNow: options.getNow,
13
+ generateId: options.generateId,
14
+ eventDefinitions
15
+ }) : makeCreateNewEvent({
9
16
  getNow: options.getNow,
10
17
  generateId: options.generateId
11
18
  });
@@ -113,7 +120,7 @@ const createInMemoryEventBus = (withUow, options = {}) => {
113
120
  subscribeAll,
114
121
  subscribeGlobal
115
122
  };
116
- };
123
+ }
117
124
  export {
118
125
  createInMemoryEventBus
119
126
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/adapters/in-memory/InMemoryEventBus.ts"],"sourcesContent":["import { makeCreateNewEvent } from '../../createNewEvent.mjs';\nimport type { EventBus } from '../../ports/EventBus.mjs';\nimport type { WithEventsUow } from '../../ports/EventRepository.mjs';\nimport {\n type GlobalSubscriberConfig,\n subscribeByTopic,\n subscribeGlobalToTopics,\n type TopicSubscriptions,\n} from '../../subscriptions.mjs';\nimport type {\n DefaultContext,\n EventId,\n EventPublication,\n GenericEvent,\n SubscriptionId,\n} from '../../types.mjs';\n\ntype SubscriptionsForTopic = Record<\n string,\n (event: GenericEvent<string, unknown, DefaultContext>) => Promise<void>\n>;\n\ntype CreateInMemoryEventBusOptions = {\n maxRetries?: number;\n getNow?: () => Date;\n generateId?: () => EventId;\n};\n\nexport const createInMemoryEventBus = <\n Event extends GenericEvent<string, unknown, DefaultContext>,\n>(\n withUow: WithEventsUow<Event>,\n options: CreateInMemoryEventBusOptions = {},\n) => {\n const maxRetries = options.maxRetries ?? 3;\n const createNewEvent = makeCreateNewEvent<Event>({\n getNow: options.getNow,\n generateId: options.generateId,\n });\n const subscriptions: Partial<Record<string, SubscriptionsForTopic>> = {};\n\n const executeCallback = async (\n event: Event,\n subscriptionId: string,\n callback: (\n event: GenericEvent<string, unknown, DefaultContext>,\n ) => Promise<void>,\n ): Promise<\n { subscriptionId: string; errorMessage: string; stack?: string } | undefined\n > => {\n try {\n await callback(event);\n } catch (error) {\n return {\n subscriptionId,\n errorMessage: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n };\n }\n };\n\n const getSubscriptionIdsToPublish = (\n event: Event,\n callbacksBySubscriptionId: SubscriptionsForTopic,\n ): string[] => {\n const allSubscriptionIds = Object.keys(callbacksBySubscriptionId);\n\n if (event.publications.length === 0 || event.status === \"to-republish\") {\n return allSubscriptionIds;\n }\n\n const lastPublication = event.publications.reduce((latest, current) =>\n current.publishedAt > latest.publishedAt ? current : latest,\n );\n const failedSubscriptionIds = (lastPublication.failures ?? []).map(\n (failure) => failure.subscriptionId,\n );\n\n return allSubscriptionIds.filter((id) =>\n failedSubscriptionIds.includes(id),\n );\n };\n\n const eventBus: EventBus<Event> = {\n publish: async (event) => {\n const publishedAt = new Date();\n const topic = event.topic;\n\n const callbacksBySubscriptionSlug = subscriptions[topic];\n\n if (!callbacksBySubscriptionSlug) {\n event.publications.push({\n publishedAt,\n publishedSubscribers: [],\n });\n event.status = \"published\";\n await withUow(async (uow) => {\n await uow.eventRepository.save(event);\n });\n return;\n }\n\n const subscriptionIdsToPublish = getSubscriptionIdsToPublish(\n event,\n callbacksBySubscriptionSlug,\n );\n\n const failuresOrUndefined = await Promise.all(\n subscriptionIdsToPublish.map((subscriptionId) =>\n executeCallback(\n event,\n subscriptionId,\n callbacksBySubscriptionSlug[subscriptionId],\n ),\n ),\n );\n\n const failures = failuresOrUndefined.filter(\n (\n f,\n ): f is {\n subscriptionId: string;\n errorMessage: string;\n stack?: string;\n } => f !== undefined,\n );\n\n const publications: EventPublication[] = [\n ...event.publications,\n {\n publishedAt,\n publishedSubscribers: subscriptionIdsToPublish.map(\n (id) => id as SubscriptionId,\n ),\n ...(failures.length > 0 && { failures }),\n },\n ];\n\n if (failures.length === 0) {\n event.status = \"published\";\n } else {\n const wasMaxNumberOfErrorsReached = publications.length >= maxRetries;\n event.status = wasMaxNumberOfErrorsReached\n ? \"quarantined\"\n : \"failed-but-will-retry\";\n }\n\n event.publications = publications;\n\n await withUow(async (uow) => {\n await uow.eventRepository.save(event);\n });\n },\n\n subscribe: ({ topic, subscriptionId, callBack }) => {\n if (!subscriptions[topic]) {\n subscriptions[topic] = {};\n }\n\n const subscriptionsForTopic = subscriptions[topic];\n if (subscriptionsForTopic) {\n subscriptionsForTopic[subscriptionId] = callBack as (\n event: GenericEvent<string, unknown, DefaultContext>,\n ) => Promise<void>;\n }\n },\n };\n\n /**\n * Identity function for type inference when defining subscription maps.\n * Ensures all topics are covered and handlers have correct payload types.\n *\n * @example\n * ```typescript\n * const subscriptions = defineSubscriptions({\n * OrderCreated: [{ subscriptionId: \"notify\", handler: async (e) => {...} }],\n * OrderShipped: [], // Required even if empty\n * });\n * ```\n */\n const defineSubscriptions = (\n subscriptions: TopicSubscriptions<Event>,\n ): TopicSubscriptions<Event> => subscriptions;\n\n /**\n * Subscribe all handlers from a topic subscription map to this event bus.\n *\n * @example\n * ```typescript\n * const subscriptions = defineSubscriptions({...});\n * subscribeAll(subscriptions);\n * ```\n */\n const subscribeAll = (subscriptions: TopicSubscriptions<Event>): void => {\n subscribeByTopic(eventBus, subscriptions);\n };\n\n /**\n * Subscribe a global handler to multiple topics with optional filtering.\n *\n * @example\n * ```typescript\n * subscribeGlobal(subscriptions, {\n * subscriptionId: \"audit-log\",\n * handler: async (event) => auditLog.record(event),\n * filter: { exclude: [\"NotificationAdded\"] },\n * });\n * ```\n */\n const subscribeGlobal = (\n subscriptions: TopicSubscriptions<Event>,\n config: GlobalSubscriberConfig<Event>,\n ): void => {\n subscribeGlobalToTopics(eventBus, subscriptions, config);\n };\n\n return {\n eventBus,\n createNewEvent,\n defineSubscriptions,\n subscribeAll,\n subscribeGlobal,\n };\n};\n"],"mappings":"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","names":["subscriptions"]}
1
+ {"version":3,"sources":["../../../src/adapters/in-memory/InMemoryEventBus.ts"],"sourcesContent":["import {\n type CreateNewEvent,\n type CreateNewEventFromDefinitions,\n makeCreateNewEvent,\n} from '../../createNewEvent.mjs';\nimport type {\n EventDefinitions,\n InferEventsFromDefinitions,\n} from '../../eventDefinitions.mjs';\nimport type { EventBus } from '../../ports/EventBus.mjs';\nimport type { WithEventsUow } from '../../ports/EventRepository.mjs';\nimport {\n type GlobalSubscriberConfig,\n subscribeByTopic,\n subscribeGlobalToTopics,\n type TopicSubscriptions,\n} from '../../subscriptions.mjs';\nimport type {\n DefaultContext,\n EventId,\n EventPublication,\n GenericEvent,\n SubscriptionId,\n} from '../../types.mjs';\n\ntype SubscriptionsForTopic = Record<\n string,\n (event: GenericEvent<string, unknown, DefaultContext>) => Promise<void>\n>;\n\ntype CreateInMemoryEventBusOptions = {\n maxRetries?: number;\n getNow?: () => Date;\n generateId?: () => EventId;\n};\n\ntype CreateInMemoryEventBusFromDefinitionsOptions<\n Definitions extends EventDefinitions,\n> = CreateInMemoryEventBusOptions & {\n eventDefinitions: Definitions;\n};\n\ntype CreateInMemoryEventBusResult<\n Event extends GenericEvent<string, unknown, DefaultContext>,\n> = {\n eventBus: EventBus<Event>;\n createNewEvent: CreateNewEvent<Event>;\n defineSubscriptions: (\n subscriptions: TopicSubscriptions<Event>,\n ) => TopicSubscriptions<Event>;\n subscribeAll: (subscriptions: TopicSubscriptions<Event>) => void;\n subscribeGlobal: (\n subscriptions: TopicSubscriptions<Event>,\n config: GlobalSubscriberConfig<Event>,\n ) => void;\n};\n\nexport function createInMemoryEventBus<\n Event extends GenericEvent<string, unknown, DefaultContext>,\n>(\n withUow: WithEventsUow<Event>,\n options?: CreateInMemoryEventBusOptions,\n): CreateInMemoryEventBusResult<Event>;\nexport function createInMemoryEventBus<Definitions extends EventDefinitions>(\n withUow: WithEventsUow<InferEventsFromDefinitions<Definitions>>,\n options: CreateInMemoryEventBusFromDefinitionsOptions<Definitions>,\n): Omit<\n CreateInMemoryEventBusResult<InferEventsFromDefinitions<Definitions>>,\n \"createNewEvent\"\n> & {\n createNewEvent: CreateNewEventFromDefinitions<Definitions>;\n};\nexport function createInMemoryEventBus<\n Event extends GenericEvent<string, unknown, DefaultContext>,\n>(\n withUow: WithEventsUow<Event>,\n options:\n | CreateInMemoryEventBusOptions\n | CreateInMemoryEventBusFromDefinitionsOptions<EventDefinitions> = {},\n) {\n const maxRetries = options.maxRetries ?? 3;\n const eventDefinitions =\n \"eventDefinitions\" in options ? options.eventDefinitions : undefined;\n const createNewEvent = eventDefinitions\n ? makeCreateNewEvent({\n getNow: options.getNow,\n generateId: options.generateId,\n eventDefinitions,\n })\n : makeCreateNewEvent<Event>({\n getNow: options.getNow,\n generateId: options.generateId,\n });\n const subscriptions: Partial<Record<string, SubscriptionsForTopic>> = {};\n\n const executeCallback = async (\n event: Event,\n subscriptionId: string,\n callback: (\n event: GenericEvent<string, unknown, DefaultContext>,\n ) => Promise<void>,\n ): Promise<\n { subscriptionId: string; errorMessage: string; stack?: string } | undefined\n > => {\n try {\n await callback(event);\n } catch (error) {\n return {\n subscriptionId,\n errorMessage: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n };\n }\n };\n\n const getSubscriptionIdsToPublish = (\n event: Event,\n callbacksBySubscriptionId: SubscriptionsForTopic,\n ): string[] => {\n const allSubscriptionIds = Object.keys(callbacksBySubscriptionId);\n\n if (event.publications.length === 0 || event.status === \"to-republish\") {\n return allSubscriptionIds;\n }\n\n const lastPublication = event.publications.reduce((latest, current) =>\n current.publishedAt > latest.publishedAt ? current : latest,\n );\n const failedSubscriptionIds = (lastPublication.failures ?? []).map(\n (failure) => failure.subscriptionId,\n );\n\n return allSubscriptionIds.filter((id) =>\n failedSubscriptionIds.includes(id),\n );\n };\n\n const eventBus: EventBus<Event> = {\n publish: async (event) => {\n const publishedAt = new Date();\n const topic = event.topic;\n\n const callbacksBySubscriptionSlug = subscriptions[topic];\n\n if (!callbacksBySubscriptionSlug) {\n event.publications.push({\n publishedAt,\n publishedSubscribers: [],\n });\n event.status = \"published\";\n await withUow(async (uow) => {\n await uow.eventRepository.save(event);\n });\n return;\n }\n\n const subscriptionIdsToPublish = getSubscriptionIdsToPublish(\n event,\n callbacksBySubscriptionSlug,\n );\n\n const failuresOrUndefined = await Promise.all(\n subscriptionIdsToPublish.map((subscriptionId) =>\n executeCallback(\n event,\n subscriptionId,\n callbacksBySubscriptionSlug[subscriptionId],\n ),\n ),\n );\n\n const failures = failuresOrUndefined.filter(\n (\n f,\n ): f is {\n subscriptionId: string;\n errorMessage: string;\n stack?: string;\n } => f !== undefined,\n );\n\n const publications: EventPublication[] = [\n ...event.publications,\n {\n publishedAt,\n publishedSubscribers: subscriptionIdsToPublish.map(\n (id) => id as SubscriptionId,\n ),\n ...(failures.length > 0 && { failures }),\n },\n ];\n\n if (failures.length === 0) {\n event.status = \"published\";\n } else {\n const wasMaxNumberOfErrorsReached = publications.length >= maxRetries;\n event.status = wasMaxNumberOfErrorsReached\n ? \"quarantined\"\n : \"failed-but-will-retry\";\n }\n\n event.publications = publications;\n\n await withUow(async (uow) => {\n await uow.eventRepository.save(event);\n });\n },\n\n subscribe: ({ topic, subscriptionId, callBack }) => {\n if (!subscriptions[topic]) {\n subscriptions[topic] = {};\n }\n\n const subscriptionsForTopic = subscriptions[topic];\n if (subscriptionsForTopic) {\n subscriptionsForTopic[subscriptionId] = callBack as (\n event: GenericEvent<string, unknown, DefaultContext>,\n ) => Promise<void>;\n }\n },\n };\n\n /**\n * Identity function for type inference when defining subscription maps.\n * Ensures all topics are covered and handlers have correct payload types.\n *\n * @example\n * ```typescript\n * const subscriptions = defineSubscriptions({\n * OrderCreated: [{ subscriptionId: \"notify\", handler: async (e) => {...} }],\n * OrderShipped: [], // Required even if empty\n * });\n * ```\n */\n const defineSubscriptions = (\n subscriptions: TopicSubscriptions<Event>,\n ): TopicSubscriptions<Event> => subscriptions;\n\n /**\n * Subscribe all handlers from a topic subscription map to this event bus.\n *\n * @example\n * ```typescript\n * const subscriptions = defineSubscriptions({...});\n * subscribeAll(subscriptions);\n * ```\n */\n const subscribeAll = (subscriptions: TopicSubscriptions<Event>): void => {\n subscribeByTopic(eventBus, subscriptions);\n };\n\n /**\n * Subscribe a global handler to multiple topics with optional filtering.\n *\n * @example\n * ```typescript\n * subscribeGlobal(subscriptions, {\n * subscriptionId: \"audit-log\",\n * handler: async (event) => auditLog.record(event),\n * filter: { exclude: [\"NotificationAdded\"] },\n * });\n * ```\n */\n const subscribeGlobal = (\n subscriptions: TopicSubscriptions<Event>,\n config: GlobalSubscriberConfig<Event>,\n ): void => {\n subscribeGlobalToTopics(eventBus, subscriptions, config);\n };\n\n return {\n eventBus,\n createNewEvent,\n defineSubscriptions,\n subscribeAll,\n subscribeGlobal,\n };\n}\n"],"mappings":"AAAA;AAAA,EAGE;AAAA,OACK;AAOP;AAAA,EAEE;AAAA,EACA;AAAA,OAEK;AAwDA,SAAS,uBAGd,SACA,UAEqE,CAAC,GACtE;AACA,QAAM,aAAa,QAAQ,cAAc;AACzC,QAAM,mBACJ,sBAAsB,UAAU,QAAQ,mBAAmB;AAC7D,QAAM,iBAAiB,mBACnB,mBAAmB;AAAA,IACjB,QAAQ,QAAQ;AAAA,IAChB,YAAY,QAAQ;AAAA,IACpB;AAAA,EACF,CAAC,IACD,mBAA0B;AAAA,IACxB,QAAQ,QAAQ;AAAA,IAChB,YAAY,QAAQ;AAAA,EACtB,CAAC;AACL,QAAM,gBAAgE,CAAC;AAEvE,QAAM,kBAAkB,OACtB,OACA,gBACA,aAKG;AACH,QAAI;AACF,YAAM,SAAS,KAAK;AAAA,IACtB,SAAS,OAAO;AACd,aAAO;AAAA,QACL;AAAA,QACA,cAAc,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,QACnE,OAAO,iBAAiB,QAAQ,MAAM,QAAQ;AAAA,MAChD;AAAA,IACF;AAAA,EACF;AAEA,QAAM,8BAA8B,CAClC,OACA,8BACa;AACb,UAAM,qBAAqB,OAAO,KAAK,yBAAyB;AAEhE,QAAI,MAAM,aAAa,WAAW,KAAK,MAAM,WAAW,gBAAgB;AACtE,aAAO;AAAA,IACT;AAEA,UAAM,kBAAkB,MAAM,aAAa;AAAA,MAAO,CAAC,QAAQ,YACzD,QAAQ,cAAc,OAAO,cAAc,UAAU;AAAA,IACvD;AACA,UAAM,yBAAyB,gBAAgB,YAAY,CAAC,GAAG;AAAA,MAC7D,CAAC,YAAY,QAAQ;AAAA,IACvB;AAEA,WAAO,mBAAmB;AAAA,MAAO,CAAC,OAChC,sBAAsB,SAAS,EAAE;AAAA,IACnC;AAAA,EACF;AAEA,QAAM,WAA4B;AAAA,IAChC,SAAS,OAAO,UAAU;AACxB,YAAM,cAAc,oBAAI,KAAK;AAC7B,YAAM,QAAQ,MAAM;AAEpB,YAAM,8BAA8B,cAAc,KAAK;AAEvD,UAAI,CAAC,6BAA6B;AAChC,cAAM,aAAa,KAAK;AAAA,UACtB;AAAA,UACA,sBAAsB,CAAC;AAAA,QACzB,CAAC;AACD,cAAM,SAAS;AACf,cAAM,QAAQ,OAAO,QAAQ;AAC3B,gBAAM,IAAI,gBAAgB,KAAK,KAAK;AAAA,QACtC,CAAC;AACD;AAAA,MACF;AAEA,YAAM,2BAA2B;AAAA,QAC/B;AAAA,QACA;AAAA,MACF;AAEA,YAAM,sBAAsB,MAAM,QAAQ;AAAA,QACxC,yBAAyB;AAAA,UAAI,CAAC,mBAC5B;AAAA,YACE;AAAA,YACA;AAAA,YACA,4BAA4B,cAAc;AAAA,UAC5C;AAAA,QACF;AAAA,MACF;AAEA,YAAM,WAAW,oBAAoB;AAAA,QACnC,CACE,MAKG,MAAM;AAAA,MACb;AAEA,YAAM,eAAmC;AAAA,QACvC,GAAG,MAAM;AAAA,QACT;AAAA,UACE;AAAA,UACA,sBAAsB,yBAAyB;AAAA,YAC7C,CAAC,OAAO;AAAA,UACV;AAAA,UACA,GAAI,SAAS,SAAS,KAAK,EAAE,SAAS;AAAA,QACxC;AAAA,MACF;AAEA,UAAI,SAAS,WAAW,GAAG;AACzB,cAAM,SAAS;AAAA,MACjB,OAAO;AACL,cAAM,8BAA8B,aAAa,UAAU;AAC3D,cAAM,SAAS,8BACX,gBACA;AAAA,MACN;AAEA,YAAM,eAAe;AAErB,YAAM,QAAQ,OAAO,QAAQ;AAC3B,cAAM,IAAI,gBAAgB,KAAK,KAAK;AAAA,MACtC,CAAC;AAAA,IACH;AAAA,IAEA,WAAW,CAAC,EAAE,OAAO,gBAAgB,SAAS,MAAM;AAClD,UAAI,CAAC,cAAc,KAAK,GAAG;AACzB,sBAAc,KAAK,IAAI,CAAC;AAAA,MAC1B;AAEA,YAAM,wBAAwB,cAAc,KAAK;AACjD,UAAI,uBAAuB;AACzB,8BAAsB,cAAc,IAAI;AAAA,MAG1C;AAAA,IACF;AAAA,EACF;AAcA,QAAM,sBAAsB,CAC1BA,mBAC8BA;AAWhC,QAAM,eAAe,CAACA,mBAAmD;AACvE,qBAAiB,UAAUA,cAAa;AAAA,EAC1C;AAcA,QAAM,kBAAkB,CACtBA,gBACA,WACS;AACT,4BAAwB,UAAUA,gBAAe,MAAM;AAAA,EACzD;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":["subscriptions"]}
@@ -6,6 +6,7 @@ import { EventRepository, WithEventsUow } from '../../ports/EventRepository.cjs'
6
6
  export { createInMemoryEventBus } from './InMemoryEventBus.cjs';
7
7
  export { createInMemoryEventQueries } from './InMemoryEventQueries.cjs';
8
8
  import '../../createNewEvent.cjs';
9
+ import '../../eventDefinitions.cjs';
9
10
  import '../../ports/EventBus.cjs';
10
11
  import '../../subscriptions.cjs';
11
12
 
@@ -6,6 +6,7 @@ import { EventRepository, WithEventsUow } from '../../ports/EventRepository.js';
6
6
  export { createInMemoryEventBus } from './InMemoryEventBus.js';
7
7
  export { createInMemoryEventQueries } from './InMemoryEventQueries.js';
8
8
  import '../../createNewEvent.js';
9
+ import '../../eventDefinitions.js';
9
10
  import '../../ports/EventBus.js';
10
11
  import '../../subscriptions.js';
11
12
 
@@ -41,6 +41,8 @@ const createKyselyEventQueries = (db) => ({
41
41
  (row) => ({
42
42
  ...row,
43
43
  context: row.context ?? void 0,
44
+ flowId: row.flowId ?? void 0,
45
+ causedByEventId: row.causedByEventId ?? void 0,
44
46
  priority: row.priority ?? void 0
45
47
  })
46
48
  );