@l-etabli/events 0.1.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 (115) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +16 -0
  3. package/dist/adapters/in-memory/InMemoryEventBus.cjs +128 -0
  4. package/dist/adapters/in-memory/InMemoryEventBus.cjs.map +1 -0
  5. package/dist/adapters/in-memory/InMemoryEventBus.d.cts +16 -0
  6. package/dist/adapters/in-memory/InMemoryEventBus.d.ts +16 -0
  7. package/dist/adapters/in-memory/InMemoryEventBus.mjs +104 -0
  8. package/dist/adapters/in-memory/InMemoryEventBus.mjs.map +1 -0
  9. package/dist/adapters/in-memory/InMemoryEventQueries.cjs +44 -0
  10. package/dist/adapters/in-memory/InMemoryEventQueries.cjs.map +1 -0
  11. package/dist/adapters/in-memory/InMemoryEventQueries.d.cts +10 -0
  12. package/dist/adapters/in-memory/InMemoryEventQueries.d.ts +10 -0
  13. package/dist/adapters/in-memory/InMemoryEventQueries.mjs +20 -0
  14. package/dist/adapters/in-memory/InMemoryEventQueries.mjs.map +1 -0
  15. package/dist/adapters/in-memory/InMemoryEventRepository.cjs +68 -0
  16. package/dist/adapters/in-memory/InMemoryEventRepository.cjs.map +1 -0
  17. package/dist/adapters/in-memory/InMemoryEventRepository.d.cts +16 -0
  18. package/dist/adapters/in-memory/InMemoryEventRepository.d.ts +16 -0
  19. package/dist/adapters/in-memory/InMemoryEventRepository.mjs +43 -0
  20. package/dist/adapters/in-memory/InMemoryEventRepository.mjs.map +1 -0
  21. package/dist/adapters/in-memory/index.cjs +43 -0
  22. package/dist/adapters/in-memory/index.cjs.map +1 -0
  23. package/dist/adapters/in-memory/index.d.cts +18 -0
  24. package/dist/adapters/in-memory/index.d.ts +18 -0
  25. package/dist/adapters/in-memory/index.mjs +18 -0
  26. package/dist/adapters/in-memory/index.mjs.map +1 -0
  27. package/dist/adapters/kysely/KyselyEventQueries.cjs +47 -0
  28. package/dist/adapters/kysely/KyselyEventQueries.cjs.map +1 -0
  29. package/dist/adapters/kysely/KyselyEventQueries.d.cts +8 -0
  30. package/dist/adapters/kysely/KyselyEventQueries.d.ts +8 -0
  31. package/dist/adapters/kysely/KyselyEventQueries.mjs +23 -0
  32. package/dist/adapters/kysely/KyselyEventQueries.mjs.map +1 -0
  33. package/dist/adapters/kysely/KyselyEventRepository.cjs +53 -0
  34. package/dist/adapters/kysely/KyselyEventRepository.cjs.map +1 -0
  35. package/dist/adapters/kysely/KyselyEventRepository.d.cts +8 -0
  36. package/dist/adapters/kysely/KyselyEventRepository.d.ts +8 -0
  37. package/dist/adapters/kysely/KyselyEventRepository.mjs +29 -0
  38. package/dist/adapters/kysely/KyselyEventRepository.mjs.map +1 -0
  39. package/dist/adapters/kysely/index.cjs +32 -0
  40. package/dist/adapters/kysely/index.cjs.map +1 -0
  41. package/dist/adapters/kysely/index.d.cts +7 -0
  42. package/dist/adapters/kysely/index.d.ts +7 -0
  43. package/dist/adapters/kysely/index.mjs +7 -0
  44. package/dist/adapters/kysely/index.mjs.map +1 -0
  45. package/dist/adapters/kysely/migration.cjs +38 -0
  46. package/dist/adapters/kysely/migration.cjs.map +1 -0
  47. package/dist/adapters/kysely/migration.d.cts +6 -0
  48. package/dist/adapters/kysely/migration.d.ts +6 -0
  49. package/dist/adapters/kysely/migration.mjs +13 -0
  50. package/dist/adapters/kysely/migration.mjs.map +1 -0
  51. package/dist/adapters/kysely/types.cjs +17 -0
  52. package/dist/adapters/kysely/types.cjs.map +1 -0
  53. package/dist/adapters/kysely/types.d.cts +34 -0
  54. package/dist/adapters/kysely/types.d.ts +34 -0
  55. package/dist/adapters/kysely/types.mjs +1 -0
  56. package/dist/adapters/kysely/types.mjs.map +1 -0
  57. package/dist/createEventCrawler.cjs +102 -0
  58. package/dist/createEventCrawler.cjs.map +1 -0
  59. package/dist/createEventCrawler.d.cts +56 -0
  60. package/dist/createEventCrawler.d.ts +56 -0
  61. package/dist/createEventCrawler.mjs +78 -0
  62. package/dist/createEventCrawler.mjs.map +1 -0
  63. package/dist/createNewEvent.cjs +43 -0
  64. package/dist/createNewEvent.cjs.map +1 -0
  65. package/dist/createNewEvent.d.cts +61 -0
  66. package/dist/createNewEvent.d.ts +61 -0
  67. package/dist/createNewEvent.mjs +19 -0
  68. package/dist/createNewEvent.mjs.map +1 -0
  69. package/dist/index.cjs +27 -0
  70. package/dist/index.cjs.map +1 -0
  71. package/dist/index.d.cts +10 -0
  72. package/dist/index.d.ts +10 -0
  73. package/dist/index.mjs +4 -0
  74. package/dist/index.mjs.map +1 -0
  75. package/dist/ports/EventBus.cjs +17 -0
  76. package/dist/ports/EventBus.cjs.map +1 -0
  77. package/dist/ports/EventBus.d.cts +35 -0
  78. package/dist/ports/EventBus.d.ts +35 -0
  79. package/dist/ports/EventBus.mjs +1 -0
  80. package/dist/ports/EventBus.mjs.map +1 -0
  81. package/dist/ports/EventQueries.cjs +17 -0
  82. package/dist/ports/EventQueries.cjs.map +1 -0
  83. package/dist/ports/EventQueries.d.cts +24 -0
  84. package/dist/ports/EventQueries.d.ts +24 -0
  85. package/dist/ports/EventQueries.mjs +1 -0
  86. package/dist/ports/EventQueries.mjs.map +1 -0
  87. package/dist/ports/EventRepository.cjs +17 -0
  88. package/dist/ports/EventRepository.cjs.map +1 -0
  89. package/dist/ports/EventRepository.d.cts +43 -0
  90. package/dist/ports/EventRepository.d.ts +43 -0
  91. package/dist/ports/EventRepository.mjs +1 -0
  92. package/dist/ports/EventRepository.mjs.map +1 -0
  93. package/dist/types.cjs +17 -0
  94. package/dist/types.cjs.map +1 -0
  95. package/dist/types.d.cts +84 -0
  96. package/dist/types.d.ts +84 -0
  97. package/dist/types.mjs +1 -0
  98. package/dist/types.mjs.map +1 -0
  99. package/package.json +68 -0
  100. package/src/adapters/in-memory/InMemoryEventBus.ts +165 -0
  101. package/src/adapters/in-memory/InMemoryEventQueries.ts +30 -0
  102. package/src/adapters/in-memory/InMemoryEventRepository.ts +61 -0
  103. package/src/adapters/in-memory/index.ts +19 -0
  104. package/src/adapters/kysely/KyselyEventQueries.ts +35 -0
  105. package/src/adapters/kysely/KyselyEventRepository.ts +44 -0
  106. package/src/adapters/kysely/index.ts +3 -0
  107. package/src/adapters/kysely/migration.ts +39 -0
  108. package/src/adapters/kysely/types.ts +37 -0
  109. package/src/createEventCrawler.ts +139 -0
  110. package/src/createNewEvent.ts +87 -0
  111. package/src/index.ts +7 -0
  112. package/src/ports/EventBus.ts +37 -0
  113. package/src/ports/EventQueries.ts +25 -0
  114. package/src/ports/EventRepository.ts +49 -0
  115. package/src/types.ts +100 -0
