@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,102 @@
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 __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var createEventCrawler_exports = {};
20
+ __export(createEventCrawler_exports, {
21
+ createEventCrawler: () => createEventCrawler
22
+ });
23
+ module.exports = __toCommonJS(createEventCrawler_exports);
24
+ const splitIntoChunks = (array, chunkSize) => {
25
+ const chunks = [];
26
+ for (let i = 0; i < array.length; i += chunkSize) {
27
+ chunks.push(array.slice(i, i + chunkSize));
28
+ }
29
+ return chunks;
30
+ };
31
+ const createEventCrawler = ({
32
+ withUow,
33
+ eventQueries,
34
+ eventBus,
35
+ options = {}
36
+ }) => {
37
+ const batchSize = options.batchSize ?? 100;
38
+ const maxParallelProcessing = options.maxParallelProcessing ?? 1;
39
+ const newEventsIntervalMs = options.newEventsIntervalMs ?? 1e4;
40
+ const failedEventsIntervalMs = options.failedEventsIntervalMs ?? 6e4;
41
+ const publishEventsInParallel = async (events) => {
42
+ const eventChunks = splitIntoChunks(events, maxParallelProcessing);
43
+ for (const chunk of eventChunks) {
44
+ await Promise.all(chunk.map((event) => eventBus.publish(event)));
45
+ }
46
+ };
47
+ const processNewEvents = async () => {
48
+ const events = await eventQueries.getEvents({
49
+ filters: { statuses: ["never-published"] },
50
+ limit: batchSize
51
+ });
52
+ if (events.length === 0) return;
53
+ await withUow(async (uow) => {
54
+ await uow.eventRepository.markEventsAsInProcess(events);
55
+ });
56
+ await publishEventsInParallel(events);
57
+ };
58
+ const retryFailedEvents = async () => {
59
+ const events = await eventQueries.getEvents({
60
+ filters: { statuses: ["to-republish", "failed-but-will-retry"] },
61
+ limit: batchSize
62
+ });
63
+ if (events.length === 0) return;
64
+ await publishEventsInParallel(events);
65
+ };
66
+ const start = () => {
67
+ const scheduleProcessNewEvents = () => {
68
+ setTimeout(async () => {
69
+ try {
70
+ await processNewEvents();
71
+ } catch (error) {
72
+ console.error("Error processing new events:", error);
73
+ } finally {
74
+ scheduleProcessNewEvents();
75
+ }
76
+ }, newEventsIntervalMs);
77
+ };
78
+ const scheduleRetryFailedEvents = () => {
79
+ setTimeout(async () => {
80
+ try {
81
+ await retryFailedEvents();
82
+ } catch (error) {
83
+ console.error("Error retrying failed events:", error);
84
+ } finally {
85
+ scheduleRetryFailedEvents();
86
+ }
87
+ }, failedEventsIntervalMs);
88
+ };
89
+ scheduleProcessNewEvents();
90
+ scheduleRetryFailedEvents();
91
+ };
92
+ return {
93
+ processNewEvents,
94
+ retryFailedEvents,
95
+ start
96
+ };
97
+ };
98
+ // Annotate the CommonJS export names for ESM import in node:
99
+ 0 && (module.exports = {
100
+ createEventCrawler
101
+ });
102
+ //# sourceMappingURL=createEventCrawler.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/createEventCrawler.ts"],"sourcesContent":["import type { EventBus } from \"./ports/EventBus.ts\";\nimport type { EventQueries } from \"./ports/EventQueries.ts\";\nimport type { WithEventsUow } from \"./ports/EventRepository.ts\";\nimport type { DefaultContext, GenericEvent } from \"./types.ts\";\n\n/** Configuration options for the event crawler. */\ntype CreateEventCrawlerOptions = {\n /** Max events to fetch per batch (default: 100). */\n batchSize?: number;\n /** Max events to publish in parallel (default: 1). */\n maxParallelProcessing?: number;\n /** Interval for processing new events in ms (default: 10000). */\n newEventsIntervalMs?: number;\n /** Interval for retrying failed events in ms (default: 60000). */\n failedEventsIntervalMs?: number;\n};\n\nconst splitIntoChunks = <T>(array: T[], chunkSize: number): T[][] => {\n const chunks: T[][] = [];\n for (let i = 0; i < array.length; i += chunkSize) {\n chunks.push(array.slice(i, i + chunkSize));\n }\n return chunks;\n};\n\n/**\n * Creates a background event crawler that processes and publishes events.\n *\n * The crawler runs two loops:\n * 1. Process new events: polls for \"never-published\" events and publishes them\n * 2. Retry failed events: polls for failed events and retries them\n *\n * @returns Object with:\n * - `start()`: Start the background polling loops\n * - `processNewEvents()`: Manually trigger new event processing\n * - `retryFailedEvents()`: Manually trigger failed event retry\n *\n * @example\n * ```typescript\n * const crawler = createEventCrawler({\n * withUow,\n * eventQueries,\n * eventBus,\n * options: { batchSize: 50, newEventsIntervalMs: 5000 },\n * });\n *\n * // Start background processing\n * crawler.start();\n *\n * // Or trigger manually (useful for testing)\n * await crawler.processNewEvents();\n * ```\n */\nexport const createEventCrawler = <\n Event extends GenericEvent<string, unknown, DefaultContext>,\n>({\n withUow,\n eventQueries,\n eventBus,\n options = {},\n}: {\n withUow: WithEventsUow<Event>;\n eventQueries: EventQueries<Event>;\n eventBus: EventBus<Event>;\n options?: CreateEventCrawlerOptions;\n}) => {\n const batchSize = options.batchSize ?? 100;\n const maxParallelProcessing = options.maxParallelProcessing ?? 1;\n const newEventsIntervalMs = options.newEventsIntervalMs ?? 10_000;\n const failedEventsIntervalMs = options.failedEventsIntervalMs ?? 60_000;\n\n const publishEventsInParallel = async (events: Event[]) => {\n const eventChunks = splitIntoChunks(events, maxParallelProcessing);\n for (const chunk of eventChunks) {\n await Promise.all(chunk.map((event) => eventBus.publish(event)));\n }\n };\n\n const processNewEvents = async (): Promise<void> => {\n const events = await eventQueries.getEvents({\n filters: { statuses: [\"never-published\"] },\n limit: batchSize,\n });\n\n if (events.length === 0) return;\n\n await withUow(async (uow) => {\n await uow.eventRepository.markEventsAsInProcess(events);\n });\n\n await publishEventsInParallel(events);\n };\n\n const retryFailedEvents = async (): Promise<void> => {\n const events = await eventQueries.getEvents({\n filters: { statuses: [\"to-republish\", \"failed-but-will-retry\"] },\n limit: batchSize,\n });\n\n if (events.length === 0) return;\n\n await publishEventsInParallel(events);\n };\n\n const start = () => {\n const scheduleProcessNewEvents = () => {\n setTimeout(async () => {\n try {\n await processNewEvents();\n } catch (error) {\n console.error(\"Error processing new events:\", error);\n } finally {\n scheduleProcessNewEvents();\n }\n }, newEventsIntervalMs);\n };\n\n const scheduleRetryFailedEvents = () => {\n setTimeout(async () => {\n try {\n await retryFailedEvents();\n } catch (error) {\n console.error(\"Error retrying failed events:\", error);\n } finally {\n scheduleRetryFailedEvents();\n }\n }, failedEventsIntervalMs);\n };\n\n scheduleProcessNewEvents();\n scheduleRetryFailedEvents();\n };\n\n return {\n processNewEvents,\n retryFailedEvents,\n start,\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBA,MAAM,kBAAkB,CAAI,OAAY,cAA6B;AACnE,QAAM,SAAgB,CAAC;AACvB,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,WAAW;AAChD,WAAO,KAAK,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;AAAA,EAC3C;AACA,SAAO;AACT;AA8BO,MAAM,qBAAqB,CAEhC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU,CAAC;AACb,MAKM;AACJ,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,wBAAwB,QAAQ,yBAAyB;AAC/D,QAAM,sBAAsB,QAAQ,uBAAuB;AAC3D,QAAM,yBAAyB,QAAQ,0BAA0B;AAEjE,QAAM,0BAA0B,OAAO,WAAoB;AACzD,UAAM,cAAc,gBAAgB,QAAQ,qBAAqB;AACjE,eAAW,SAAS,aAAa;AAC/B,YAAM,QAAQ,IAAI,MAAM,IAAI,CAAC,UAAU,SAAS,QAAQ,KAAK,CAAC,CAAC;AAAA,IACjE;AAAA,EACF;AAEA,QAAM,mBAAmB,YAA2B;AAClD,UAAM,SAAS,MAAM,aAAa,UAAU;AAAA,MAC1C,SAAS,EAAE,UAAU,CAAC,iBAAiB,EAAE;AAAA,MACzC,OAAO;AAAA,IACT,CAAC;AAED,QAAI,OAAO,WAAW,EAAG;AAEzB,UAAM,QAAQ,OAAO,QAAQ;AAC3B,YAAM,IAAI,gBAAgB,sBAAsB,MAAM;AAAA,IACxD,CAAC;AAED,UAAM,wBAAwB,MAAM;AAAA,EACtC;AAEA,QAAM,oBAAoB,YAA2B;AACnD,UAAM,SAAS,MAAM,aAAa,UAAU;AAAA,MAC1C,SAAS,EAAE,UAAU,CAAC,gBAAgB,uBAAuB,EAAE;AAAA,MAC/D,OAAO;AAAA,IACT,CAAC;AAED,QAAI,OAAO,WAAW,EAAG;AAEzB,UAAM,wBAAwB,MAAM;AAAA,EACtC;AAEA,QAAM,QAAQ,MAAM;AAClB,UAAM,2BAA2B,MAAM;AACrC,iBAAW,YAAY;AACrB,YAAI;AACF,gBAAM,iBAAiB;AAAA,QACzB,SAAS,OAAO;AACd,kBAAQ,MAAM,gCAAgC,KAAK;AAAA,QACrD,UAAE;AACA,mCAAyB;AAAA,QAC3B;AAAA,MACF,GAAG,mBAAmB;AAAA,IACxB;AAEA,UAAM,4BAA4B,MAAM;AACtC,iBAAW,YAAY;AACrB,YAAI;AACF,gBAAM,kBAAkB;AAAA,QAC1B,SAAS,OAAO;AACd,kBAAQ,MAAM,iCAAiC,KAAK;AAAA,QACtD,UAAE;AACA,oCAA0B;AAAA,QAC5B;AAAA,MACF,GAAG,sBAAsB;AAAA,IAC3B;AAEA,6BAAyB;AACzB,8BAA0B;AAAA,EAC5B;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,56 @@
1
+ import { EventBus } from './ports/EventBus.cjs';
2
+ import { EventQueries } from './ports/EventQueries.cjs';
3
+ import { WithEventsUow } from './ports/EventRepository.cjs';
4
+ import { GenericEvent, DefaultContext } from './types.cjs';
5
+
6
+ /** Configuration options for the event crawler. */
7
+ type CreateEventCrawlerOptions = {
8
+ /** Max events to fetch per batch (default: 100). */
9
+ batchSize?: number;
10
+ /** Max events to publish in parallel (default: 1). */
11
+ maxParallelProcessing?: number;
12
+ /** Interval for processing new events in ms (default: 10000). */
13
+ newEventsIntervalMs?: number;
14
+ /** Interval for retrying failed events in ms (default: 60000). */
15
+ failedEventsIntervalMs?: number;
16
+ };
17
+ /**
18
+ * Creates a background event crawler that processes and publishes events.
19
+ *
20
+ * The crawler runs two loops:
21
+ * 1. Process new events: polls for "never-published" events and publishes them
22
+ * 2. Retry failed events: polls for failed events and retries them
23
+ *
24
+ * @returns Object with:
25
+ * - `start()`: Start the background polling loops
26
+ * - `processNewEvents()`: Manually trigger new event processing
27
+ * - `retryFailedEvents()`: Manually trigger failed event retry
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * const crawler = createEventCrawler({
32
+ * withUow,
33
+ * eventQueries,
34
+ * eventBus,
35
+ * options: { batchSize: 50, newEventsIntervalMs: 5000 },
36
+ * });
37
+ *
38
+ * // Start background processing
39
+ * crawler.start();
40
+ *
41
+ * // Or trigger manually (useful for testing)
42
+ * await crawler.processNewEvents();
43
+ * ```
44
+ */
45
+ declare const createEventCrawler: <Event extends GenericEvent<string, unknown, DefaultContext>>({ withUow, eventQueries, eventBus, options, }: {
46
+ withUow: WithEventsUow<Event>;
47
+ eventQueries: EventQueries<Event>;
48
+ eventBus: EventBus<Event>;
49
+ options?: CreateEventCrawlerOptions;
50
+ }) => {
51
+ processNewEvents: () => Promise<void>;
52
+ retryFailedEvents: () => Promise<void>;
53
+ start: () => void;
54
+ };
55
+
56
+ export { createEventCrawler };
@@ -0,0 +1,56 @@
1
+ import { EventBus } from './ports/EventBus.js';
2
+ import { EventQueries } from './ports/EventQueries.js';
3
+ import { WithEventsUow } from './ports/EventRepository.js';
4
+ import { GenericEvent, DefaultContext } from './types.js';
5
+
6
+ /** Configuration options for the event crawler. */
7
+ type CreateEventCrawlerOptions = {
8
+ /** Max events to fetch per batch (default: 100). */
9
+ batchSize?: number;
10
+ /** Max events to publish in parallel (default: 1). */
11
+ maxParallelProcessing?: number;
12
+ /** Interval for processing new events in ms (default: 10000). */
13
+ newEventsIntervalMs?: number;
14
+ /** Interval for retrying failed events in ms (default: 60000). */
15
+ failedEventsIntervalMs?: number;
16
+ };
17
+ /**
18
+ * Creates a background event crawler that processes and publishes events.
19
+ *
20
+ * The crawler runs two loops:
21
+ * 1. Process new events: polls for "never-published" events and publishes them
22
+ * 2. Retry failed events: polls for failed events and retries them
23
+ *
24
+ * @returns Object with:
25
+ * - `start()`: Start the background polling loops
26
+ * - `processNewEvents()`: Manually trigger new event processing
27
+ * - `retryFailedEvents()`: Manually trigger failed event retry
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * const crawler = createEventCrawler({
32
+ * withUow,
33
+ * eventQueries,
34
+ * eventBus,
35
+ * options: { batchSize: 50, newEventsIntervalMs: 5000 },
36
+ * });
37
+ *
38
+ * // Start background processing
39
+ * crawler.start();
40
+ *
41
+ * // Or trigger manually (useful for testing)
42
+ * await crawler.processNewEvents();
43
+ * ```
44
+ */
45
+ declare const createEventCrawler: <Event extends GenericEvent<string, unknown, DefaultContext>>({ withUow, eventQueries, eventBus, options, }: {
46
+ withUow: WithEventsUow<Event>;
47
+ eventQueries: EventQueries<Event>;
48
+ eventBus: EventBus<Event>;
49
+ options?: CreateEventCrawlerOptions;
50
+ }) => {
51
+ processNewEvents: () => Promise<void>;
52
+ retryFailedEvents: () => Promise<void>;
53
+ start: () => void;
54
+ };
55
+
56
+ export { createEventCrawler };
@@ -0,0 +1,78 @@
1
+ const splitIntoChunks = (array, chunkSize) => {
2
+ const chunks = [];
3
+ for (let i = 0; i < array.length; i += chunkSize) {
4
+ chunks.push(array.slice(i, i + chunkSize));
5
+ }
6
+ return chunks;
7
+ };
8
+ const createEventCrawler = ({
9
+ withUow,
10
+ eventQueries,
11
+ eventBus,
12
+ options = {}
13
+ }) => {
14
+ const batchSize = options.batchSize ?? 100;
15
+ const maxParallelProcessing = options.maxParallelProcessing ?? 1;
16
+ const newEventsIntervalMs = options.newEventsIntervalMs ?? 1e4;
17
+ const failedEventsIntervalMs = options.failedEventsIntervalMs ?? 6e4;
18
+ const publishEventsInParallel = async (events) => {
19
+ const eventChunks = splitIntoChunks(events, maxParallelProcessing);
20
+ for (const chunk of eventChunks) {
21
+ await Promise.all(chunk.map((event) => eventBus.publish(event)));
22
+ }
23
+ };
24
+ const processNewEvents = async () => {
25
+ const events = await eventQueries.getEvents({
26
+ filters: { statuses: ["never-published"] },
27
+ limit: batchSize
28
+ });
29
+ if (events.length === 0) return;
30
+ await withUow(async (uow) => {
31
+ await uow.eventRepository.markEventsAsInProcess(events);
32
+ });
33
+ await publishEventsInParallel(events);
34
+ };
35
+ const retryFailedEvents = async () => {
36
+ const events = await eventQueries.getEvents({
37
+ filters: { statuses: ["to-republish", "failed-but-will-retry"] },
38
+ limit: batchSize
39
+ });
40
+ if (events.length === 0) return;
41
+ await publishEventsInParallel(events);
42
+ };
43
+ const start = () => {
44
+ const scheduleProcessNewEvents = () => {
45
+ setTimeout(async () => {
46
+ try {
47
+ await processNewEvents();
48
+ } catch (error) {
49
+ console.error("Error processing new events:", error);
50
+ } finally {
51
+ scheduleProcessNewEvents();
52
+ }
53
+ }, newEventsIntervalMs);
54
+ };
55
+ const scheduleRetryFailedEvents = () => {
56
+ setTimeout(async () => {
57
+ try {
58
+ await retryFailedEvents();
59
+ } catch (error) {
60
+ console.error("Error retrying failed events:", error);
61
+ } finally {
62
+ scheduleRetryFailedEvents();
63
+ }
64
+ }, failedEventsIntervalMs);
65
+ };
66
+ scheduleProcessNewEvents();
67
+ scheduleRetryFailedEvents();
68
+ };
69
+ return {
70
+ processNewEvents,
71
+ retryFailedEvents,
72
+ start
73
+ };
74
+ };
75
+ export {
76
+ createEventCrawler
77
+ };
78
+ //# sourceMappingURL=createEventCrawler.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/createEventCrawler.ts"],"sourcesContent":["import type { EventBus } from './ports/EventBus.ts.mjs';\nimport type { EventQueries } from './ports/EventQueries.ts.mjs';\nimport type { WithEventsUow } from './ports/EventRepository.ts.mjs';\nimport type { DefaultContext, GenericEvent } from './types.ts.mjs';\n\n/** Configuration options for the event crawler. */\ntype CreateEventCrawlerOptions = {\n /** Max events to fetch per batch (default: 100). */\n batchSize?: number;\n /** Max events to publish in parallel (default: 1). */\n maxParallelProcessing?: number;\n /** Interval for processing new events in ms (default: 10000). */\n newEventsIntervalMs?: number;\n /** Interval for retrying failed events in ms (default: 60000). */\n failedEventsIntervalMs?: number;\n};\n\nconst splitIntoChunks = <T>(array: T[], chunkSize: number): T[][] => {\n const chunks: T[][] = [];\n for (let i = 0; i < array.length; i += chunkSize) {\n chunks.push(array.slice(i, i + chunkSize));\n }\n return chunks;\n};\n\n/**\n * Creates a background event crawler that processes and publishes events.\n *\n * The crawler runs two loops:\n * 1. Process new events: polls for \"never-published\" events and publishes them\n * 2. Retry failed events: polls for failed events and retries them\n *\n * @returns Object with:\n * - `start()`: Start the background polling loops\n * - `processNewEvents()`: Manually trigger new event processing\n * - `retryFailedEvents()`: Manually trigger failed event retry\n *\n * @example\n * ```typescript\n * const crawler = createEventCrawler({\n * withUow,\n * eventQueries,\n * eventBus,\n * options: { batchSize: 50, newEventsIntervalMs: 5000 },\n * });\n *\n * // Start background processing\n * crawler.start();\n *\n * // Or trigger manually (useful for testing)\n * await crawler.processNewEvents();\n * ```\n */\nexport const createEventCrawler = <\n Event extends GenericEvent<string, unknown, DefaultContext>,\n>({\n withUow,\n eventQueries,\n eventBus,\n options = {},\n}: {\n withUow: WithEventsUow<Event>;\n eventQueries: EventQueries<Event>;\n eventBus: EventBus<Event>;\n options?: CreateEventCrawlerOptions;\n}) => {\n const batchSize = options.batchSize ?? 100;\n const maxParallelProcessing = options.maxParallelProcessing ?? 1;\n const newEventsIntervalMs = options.newEventsIntervalMs ?? 10_000;\n const failedEventsIntervalMs = options.failedEventsIntervalMs ?? 60_000;\n\n const publishEventsInParallel = async (events: Event[]) => {\n const eventChunks = splitIntoChunks(events, maxParallelProcessing);\n for (const chunk of eventChunks) {\n await Promise.all(chunk.map((event) => eventBus.publish(event)));\n }\n };\n\n const processNewEvents = async (): Promise<void> => {\n const events = await eventQueries.getEvents({\n filters: { statuses: [\"never-published\"] },\n limit: batchSize,\n });\n\n if (events.length === 0) return;\n\n await withUow(async (uow) => {\n await uow.eventRepository.markEventsAsInProcess(events);\n });\n\n await publishEventsInParallel(events);\n };\n\n const retryFailedEvents = async (): Promise<void> => {\n const events = await eventQueries.getEvents({\n filters: { statuses: [\"to-republish\", \"failed-but-will-retry\"] },\n limit: batchSize,\n });\n\n if (events.length === 0) return;\n\n await publishEventsInParallel(events);\n };\n\n const start = () => {\n const scheduleProcessNewEvents = () => {\n setTimeout(async () => {\n try {\n await processNewEvents();\n } catch (error) {\n console.error(\"Error processing new events:\", error);\n } finally {\n scheduleProcessNewEvents();\n }\n }, newEventsIntervalMs);\n };\n\n const scheduleRetryFailedEvents = () => {\n setTimeout(async () => {\n try {\n await retryFailedEvents();\n } catch (error) {\n console.error(\"Error retrying failed events:\", error);\n } finally {\n scheduleRetryFailedEvents();\n }\n }, failedEventsIntervalMs);\n };\n\n scheduleProcessNewEvents();\n scheduleRetryFailedEvents();\n };\n\n return {\n processNewEvents,\n retryFailedEvents,\n start,\n };\n};\n"],"mappings":"AAiBA,MAAM,kBAAkB,CAAI,OAAY,cAA6B;AACnE,QAAM,SAAgB,CAAC;AACvB,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,WAAW;AAChD,WAAO,KAAK,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;AAAA,EAC3C;AACA,SAAO;AACT;AA8BO,MAAM,qBAAqB,CAEhC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU,CAAC;AACb,MAKM;AACJ,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,wBAAwB,QAAQ,yBAAyB;AAC/D,QAAM,sBAAsB,QAAQ,uBAAuB;AAC3D,QAAM,yBAAyB,QAAQ,0BAA0B;AAEjE,QAAM,0BAA0B,OAAO,WAAoB;AACzD,UAAM,cAAc,gBAAgB,QAAQ,qBAAqB;AACjE,eAAW,SAAS,aAAa;AAC/B,YAAM,QAAQ,IAAI,MAAM,IAAI,CAAC,UAAU,SAAS,QAAQ,KAAK,CAAC,CAAC;AAAA,IACjE;AAAA,EACF;AAEA,QAAM,mBAAmB,YAA2B;AAClD,UAAM,SAAS,MAAM,aAAa,UAAU;AAAA,MAC1C,SAAS,EAAE,UAAU,CAAC,iBAAiB,EAAE;AAAA,MACzC,OAAO;AAAA,IACT,CAAC;AAED,QAAI,OAAO,WAAW,EAAG;AAEzB,UAAM,QAAQ,OAAO,QAAQ;AAC3B,YAAM,IAAI,gBAAgB,sBAAsB,MAAM;AAAA,IACxD,CAAC;AAED,UAAM,wBAAwB,MAAM;AAAA,EACtC;AAEA,QAAM,oBAAoB,YAA2B;AACnD,UAAM,SAAS,MAAM,aAAa,UAAU;AAAA,MAC1C,SAAS,EAAE,UAAU,CAAC,gBAAgB,uBAAuB,EAAE;AAAA,MAC/D,OAAO;AAAA,IACT,CAAC;AAED,QAAI,OAAO,WAAW,EAAG;AAEzB,UAAM,wBAAwB,MAAM;AAAA,EACtC;AAEA,QAAM,QAAQ,MAAM;AAClB,UAAM,2BAA2B,MAAM;AACrC,iBAAW,YAAY;AACrB,YAAI;AACF,gBAAM,iBAAiB;AAAA,QACzB,SAAS,OAAO;AACd,kBAAQ,MAAM,gCAAgC,KAAK;AAAA,QACrD,UAAE;AACA,mCAAyB;AAAA,QAC3B;AAAA,MACF,GAAG,mBAAmB;AAAA,IACxB;AAEA,UAAM,4BAA4B,MAAM;AACtC,iBAAW,YAAY;AACrB,YAAI;AACF,gBAAM,kBAAkB;AAAA,QAC1B,SAAS,OAAO;AACd,kBAAQ,MAAM,iCAAiC,KAAK;AAAA,QACtD,UAAE;AACA,oCAA0B;AAAA,QAC5B;AAAA,MACF,GAAG,sBAAsB;AAAA,IAC3B;AAEA,6BAAyB;AACzB,8BAA0B;AAAA,EAC5B;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,43 @@
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 __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var createNewEvent_exports = {};
20
+ __export(createNewEvent_exports, {
21
+ makeCreateNewEvent: () => makeCreateNewEvent
22
+ });
23
+ module.exports = __toCommonJS(createNewEvent_exports);
24
+ const makeCreateNewEvent = (options = {}) => {
25
+ const getNow = options.getNow ?? (() => /* @__PURE__ */ new Date());
26
+ const generateId = options.generateId ?? (() => crypto.randomUUID());
27
+ return (params) => ({
28
+ id: params.id ?? generateId(),
29
+ topic: params.topic,
30
+ payload: params.payload,
31
+ triggeredByUserId: params.triggeredByUserId,
32
+ occurredAt: params.occurredAt ?? getNow(),
33
+ status: "never-published",
34
+ publications: [],
35
+ priority: params.priority,
36
+ context: params.context
37
+ });
38
+ };
39
+ // Annotate the CommonJS export names for ESM import in node:
40
+ 0 && (module.exports = {
41
+ makeCreateNewEvent
42
+ });
43
+ //# sourceMappingURL=createNewEvent.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/createNewEvent.ts"],"sourcesContent":["import type { DefaultContext, EventId, GenericEvent, UserId } from \"./types.ts\";\n\ntype MakeCreateNewEventOptions = {\n getNow?: () => Date;\n generateId?: () => EventId;\n};\n\ntype ContextParam<\n Event extends GenericEvent<string, unknown, DefaultContext>,\n Topic extends Event[\"topic\"],\n> = Extract<Event, { topic: Topic }>[\"context\"] extends undefined\n ? { context?: undefined }\n : { context: Extract<Event, { topic: Topic }>[\"context\"] };\n\ntype CreateNewEventParams<\n Event extends GenericEvent<string, unknown, DefaultContext>,\n Topic extends Event[\"topic\"],\n> = {\n topic: Topic;\n payload: Extract<Event, { topic: Topic }>[\"payload\"];\n triggeredByUserId: UserId;\n id?: EventId;\n occurredAt?: Date;\n priority?: number;\n} & ContextParam<Event, Topic>;\n\n/**\n * Creates a typed event creator factory for your event union.\n * Provides type-safe event creation where topic constrains payload type.\n *\n * @param options.getNow - Function to get current time (default: `() => new Date()`)\n * @param options.generateId - Function to generate event IDs (default: `() => crypto.randomUUID()`)\n *\n * @example\n * ```typescript\n * type MyEvents =\n * | GenericEvent<\"UserCreated\", { email: string }>\n * | GenericEvent<\"OrderPlaced\", { orderId: string }>;\n *\n * // Standalone usage:\n * const createEvent = makeCreateNewEvent<MyEvents>();\n *\n * // Or get it from createInMemoryEventBus (recommended):\n * const { eventBus, createEvent } = createInMemoryEventBus<MyEvents>(withUow);\n *\n * // Type-safe: payload must match topic\n * createEvent({ topic: \"UserCreated\", payload: { email: \"a@b.com\" }, triggeredByUserId: \"u1\" }); // OK\n * createEvent({ topic: \"UserCreated\", payload: { orderId: \"123\" }, triggeredByUserId: \"u1\" }); // Error!\n *\n * // For testing, inject deterministic functions:\n * const createEvent = makeCreateNewEvent<MyEvents>({\n * getNow: () => new Date(\"2024-01-01\"),\n * generateId: () => \"test-id\",\n * });\n * ```\n */\n\nexport type CreateNewEvent<\n Event extends GenericEvent<string, unknown, DefaultContext>,\n> = <Topic extends Event[\"topic\"]>(\n params: CreateNewEventParams<Event, Topic>,\n) => Extract<Event, { topic: Topic }>;\n\nexport const makeCreateNewEvent = <\n Event extends GenericEvent<string, unknown, DefaultContext>,\n>(\n options: MakeCreateNewEventOptions = {},\n): CreateNewEvent<Event> => {\n const getNow = options.getNow ?? (() => new Date());\n const generateId =\n options.generateId ?? (() => crypto.randomUUID() as EventId);\n\n return <Topic extends Event[\"topic\"]>(\n params: CreateNewEventParams<Event, Topic>,\n ): Extract<Event, { topic: Topic }> =>\n ({\n id: params.id ?? generateId(),\n topic: params.topic,\n payload: params.payload,\n triggeredByUserId: params.triggeredByUserId,\n occurredAt: params.occurredAt ?? getNow(),\n status: \"never-published\",\n publications: [],\n priority: params.priority,\n context: params.context,\n }) as unknown as Extract<Event, { topic: Topic }>;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA+DO,MAAM,qBAAqB,CAGhC,UAAqC,CAAC,MACZ;AAC1B,QAAM,SAAS,QAAQ,WAAW,MAAM,oBAAI,KAAK;AACjD,QAAM,aACJ,QAAQ,eAAe,MAAM,OAAO,WAAW;AAEjD,SAAO,CACL,YAEC;AAAA,IACC,IAAI,OAAO,MAAM,WAAW;AAAA,IAC5B,OAAO,OAAO;AAAA,IACd,SAAS,OAAO;AAAA,IAChB,mBAAmB,OAAO;AAAA,IAC1B,YAAY,OAAO,cAAc,OAAO;AAAA,IACxC,QAAQ;AAAA,IACR,cAAc,CAAC;AAAA,IACf,UAAU,OAAO;AAAA,IACjB,SAAS,OAAO;AAAA,EAClB;AACJ;","names":[]}
@@ -0,0 +1,61 @@
1
+ import { GenericEvent, DefaultContext, UserId, EventId } from './types.cjs';
2
+
3
+ type MakeCreateNewEventOptions = {
4
+ getNow?: () => Date;
5
+ generateId?: () => EventId;
6
+ };
7
+ type ContextParam<Event extends GenericEvent<string, unknown, DefaultContext>, Topic extends Event["topic"]> = Extract<Event, {
8
+ topic: Topic;
9
+ }>["context"] extends undefined ? {
10
+ context?: undefined;
11
+ } : {
12
+ context: Extract<Event, {
13
+ topic: Topic;
14
+ }>["context"];
15
+ };
16
+ type CreateNewEventParams<Event extends GenericEvent<string, unknown, DefaultContext>, Topic extends Event["topic"]> = {
17
+ topic: Topic;
18
+ payload: Extract<Event, {
19
+ topic: Topic;
20
+ }>["payload"];
21
+ triggeredByUserId: UserId;
22
+ id?: EventId;
23
+ occurredAt?: Date;
24
+ priority?: number;
25
+ } & ContextParam<Event, Topic>;
26
+ /**
27
+ * Creates a typed event creator factory for your event union.
28
+ * Provides type-safe event creation where topic constrains payload type.
29
+ *
30
+ * @param options.getNow - Function to get current time (default: `() => new Date()`)
31
+ * @param options.generateId - Function to generate event IDs (default: `() => crypto.randomUUID()`)
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * type MyEvents =
36
+ * | GenericEvent<"UserCreated", { email: string }>
37
+ * | GenericEvent<"OrderPlaced", { orderId: string }>;
38
+ *
39
+ * // Standalone usage:
40
+ * const createEvent = makeCreateNewEvent<MyEvents>();
41
+ *
42
+ * // Or get it from createInMemoryEventBus (recommended):
43
+ * const { eventBus, createEvent } = createInMemoryEventBus<MyEvents>(withUow);
44
+ *
45
+ * // Type-safe: payload must match topic
46
+ * createEvent({ topic: "UserCreated", payload: { email: "a@b.com" }, triggeredByUserId: "u1" }); // OK
47
+ * createEvent({ topic: "UserCreated", payload: { orderId: "123" }, triggeredByUserId: "u1" }); // Error!
48
+ *
49
+ * // For testing, inject deterministic functions:
50
+ * const createEvent = makeCreateNewEvent<MyEvents>({
51
+ * getNow: () => new Date("2024-01-01"),
52
+ * generateId: () => "test-id",
53
+ * });
54
+ * ```
55
+ */
56
+ type CreateNewEvent<Event extends GenericEvent<string, unknown, DefaultContext>> = <Topic extends Event["topic"]>(params: CreateNewEventParams<Event, Topic>) => Extract<Event, {
57
+ topic: Topic;
58
+ }>;
59
+ declare const makeCreateNewEvent: <Event extends GenericEvent<string, unknown, DefaultContext>>(options?: MakeCreateNewEventOptions) => CreateNewEvent<Event>;
60
+
61
+ export { type CreateNewEvent, makeCreateNewEvent };
@@ -0,0 +1,61 @@
1
+ import { GenericEvent, DefaultContext, UserId, EventId } from './types.js';
2
+
3
+ type MakeCreateNewEventOptions = {
4
+ getNow?: () => Date;
5
+ generateId?: () => EventId;
6
+ };
7
+ type ContextParam<Event extends GenericEvent<string, unknown, DefaultContext>, Topic extends Event["topic"]> = Extract<Event, {
8
+ topic: Topic;
9
+ }>["context"] extends undefined ? {
10
+ context?: undefined;
11
+ } : {
12
+ context: Extract<Event, {
13
+ topic: Topic;
14
+ }>["context"];
15
+ };
16
+ type CreateNewEventParams<Event extends GenericEvent<string, unknown, DefaultContext>, Topic extends Event["topic"]> = {
17
+ topic: Topic;
18
+ payload: Extract<Event, {
19
+ topic: Topic;
20
+ }>["payload"];
21
+ triggeredByUserId: UserId;
22
+ id?: EventId;
23
+ occurredAt?: Date;
24
+ priority?: number;
25
+ } & ContextParam<Event, Topic>;
26
+ /**
27
+ * Creates a typed event creator factory for your event union.
28
+ * Provides type-safe event creation where topic constrains payload type.
29
+ *
30
+ * @param options.getNow - Function to get current time (default: `() => new Date()`)
31
+ * @param options.generateId - Function to generate event IDs (default: `() => crypto.randomUUID()`)
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * type MyEvents =
36
+ * | GenericEvent<"UserCreated", { email: string }>
37
+ * | GenericEvent<"OrderPlaced", { orderId: string }>;
38
+ *
39
+ * // Standalone usage:
40
+ * const createEvent = makeCreateNewEvent<MyEvents>();
41
+ *
42
+ * // Or get it from createInMemoryEventBus (recommended):
43
+ * const { eventBus, createEvent } = createInMemoryEventBus<MyEvents>(withUow);
44
+ *
45
+ * // Type-safe: payload must match topic
46
+ * createEvent({ topic: "UserCreated", payload: { email: "a@b.com" }, triggeredByUserId: "u1" }); // OK
47
+ * createEvent({ topic: "UserCreated", payload: { orderId: "123" }, triggeredByUserId: "u1" }); // Error!
48
+ *
49
+ * // For testing, inject deterministic functions:
50
+ * const createEvent = makeCreateNewEvent<MyEvents>({
51
+ * getNow: () => new Date("2024-01-01"),
52
+ * generateId: () => "test-id",
53
+ * });
54
+ * ```
55
+ */
56
+ type CreateNewEvent<Event extends GenericEvent<string, unknown, DefaultContext>> = <Topic extends Event["topic"]>(params: CreateNewEventParams<Event, Topic>) => Extract<Event, {
57
+ topic: Topic;
58
+ }>;
59
+ declare const makeCreateNewEvent: <Event extends GenericEvent<string, unknown, DefaultContext>>(options?: MakeCreateNewEventOptions) => CreateNewEvent<Event>;
60
+
61
+ export { type CreateNewEvent, makeCreateNewEvent };
@@ -0,0 +1,19 @@
1
+ const makeCreateNewEvent = (options = {}) => {
2
+ const getNow = options.getNow ?? (() => /* @__PURE__ */ new Date());
3
+ const generateId = options.generateId ?? (() => crypto.randomUUID());
4
+ return (params) => ({
5
+ id: params.id ?? generateId(),
6
+ topic: params.topic,
7
+ payload: params.payload,
8
+ triggeredByUserId: params.triggeredByUserId,
9
+ occurredAt: params.occurredAt ?? getNow(),
10
+ status: "never-published",
11
+ publications: [],
12
+ priority: params.priority,
13
+ context: params.context
14
+ });
15
+ };
16
+ export {
17
+ makeCreateNewEvent
18
+ };
19
+ //# sourceMappingURL=createNewEvent.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/createNewEvent.ts"],"sourcesContent":["import type { DefaultContext, EventId, GenericEvent, UserId } from './types.ts.mjs';\n\ntype MakeCreateNewEventOptions = {\n getNow?: () => Date;\n generateId?: () => EventId;\n};\n\ntype ContextParam<\n Event extends GenericEvent<string, unknown, DefaultContext>,\n Topic extends Event[\"topic\"],\n> = Extract<Event, { topic: Topic }>[\"context\"] extends undefined\n ? { context?: undefined }\n : { context: Extract<Event, { topic: Topic }>[\"context\"] };\n\ntype CreateNewEventParams<\n Event extends GenericEvent<string, unknown, DefaultContext>,\n Topic extends Event[\"topic\"],\n> = {\n topic: Topic;\n payload: Extract<Event, { topic: Topic }>[\"payload\"];\n triggeredByUserId: UserId;\n id?: EventId;\n occurredAt?: Date;\n priority?: number;\n} & ContextParam<Event, Topic>;\n\n/**\n * Creates a typed event creator factory for your event union.\n * Provides type-safe event creation where topic constrains payload type.\n *\n * @param options.getNow - Function to get current time (default: `() => new Date()`)\n * @param options.generateId - Function to generate event IDs (default: `() => crypto.randomUUID()`)\n *\n * @example\n * ```typescript\n * type MyEvents =\n * | GenericEvent<\"UserCreated\", { email: string }>\n * | GenericEvent<\"OrderPlaced\", { orderId: string }>;\n *\n * // Standalone usage:\n * const createEvent = makeCreateNewEvent<MyEvents>();\n *\n * // Or get it from createInMemoryEventBus (recommended):\n * const { eventBus, createEvent } = createInMemoryEventBus<MyEvents>(withUow);\n *\n * // Type-safe: payload must match topic\n * createEvent({ topic: \"UserCreated\", payload: { email: \"a@b.com\" }, triggeredByUserId: \"u1\" }); // OK\n * createEvent({ topic: \"UserCreated\", payload: { orderId: \"123\" }, triggeredByUserId: \"u1\" }); // Error!\n *\n * // For testing, inject deterministic functions:\n * const createEvent = makeCreateNewEvent<MyEvents>({\n * getNow: () => new Date(\"2024-01-01\"),\n * generateId: () => \"test-id\",\n * });\n * ```\n */\n\nexport type CreateNewEvent<\n Event extends GenericEvent<string, unknown, DefaultContext>,\n> = <Topic extends Event[\"topic\"]>(\n params: CreateNewEventParams<Event, Topic>,\n) => Extract<Event, { topic: Topic }>;\n\nexport const makeCreateNewEvent = <\n Event extends GenericEvent<string, unknown, DefaultContext>,\n>(\n options: MakeCreateNewEventOptions = {},\n): CreateNewEvent<Event> => {\n const getNow = options.getNow ?? (() => new Date());\n const generateId =\n options.generateId ?? (() => crypto.randomUUID() as EventId);\n\n return <Topic extends Event[\"topic\"]>(\n params: CreateNewEventParams<Event, Topic>,\n ): Extract<Event, { topic: Topic }> =>\n ({\n id: params.id ?? generateId(),\n topic: params.topic,\n payload: params.payload,\n triggeredByUserId: params.triggeredByUserId,\n occurredAt: params.occurredAt ?? getNow(),\n status: \"never-published\",\n publications: [],\n priority: params.priority,\n context: params.context,\n }) as unknown as Extract<Event, { topic: Topic }>;\n};\n"],"mappings":"AA+DO,MAAM,qBAAqB,CAGhC,UAAqC,CAAC,MACZ;AAC1B,QAAM,SAAS,QAAQ,WAAW,MAAM,oBAAI,KAAK;AACjD,QAAM,aACJ,QAAQ,eAAe,MAAM,OAAO,WAAW;AAEjD,SAAO,CACL,YAEC;AAAA,IACC,IAAI,OAAO,MAAM,WAAW;AAAA,IAC5B,OAAO,OAAO;AAAA,IACd,SAAS,OAAO;AAAA,IAChB,mBAAmB,OAAO;AAAA,IAC1B,YAAY,OAAO,cAAc,OAAO;AAAA,IACxC,QAAQ;AAAA,IACR,cAAc,CAAC;AAAA,IACf,UAAU,OAAO;AAAA,IACjB,SAAS,OAAO;AAAA,EAClB;AACJ;","names":[]}
package/dist/index.cjs ADDED
@@ -0,0 +1,27 @@
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 __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
15
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
16
+ var index_exports = {};
17
+ module.exports = __toCommonJS(index_exports);
18
+ __reExport(index_exports, require("./adapters/in-memory/index.ts"), module.exports);
19
+ __reExport(index_exports, require("./createEventCrawler.ts"), module.exports);
20
+ __reExport(index_exports, require("./createNewEvent.ts"), module.exports);
21
+ // Annotate the CommonJS export names for ESM import in node:
22
+ 0 && (module.exports = {
23
+ ...require("./adapters/in-memory/index.ts"),
24
+ ...require("./createEventCrawler.ts"),
25
+ ...require("./createNewEvent.ts")
26
+ });
27
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from \"./adapters/in-memory/index.ts\";\nexport * from \"./createEventCrawler.ts\";\nexport * from \"./createNewEvent.ts\";\nexport type * from \"./ports/EventBus.ts\";\nexport type * from \"./ports/EventQueries.ts\";\nexport type * from \"./ports/EventRepository.ts\";\nexport type * from \"./types.ts\";\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AAAA;AAAA,0BAAc,0CAAd;AACA,0BAAc,oCADd;AAEA,0BAAc,gCAFd;","names":[]}
@@ -0,0 +1,10 @@
1
+ export { createInMemoryEventRepositoryAndQueries } from './adapters/in-memory/index.cjs';
2
+ export { createEventCrawler } from './createEventCrawler.cjs';
3
+ export { CreateNewEvent, makeCreateNewEvent } from './createNewEvent.cjs';
4
+ export { EventBus } from './ports/EventBus.cjs';
5
+ export { EventQueries } from './ports/EventQueries.cjs';
6
+ export { EventRepository, EventsUnitOfWork, WithEventsUow } from './ports/EventRepository.cjs';
7
+ export { DefaultContext, EventFailure, EventId, EventPublication, EventStatus, Flavor, GenericEvent, SubscriptionId, UserId } from './types.cjs';
8
+ export { createInMemoryEventBus } from './adapters/in-memory/InMemoryEventBus.cjs';
9
+ export { createInMemoryEventQueries } from './adapters/in-memory/InMemoryEventQueries.cjs';
10
+ export { InMemoryEventRepositoryHelpers, createInMemoryEventRepository, createInMemoryWithUow } from './adapters/in-memory/InMemoryEventRepository.cjs';
@@ -0,0 +1,10 @@
1
+ export { createInMemoryEventRepositoryAndQueries } from './adapters/in-memory/index.js';
2
+ export { createEventCrawler } from './createEventCrawler.js';
3
+ export { CreateNewEvent, makeCreateNewEvent } from './createNewEvent.js';
4
+ export { EventBus } from './ports/EventBus.js';
5
+ export { EventQueries } from './ports/EventQueries.js';
6
+ export { EventRepository, EventsUnitOfWork, WithEventsUow } from './ports/EventRepository.js';
7
+ export { DefaultContext, EventFailure, EventId, EventPublication, EventStatus, Flavor, GenericEvent, SubscriptionId, UserId } from './types.js';
8
+ export { createInMemoryEventBus } from './adapters/in-memory/InMemoryEventBus.js';
9
+ export { createInMemoryEventQueries } from './adapters/in-memory/InMemoryEventQueries.js';
10
+ export { InMemoryEventRepositoryHelpers, createInMemoryEventRepository, createInMemoryWithUow } from './adapters/in-memory/InMemoryEventRepository.js';
package/dist/index.mjs ADDED
@@ -0,0 +1,4 @@
1
+ export * from "./adapters/in-memory/index.ts.mjs";
2
+ export * from "./createEventCrawler.ts.mjs";
3
+ export * from "./createNewEvent.ts.mjs";
4
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './adapters/in-memory/index.ts.mjs';\nexport * from './createEventCrawler.ts.mjs';\nexport * from './createNewEvent.ts.mjs';\nexport type * from './ports/EventBus.ts.mjs';\nexport type * from './ports/EventQueries.ts.mjs';\nexport type * from './ports/EventRepository.ts.mjs';\nexport type * from './types.ts.mjs';\n"],"mappings":"AAAA,cAAc;AACd,cAAc;AACd,cAAc;","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 EventBus_exports = {};
16
+ module.exports = __toCommonJS(EventBus_exports);
17
+ //# sourceMappingURL=EventBus.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/ports/EventBus.ts"],"sourcesContent":["import type { DefaultContext, GenericEvent, SubscriptionId } from \"../types.ts\";\n\n/**\n * Event bus for publishing events to subscribers.\n * Handles delivery, failure tracking, and retry logic.\n *\n * @example\n * ```typescript\n * eventBus.subscribe({\n * topic: \"OrderPlaced\",\n * subscriptionId: \"send-confirmation-email\",\n * callBack: async (event) => {\n * await emailService.sendOrderConfirmation(event.payload);\n * },\n * });\n * ```\n */\nexport type EventBus<\n Event extends GenericEvent<string, unknown, DefaultContext>,\n> = {\n /**\n * Publish an event to all subscribers of its topic.\n * Updates event status and records publication results.\n */\n publish: (event: Event) => Promise<void>;\n /**\n * Register a subscriber for a specific topic.\n * The subscriptionId must be unique per topic and is used for retry tracking.\n */\n subscribe: <\n Event extends GenericEvent<string, unknown, DefaultContext>,\n >(params: {\n topic: Event[\"topic\"];\n subscriptionId: SubscriptionId;\n callBack: (e: Event) => Promise<void>;\n }) => void;\n};\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}