@@ -0,0 +1,35 @@
1
+ import { GenericEvent, DefaultContext, SubscriptionId } from '../types.cjs';
2
+
3
+ /**
4
+ * Event bus for publishing events to subscribers.
5
+ * Handles delivery, failure tracking, and retry logic.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * eventBus.subscribe({
10
+ * topic: "OrderPlaced",
11
+ * subscriptionId: "send-confirmation-email",
12
+ * callBack: async (event) => {
13
+ * await emailService.sendOrderConfirmation(event.payload);
14
+ * },
15
+ * });
16
+ * ```
17
+ */
18
+ type EventBus<Event extends GenericEvent<string, unknown, DefaultContext>> = {
19
+ /**
20
+ * Publish an event to all subscribers of its topic.
21
+ * Updates event status and records publication results.
22
+ */
23
+ publish: (event: Event) => Promise<void>;
24
+ /**
25
+ * Register a subscriber for a specific topic.
26
+ * The subscriptionId must be unique per topic and is used for retry tracking.
27
+ */
28
+ subscribe: <Event extends GenericEvent<string, unknown, DefaultContext>>(params: {
29
+ topic: Event["topic"];
30
+ subscriptionId: SubscriptionId;
31
+ callBack: (e: Event) => Promise<void>;
32
+ }) => void;
33
+ };
34
+
35
+ export type { EventBus };
@@ -0,0 +1,35 @@
1
+ import { GenericEvent, DefaultContext, SubscriptionId } from '../types.js';
2
+
3
+ /**
4
+ * Event bus for publishing events to subscribers.
5
+ * Handles delivery, failure tracking, and retry logic.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * eventBus.subscribe({
10
+ * topic: "OrderPlaced",
11
+ * subscriptionId: "send-confirmation-email",
12
+ * callBack: async (event) => {
13
+ * await emailService.sendOrderConfirmation(event.payload);
14
+ * },
15
+ * });
16
+ * ```
17
+ */
18
+ type EventBus<Event extends GenericEvent<string, unknown, DefaultContext>> = {
19
+ /**
20
+ * Publish an event to all subscribers of its topic.
21
+ * Updates event status and records publication results.
22
+ */
23
+ publish: (event: Event) => Promise<void>;
24
+ /**
25
+ * Register a subscriber for a specific topic.
26
+ * The subscriptionId must be unique per topic and is used for retry tracking.
27
+ */
28
+ subscribe: <Event extends GenericEvent<string, unknown, DefaultContext>>(params: {
29
+ topic: Event["topic"];
30
+ subscriptionId: SubscriptionId;
31
+ callBack: (e: Event) => Promise<void>;
32
+ }) => void;
33
+ };
34
+
35
+ export type { EventBus };
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=EventBus.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+ var EventQueries_exports = {};
16
+ module.exports = __toCommonJS(EventQueries_exports);
17
+ //# sourceMappingURL=EventQueries.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/ports/EventQueries.ts"],"sourcesContent":["import type { DefaultContext, EventStatus, GenericEvent } from \"../types.ts\";\n\n/** Parameters for querying events. */\ntype GetEventsParams = {\n filters: {\n /** Filter by event status (e.g., [\"never-published\", \"failed-but-will-retry\"]). */\n statuses: EventStatus[];\n /** Optional context filter for multi-tenant scenarios. */\n context?: Partial<Record<string, string>>;\n };\n /** Maximum number of events to return. */\n limit: number;\n};\n\n/**\n * Query interface for reading events.\n * Used by the event crawler to fetch events for processing.\n * Implement this to query events from your database.\n */\nexport type EventQueries<\n Event extends GenericEvent<string, unknown, DefaultContext>,\n> = {\n /** Fetch events matching the given filters. */\n getEvents: (params: GetEventsParams) => Promise<Event[]>;\n};\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -0,0 +1,24 @@
1
+ import { GenericEvent, DefaultContext, EventStatus } from '../types.cjs';
2
+
3
+ /** Parameters for querying events. */
4
+ type GetEventsParams = {
5
+ filters: {
6
+ /** Filter by event status (e.g., ["never-published", "failed-but-will-retry"]). */
7
+ statuses: EventStatus[];
8
+ /** Optional context filter for multi-tenant scenarios. */
9
+ context?: Partial<Record<string, string>>;
10
+ };
11
+ /** Maximum number of events to return. */
12
+ limit: number;
13
+ };
14
+ /**
15
+ * Query interface for reading events.
16
+ * Used by the event crawler to fetch events for processing.
17
+ * Implement this to query events from your database.
18
+ */
19
+ type EventQueries<Event extends GenericEvent<string, unknown, DefaultContext>> = {
20
+ /** Fetch events matching the given filters. */
21
+ getEvents: (params: GetEventsParams) => Promise<Event[]>;
22
+ };
23
+
24
+ export type { EventQueries };
@@ -0,0 +1,24 @@
1
+ import { GenericEvent, DefaultContext, EventStatus } from '../types.js';
2
+
3
+ /** Parameters for querying events. */
4
+ type GetEventsParams = {
5
+ filters: {
6
+ /** Filter by event status (e.g., ["never-published", "failed-but-will-retry"]). */
7
+ statuses: EventStatus[];
8
+ /** Optional context filter for multi-tenant scenarios. */
9
+ context?: Partial<Record<string, string>>;
10
+ };
11
+ /** Maximum number of events to return. */
12
+ limit: number;
13
+ };
14
+ /**
15
+ * Query interface for reading events.
16
+ * Used by the event crawler to fetch events for processing.
17
+ * Implement this to query events from your database.
18
+ */
19
+ type EventQueries<Event extends GenericEvent<string, unknown, DefaultContext>> = {
20
+ /** Fetch events matching the given filters. */
21
+ getEvents: (params: GetEventsParams) => Promise<Event[]>;
22
+ };
23
+
24
+ export type { EventQueries };
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=EventQueries.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+ var EventRepository_exports = {};
16
+ module.exports = __toCommonJS(EventRepository_exports);
17
+ //# sourceMappingURL=EventRepository.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/ports/EventRepository.ts"],"sourcesContent":["import type { DefaultContext, GenericEvent } from \"../types.ts\";\n\n/**\n * Repository interface for persisting events.\n * Implement this to store events in your database (e.g., PostgreSQL, MongoDB).\n * Events should be saved in the same transaction as your domain changes.\n */\nexport type EventRepository<\n Event extends GenericEvent<string, unknown, DefaultContext>,\n> = {\n /** Persist a single event (typically after publication status update). */\n save: (event: Event) => Promise<void>;\n /** Persist multiple new events in a batch. */\n saveNewEventsBatch: (events: Event[]) => Promise<void>;\n /** Mark events as \"in-process\" before publishing (prevents duplicate processing). */\n markEventsAsInProcess: (events: Event[]) => Promise<void>;\n};\n\n/**\n * Unit of work containing the event repository.\n * Extend this with your own repositories for transactional consistency.\n */\nexport type EventsUnitOfWork<\n Event extends GenericEvent<string, unknown, DefaultContext>,\n> = {\n eventRepository: EventRepository<Event>;\n};\n\n/**\n * Higher-order function that provides a unit of work for transactional operations.\n * Your implementation should handle transaction begin/commit/rollback.\n *\n * @example\n * ```typescript\n * const withUow: WithEventsUow<MyEvent> = async (fn) => {\n * const tx = await db.beginTransaction();\n * try {\n * await fn({ eventRepository: createEventRepo(tx) });\n * await tx.commit();\n * } catch (e) {\n * await tx.rollback();\n * throw e;\n * }\n * };\n * ```\n */\nexport type WithEventsUow<\n Event extends GenericEvent<string, unknown, DefaultContext>,\n> = (fn: (uow: EventsUnitOfWork<Event>) => Promise<void>) => Promise<void>;\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -0,0 +1,43 @@
1
+ import { GenericEvent, DefaultContext } from '../types.cjs';
2
+
3
+ /**
4
+ * Repository interface for persisting events.
5
+ * Implement this to store events in your database (e.g., PostgreSQL, MongoDB).
6
+ * Events should be saved in the same transaction as your domain changes.
7
+ */
8
+ type EventRepository<Event extends GenericEvent<string, unknown, DefaultContext>> = {
9
+ /** Persist a single event (typically after publication status update). */
10
+ save: (event: Event) => Promise<void>;
11
+ /** Persist multiple new events in a batch. */
12
+ saveNewEventsBatch: (events: Event[]) => Promise<void>;
13
+ /** Mark events as "in-process" before publishing (prevents duplicate processing). */
14
+ markEventsAsInProcess: (events: Event[]) => Promise<void>;
15
+ };
16
+ /**
17
+ * Unit of work containing the event repository.
18
+ * Extend this with your own repositories for transactional consistency.
19
+ */
20
+ type EventsUnitOfWork<Event extends GenericEvent<string, unknown, DefaultContext>> = {
21
+ eventRepository: EventRepository<Event>;
22
+ };
23
+ /**
24
+ * Higher-order function that provides a unit of work for transactional operations.
25
+ * Your implementation should handle transaction begin/commit/rollback.
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * const withUow: WithEventsUow<MyEvent> = async (fn) => {
30
+ * const tx = await db.beginTransaction();
31
+ * try {
32
+ * await fn({ eventRepository: createEventRepo(tx) });
33
+ * await tx.commit();
34
+ * } catch (e) {
35
+ * await tx.rollback();
36
+ * throw e;
37
+ * }
38
+ * };
39
+ * ```
40
+ */
41
+ type WithEventsUow<Event extends GenericEvent<string, unknown, DefaultContext>> = (fn: (uow: EventsUnitOfWork<Event>) => Promise<void>) => Promise<void>;
42
+
43
+ export type { EventRepository, EventsUnitOfWork, WithEventsUow };
@@ -0,0 +1,43 @@
1
+ import { GenericEvent, DefaultContext } from '../types.js';
2
+
3
+ /**
4
+ * Repository interface for persisting events.
5
+ * Implement this to store events in your database (e.g., PostgreSQL, MongoDB).
6
+ * Events should be saved in the same transaction as your domain changes.
7
+ */
8
+ type EventRepository<Event extends GenericEvent<string, unknown, DefaultContext>> = {
9
+ /** Persist a single event (typically after publication status update). */
10
+ save: (event: Event) => Promise<void>;
11
+ /** Persist multiple new events in a batch. */
12
+ saveNewEventsBatch: (events: Event[]) => Promise<void>;
13
+ /** Mark events as "in-process" before publishing (prevents duplicate processing). */
14
+ markEventsAsInProcess: (events: Event[]) => Promise<void>;
15
+ };
16
+ /**
17
+ * Unit of work containing the event repository.
18
+ * Extend this with your own repositories for transactional consistency.
19
+ */
20
+ type EventsUnitOfWork<Event extends GenericEvent<string, unknown, DefaultContext>> = {
21
+ eventRepository: EventRepository<Event>;
22
+ };
23
+ /**
24
+ * Higher-order function that provides a unit of work for transactional operations.
25
+ * Your implementation should handle transaction begin/commit/rollback.
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * const withUow: WithEventsUow<MyEvent> = async (fn) => {
30
+ * const tx = await db.beginTransaction();
31
+ * try {
32
+ * await fn({ eventRepository: createEventRepo(tx) });
33
+ * await tx.commit();
34
+ * } catch (e) {
35
+ * await tx.rollback();
36
+ * throw e;
37
+ * }
38
+ * };
39
+ * ```
40
+ */
41
+ type WithEventsUow<Event extends GenericEvent<string, unknown, DefaultContext>> = (fn: (uow: EventsUnitOfWork<Event>) => Promise<void>) => Promise<void>;
42
+
43
+ export type { EventRepository, EventsUnitOfWork, WithEventsUow };
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=EventRepository.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/dist/types.cjs ADDED
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+ var types_exports = {};
16
+ module.exports = __toCommonJS(types_exports);
17
+ //# sourceMappingURL=types.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["/**\n * Branded type helper for nominal typing.\n * Adds a phantom type property to distinguish between structurally identical types.\n */\nexport type Flavor<T, FlavorT> = T & {\n _type?: FlavorT;\n};\n\n/** Unique identifier for an event subscription. */\nexport type SubscriptionId = Flavor<string, \"SubscriptionId\">;\n\n/** Unique identifier for a user who triggered an event. */\nexport type UserId = Flavor<string, \"UserId\">;\n\n/** Unique identifier for an event. */\nexport type EventId = Flavor<string, \"EventId\">;\n\n/**\n * Records a subscription failure during event publication.\n * Contains the subscription that failed and error details for debugging.\n */\nexport type EventFailure = {\n subscriptionId: SubscriptionId;\n errorMessage: string;\n /** Stack trace captured when the subscription callback threw. */\n stack?: string;\n};\n\n/**\n * Records a single publication attempt for an event.\n * Tracks which subscribers were notified and any failures that occurred.\n */\nexport type EventPublication = {\n publishedAt: Date;\n /** All subscription IDs that were attempted in this publication. */\n publishedSubscribers: SubscriptionId[];\n /** Subscriptions that failed during this publication attempt. */\n failures: EventFailure[];\n};\n\n/**\n * Event lifecycle status.\n * - `never-published`: New event, not yet processed by crawler\n * - `in-process`: Currently being published by crawler\n * - `published`: Successfully delivered to all subscribers\n * - `failed-but-will-retry`: Some subscribers failed, will retry\n * - `quarantined`: Exceeded max retries, requires manual intervention\n * - `to-republish`: Force republish to all subscribers (manual trigger)\n */\nexport type EventStatus =\n | \"never-published\"\n | \"to-republish\"\n | \"in-process\"\n | \"published\"\n | \"failed-but-will-retry\"\n | \"quarantined\";\n\n/** Context type constraint - must be a string record or undefined. */\nexport type DefaultContext = Record<string, string> | undefined;\n\n/**\n * Generic event type for the outbox pattern.\n * Events are persisted in the same transaction as domain changes,\n * then asynchronously published to subscribers.\n *\n * @typeParam T - Event topic/type string literal\n * @typeParam P - Event payload type\n * @typeParam C - Optional context for filtering (e.g., tenant ID)\n *\n * @example\n * ```typescript\n * type MyEvents =\n * | GenericEvent<\"UserCreated\", { userId: string; email: string }>\n * | GenericEvent<\"OrderPlaced\", { orderId: string }, { tenantId: string }>;\n * ```\n */\nexport type GenericEvent<\n T extends string,\n P,\n C extends DefaultContext = undefined,\n> = {\n /** Unique event identifier. */\n id: EventId;\n /** When the event occurred in the domain. */\n occurredAt: Date;\n /** Event type/topic for routing to subscribers. */\n topic: T;\n /** Event-specific data. */\n payload: P;\n /** Current lifecycle status. */\n status: EventStatus;\n /** History of publication attempts. */\n publications: EventPublication[];\n /** User who triggered the action that created this event. */\n triggeredByUserId: UserId;\n /** Optional priority for processing order (not yet implemented in crawler). */\n priority?: number;\n /** Optional context for filtering events (e.g., by tenant). */\n context?: C;\n};\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Branded type helper for nominal typing.
3
+ * Adds a phantom type property to distinguish between structurally identical types.
4
+ */
5
+ type Flavor<T, FlavorT> = T & {
6
+ _type?: FlavorT;
7
+ };
8
+ /** Unique identifier for an event subscription. */
9
+ type SubscriptionId = Flavor<string, "SubscriptionId">;
10
+ /** Unique identifier for a user who triggered an event. */
11
+ type UserId = Flavor<string, "UserId">;
12
+ /** Unique identifier for an event. */
13
+ type EventId = Flavor<string, "EventId">;
14
+ /**
15
+ * Records a subscription failure during event publication.
16
+ * Contains the subscription that failed and error details for debugging.
17
+ */
18
+ type EventFailure = {
19
+ subscriptionId: SubscriptionId;
20
+ errorMessage: string;
21
+ /** Stack trace captured when the subscription callback threw. */
22
+ stack?: string;
23
+ };
24
+ /**
25
+ * Records a single publication attempt for an event.
26
+ * Tracks which subscribers were notified and any failures that occurred.
27
+ */
28
+ type EventPublication = {
29
+ publishedAt: Date;
30
+ /** All subscription IDs that were attempted in this publication. */
31
+ publishedSubscribers: SubscriptionId[];
32
+ /** Subscriptions that failed during this publication attempt. */
33
+ failures: EventFailure[];
34
+ };
35
+ /**
36
+ * Event lifecycle status.
37
+ * - `never-published`: New event, not yet processed by crawler
38
+ * - `in-process`: Currently being published by crawler
39
+ * - `published`: Successfully delivered to all subscribers
40
+ * - `failed-but-will-retry`: Some subscribers failed, will retry
41
+ * - `quarantined`: Exceeded max retries, requires manual intervention
42
+ * - `to-republish`: Force republish to all subscribers (manual trigger)
43
+ */
44
+ type EventStatus = "never-published" | "to-republish" | "in-process" | "published" | "failed-but-will-retry" | "quarantined";
45
+ /** Context type constraint - must be a string record or undefined. */
46
+ type DefaultContext = Record<string, string> | undefined;
47
+ /**
48
+ * Generic event type for the outbox pattern.
49
+ * Events are persisted in the same transaction as domain changes,
50
+ * then asynchronously published to subscribers.
51
+ *
52
+ * @typeParam T - Event topic/type string literal
53
+ * @typeParam P - Event payload type
54
+ * @typeParam C - Optional context for filtering (e.g., tenant ID)
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * type MyEvents =
59
+ * | GenericEvent<"UserCreated", { userId: string; email: string }>
60
+ * | GenericEvent<"OrderPlaced", { orderId: string }, { tenantId: string }>;
61
+ * ```
62
+ */
63
+ type GenericEvent<T extends string, P, C extends DefaultContext = undefined> = {
64
+ /** Unique event identifier. */
65
+ id: EventId;
66
+ /** When the event occurred in the domain. */
67
+ occurredAt: Date;
68
+ /** Event type/topic for routing to subscribers. */
69
+ topic: T;
70
+ /** Event-specific data. */
71
+ payload: P;
72
+ /** Current lifecycle status. */
73
+ status: EventStatus;
74
+ /** History of publication attempts. */
75
+ publications: EventPublication[];
76
+ /** User who triggered the action that created this event. */
77
+ triggeredByUserId: UserId;
78
+ /** Optional priority for processing order (not yet implemented in crawler). */
79
+ priority?: number;
80
+ /** Optional context for filtering events (e.g., by tenant). */
81
+ context?: C;
82
+ };
83
+
84
+ export type { DefaultContext, EventFailure, EventId, EventPublication, EventStatus, Flavor, GenericEvent, SubscriptionId, UserId };
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Branded type helper for nominal typing.
3
+ * Adds a phantom type property to distinguish between structurally identical types.
4
+ */
5
+ type Flavor<T, FlavorT> = T & {
6
+ _type?: FlavorT;
7
+ };
8
+ /** Unique identifier for an event subscription. */
9
+ type SubscriptionId = Flavor<string, "SubscriptionId">;
10
+ /** Unique identifier for a user who triggered an event. */
11
+ type UserId = Flavor<string, "UserId">;
12
+ /** Unique identifier for an event. */
13
+ type EventId = Flavor<string, "EventId">;
14
+ /**
15
+ * Records a subscription failure during event publication.
16
+ * Contains the subscription that failed and error details for debugging.
17
+ */
18
+ type EventFailure = {
19
+ subscriptionId: SubscriptionId;
20
+ errorMessage: string;
21
+ /** Stack trace captured when the subscription callback threw. */
22
+ stack?: string;
23
+ };
24
+ /**
25
+ * Records a single publication attempt for an event.
26
+ * Tracks which subscribers were notified and any failures that occurred.
27
+ */
28
+ type EventPublication = {
29
+ publishedAt: Date;
30
+ /** All subscription IDs that were attempted in this publication. */
31
+ publishedSubscribers: SubscriptionId[];
32
+ /** Subscriptions that failed during this publication attempt. */
33
+ failures: EventFailure[];
34
+ };
35
+ /**
36
+ * Event lifecycle status.
37
+ * - `never-published`: New event, not yet processed by crawler
38
+ * - `in-process`: Currently being published by crawler
39
+ * - `published`: Successfully delivered to all subscribers
40
+ * - `failed-but-will-retry`: Some subscribers failed, will retry
41
+ * - `quarantined`: Exceeded max retries, requires manual intervention
42
+ * - `to-republish`: Force republish to all subscribers (manual trigger)
43
+ */
44
+ type EventStatus = "never-published" | "to-republish" | "in-process" | "published" | "failed-but-will-retry" | "quarantined";
45
+ /** Context type constraint - must be a string record or undefined. */
46
+ type DefaultContext = Record<string, string> | undefined;
47
+ /**
48
+ * Generic event type for the outbox pattern.
49
+ * Events are persisted in the same transaction as domain changes,
50
+ * then asynchronously published to subscribers.
51
+ *
52
+ * @typeParam T - Event topic/type string literal
53
+ * @typeParam P - Event payload type
54
+ * @typeParam C - Optional context for filtering (e.g., tenant ID)
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * type MyEvents =
59
+ * | GenericEvent<"UserCreated", { userId: string; email: string }>
60
+ * | GenericEvent<"OrderPlaced", { orderId: string }, { tenantId: string }>;
61
+ * ```
62
+ */
63
+ type GenericEvent<T extends string, P, C extends DefaultContext = undefined> = {
64
+ /** Unique event identifier. */
65
+ id: EventId;
66
+ /** When the event occurred in the domain. */
67
+ occurredAt: Date;
68
+ /** Event type/topic for routing to subscribers. */
69
+ topic: T;
70
+ /** Event-specific data. */
71
+ payload: P;
72
+ /** Current lifecycle status. */
73
+ status: EventStatus;
74
+ /** History of publication attempts. */
75
+ publications: EventPublication[];
76
+ /** User who triggered the action that created this event. */
77
+ triggeredByUserId: UserId;
78
+ /** Optional priority for processing order (not yet implemented in crawler). */
79
+ priority?: number;
80
+ /** Optional context for filtering events (e.g., by tenant). */
81
+ context?: C;
82
+ };
83
+
84
+ export type { DefaultContext, EventFailure, EventId, EventPublication, EventStatus, Flavor, GenericEvent, SubscriptionId, UserId };
package/dist/types.mjs ADDED
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=types.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@l-etabli/events",
3
+ "description": "The purpose of this repositiory is to make it easy to setup event driven architecture using outbox pattern",
4
+ "module": "src/index.ts",
5
+ "type": "module",
6
+ "version": "0.1.0",
7
+ "main": "./dist/index.mjs",
8
+ "types": "./dist/index.d.ts",
9
+ "files": [
10
+ "dist",
11
+ "src",
12
+ "LICENSE",
13
+ "README.md"
14
+ ],
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/l-etabli/events.git"
21
+ },
22
+ "homepage": "https://github.com/l-etabli/events#readme",
23
+ "bugs": {
24
+ "url": "https://github.com/l-etabli/events/issues"
25
+ },
26
+ "scripts": {
27
+ "build": "tsup --config tsup.config.ts",
28
+ "check": "biome check",
29
+ "check:fix": "biome check --fix --no-errors-on-unmatched --files-ignore-unknown=true",
30
+ "test": "bun test",
31
+ "typecheck": "tsc --noEmit",
32
+ "fullcheck": "bun run check:fix && bun run typecheck && bun test --bail tests/ --exclude '**/kyselyAdapter.test.ts'",
33
+ "release": "semantic-release"
34
+ },
35
+ "devDependencies": {
36
+ "@biomejs/biome": "^2.2.5",
37
+ "@commitlint/cli": "^20.1.0",
38
+ "@commitlint/config-conventional": "^20.0.0",
39
+ "@types/bun": "latest",
40
+ "@types/pg": "^8.16.0",
41
+ "kysely": "^0.28.2",
42
+ "lefthook": "^1.13.6",
43
+ "pg": "^8.16.3",
44
+ "semantic-release": "^24.2.9",
45
+ "tsup": "^8.5.0",
46
+ "typescript": "^5.9.3"
47
+ },
48
+ "exports": {
49
+ ".": {
50
+ "types": "./dist/index.d.ts",
51
+ "import": "./dist/index.mjs",
52
+ "require": "./dist/index.cjs"
53
+ },
54
+ "./kysely": {
55
+ "types": "./dist/adapters/kysely/index.d.ts",
56
+ "import": "./dist/adapters/kysely/index.mjs",
57
+ "require": "./dist/adapters/kysely/index.cjs"
58
+ }
59
+ },
60
+ "peerDependencies": {
61
+ "kysely": "latest"
62
+ },
63
+ "peerDependenciesMeta": {
64
+ "kysely": {
65
+ "optional": true
66
+ }
67
+ }
68
+ }