@l-etabli/events 0.6.1 → 0.7.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 (152) hide show
  1. package/README.md +96 -0
  2. package/dist/adapters/effect-kysely/EffectKyselyEventQueries.cjs +54 -0
  3. package/dist/adapters/effect-kysely/EffectKyselyEventQueries.cjs.map +1 -0
  4. package/dist/adapters/effect-kysely/EffectKyselyEventQueries.d.cts +10 -0
  5. package/dist/adapters/effect-kysely/EffectKyselyEventQueries.d.ts +10 -0
  6. package/dist/adapters/effect-kysely/EffectKyselyEventQueries.mjs +30 -0
  7. package/dist/adapters/effect-kysely/EffectKyselyEventQueries.mjs.map +1 -0
  8. package/dist/adapters/effect-kysely/EffectKyselyEventRepository.cjs +85 -0
  9. package/dist/adapters/effect-kysely/EffectKyselyEventRepository.cjs.map +1 -0
  10. package/dist/adapters/effect-kysely/EffectKyselyEventRepository.d.cts +9 -0
  11. package/dist/adapters/effect-kysely/EffectKyselyEventRepository.d.ts +9 -0
  12. package/dist/adapters/effect-kysely/EffectKyselyEventRepository.mjs +61 -0
  13. package/dist/adapters/effect-kysely/EffectKyselyEventRepository.mjs.map +1 -0
  14. package/dist/adapters/effect-kysely/index.cjs +32 -0
  15. package/dist/adapters/effect-kysely/index.cjs.map +1 -0
  16. package/dist/adapters/effect-kysely/index.d.cts +9 -0
  17. package/dist/adapters/effect-kysely/index.d.ts +9 -0
  18. package/dist/adapters/effect-kysely/index.mjs +7 -0
  19. package/dist/adapters/effect-kysely/index.mjs.map +1 -0
  20. package/dist/adapters/in-memory/InMemoryEventBus.cjs +3 -17
  21. package/dist/adapters/in-memory/InMemoryEventBus.cjs.map +1 -1
  22. package/dist/adapters/in-memory/InMemoryEventBus.mjs +2 -16
  23. package/dist/adapters/in-memory/InMemoryEventBus.mjs.map +1 -1
  24. package/dist/adapters/in-memory/InMemoryEventQueries.cjs +2 -20
  25. package/dist/adapters/in-memory/InMemoryEventQueries.cjs.map +1 -1
  26. package/dist/adapters/in-memory/InMemoryEventQueries.mjs +2 -20
  27. package/dist/adapters/in-memory/InMemoryEventQueries.mjs.map +1 -1
  28. package/dist/adapters/kysely/KyselyEventQueries.cjs +2 -9
  29. package/dist/adapters/kysely/KyselyEventQueries.cjs.map +1 -1
  30. package/dist/adapters/kysely/KyselyEventQueries.mjs +2 -9
  31. package/dist/adapters/kysely/KyselyEventQueries.mjs.map +1 -1
  32. package/dist/adapters/kysely/KyselyEventRepository.cjs +13 -14
  33. package/dist/adapters/kysely/KyselyEventRepository.cjs.map +1 -1
  34. package/dist/adapters/kysely/KyselyEventRepository.mjs +1 -2
  35. package/dist/adapters/kysely/KyselyEventRepository.mjs.map +1 -1
  36. package/dist/adapters/kysely/jsonb.cjs +30 -0
  37. package/dist/adapters/kysely/jsonb.cjs.map +1 -0
  38. package/dist/adapters/kysely/jsonb.d.cts +5 -0
  39. package/dist/adapters/kysely/jsonb.d.ts +5 -0
  40. package/dist/adapters/kysely/jsonb.mjs +6 -0
  41. package/dist/adapters/kysely/jsonb.mjs.map +1 -0
  42. package/dist/adapters/kysely/mapEventRow.cjs +35 -0
  43. package/dist/adapters/kysely/mapEventRow.cjs.map +1 -0
  44. package/dist/adapters/kysely/mapEventRow.d.cts +6 -0
  45. package/dist/adapters/kysely/mapEventRow.d.ts +6 -0
  46. package/dist/adapters/kysely/mapEventRow.mjs +11 -0
  47. package/dist/adapters/kysely/mapEventRow.mjs.map +1 -0
  48. package/dist/createEventCrawler.cjs +2 -8
  49. package/dist/createEventCrawler.cjs.map +1 -1
  50. package/dist/createEventCrawler.mjs +1 -7
  51. package/dist/createEventCrawler.mjs.map +1 -1
  52. package/dist/effect/EffectEventCrawler.cjs +111 -0
  53. package/dist/effect/EffectEventCrawler.cjs.map +1 -0
  54. package/dist/effect/EffectEventCrawler.d.cts +26 -0
  55. package/dist/effect/EffectEventCrawler.d.ts +26 -0
  56. package/dist/effect/EffectEventCrawler.mjs +87 -0
  57. package/dist/effect/EffectEventCrawler.mjs.map +1 -0
  58. package/dist/effect/EffectInMemoryEventBus.cjs +131 -0
  59. package/dist/effect/EffectInMemoryEventBus.cjs.map +1 -0
  60. package/dist/effect/EffectInMemoryEventBus.d.cts +31 -0
  61. package/dist/effect/EffectInMemoryEventBus.d.ts +31 -0
  62. package/dist/effect/EffectInMemoryEventBus.mjs +112 -0
  63. package/dist/effect/EffectInMemoryEventBus.mjs.map +1 -0
  64. package/dist/effect/EffectInMemoryEventQueries.cjs +35 -0
  65. package/dist/effect/EffectInMemoryEventQueries.cjs.map +1 -0
  66. package/dist/effect/EffectInMemoryEventQueries.d.cts +12 -0
  67. package/dist/effect/EffectInMemoryEventQueries.d.ts +12 -0
  68. package/dist/effect/EffectInMemoryEventQueries.mjs +11 -0
  69. package/dist/effect/EffectInMemoryEventQueries.mjs.map +1 -0
  70. package/dist/effect/EffectInMemoryEventRepository.cjs +73 -0
  71. package/dist/effect/EffectInMemoryEventRepository.cjs.map +1 -0
  72. package/dist/effect/EffectInMemoryEventRepository.d.cts +15 -0
  73. package/dist/effect/EffectInMemoryEventRepository.d.ts +15 -0
  74. package/dist/effect/EffectInMemoryEventRepository.mjs +48 -0
  75. package/dist/effect/EffectInMemoryEventRepository.mjs.map +1 -0
  76. package/dist/effect/EffectSubscriptions.cjs +61 -0
  77. package/dist/effect/EffectSubscriptions.cjs.map +1 -0
  78. package/dist/effect/EffectSubscriptions.d.cts +22 -0
  79. package/dist/effect/EffectSubscriptions.d.ts +22 -0
  80. package/dist/effect/EffectSubscriptions.mjs +36 -0
  81. package/dist/effect/EffectSubscriptions.mjs.map +1 -0
  82. package/dist/effect/index.cjs +47 -0
  83. package/dist/effect/index.cjs.map +1 -0
  84. package/dist/effect/index.d.cts +27 -0
  85. package/dist/effect/index.d.ts +27 -0
  86. package/dist/effect/index.mjs +20 -0
  87. package/dist/effect/index.mjs.map +1 -0
  88. package/dist/effect/ports/EffectEventBus.cjs +17 -0
  89. package/dist/effect/ports/EffectEventBus.cjs.map +1 -0
  90. package/dist/effect/ports/EffectEventBus.d.cts +13 -0
  91. package/dist/effect/ports/EffectEventBus.d.ts +13 -0
  92. package/dist/effect/ports/EffectEventBus.mjs +1 -0
  93. package/dist/effect/ports/EffectEventBus.mjs.map +1 -0
  94. package/dist/effect/ports/EffectEventQueries.cjs +17 -0
  95. package/dist/effect/ports/EffectEventQueries.cjs.map +1 -0
  96. package/dist/effect/ports/EffectEventQueries.d.cts +9 -0
  97. package/dist/effect/ports/EffectEventQueries.d.ts +9 -0
  98. package/dist/effect/ports/EffectEventQueries.mjs +1 -0
  99. package/dist/effect/ports/EffectEventQueries.mjs.map +1 -0
  100. package/dist/effect/ports/EffectEventRepository.cjs +17 -0
  101. package/dist/effect/ports/EffectEventRepository.cjs.map +1 -0
  102. package/dist/effect/ports/EffectEventRepository.d.cts +17 -0
  103. package/dist/effect/ports/EffectEventRepository.d.ts +17 -0
  104. package/dist/effect/ports/EffectEventRepository.mjs +1 -0
  105. package/dist/effect/ports/EffectEventRepository.mjs.map +1 -0
  106. package/dist/filterEvents.cjs +48 -0
  107. package/dist/filterEvents.cjs.map +1 -0
  108. package/dist/filterEvents.d.cts +6 -0
  109. package/dist/filterEvents.d.ts +6 -0
  110. package/dist/filterEvents.mjs +24 -0
  111. package/dist/filterEvents.mjs.map +1 -0
  112. package/dist/getSubscriptionIdsToPublish.cjs +40 -0
  113. package/dist/getSubscriptionIdsToPublish.cjs.map +1 -0
  114. package/dist/getSubscriptionIdsToPublish.d.cts +5 -0
  115. package/dist/getSubscriptionIdsToPublish.d.ts +5 -0
  116. package/dist/getSubscriptionIdsToPublish.mjs +16 -0
  117. package/dist/getSubscriptionIdsToPublish.mjs.map +1 -0
  118. package/dist/index.d.cts +1 -1
  119. package/dist/index.d.ts +1 -1
  120. package/dist/ports/EventQueries.cjs.map +1 -1
  121. package/dist/ports/EventQueries.d.cts +1 -1
  122. package/dist/ports/EventQueries.d.ts +1 -1
  123. package/dist/splitIntoChunks.cjs +35 -0
  124. package/dist/splitIntoChunks.cjs.map +1 -0
  125. package/dist/splitIntoChunks.d.cts +3 -0
  126. package/dist/splitIntoChunks.d.ts +3 -0
  127. package/dist/splitIntoChunks.mjs +11 -0
  128. package/dist/splitIntoChunks.mjs.map +1 -0
  129. package/package.json +17 -2
  130. package/src/adapters/effect-kysely/EffectKyselyEventQueries.ts +45 -0
  131. package/src/adapters/effect-kysely/EffectKyselyEventRepository.ts +90 -0
  132. package/src/adapters/effect-kysely/index.ts +3 -0
  133. package/src/adapters/in-memory/InMemoryEventBus.ts +2 -23
  134. package/src/adapters/in-memory/InMemoryEventQueries.ts +2 -32
  135. package/src/adapters/kysely/KyselyEventQueries.ts +2 -10
  136. package/src/adapters/kysely/KyselyEventRepository.ts +2 -4
  137. package/src/adapters/kysely/jsonb.ts +4 -0
  138. package/src/adapters/kysely/mapEventRow.ts +15 -0
  139. package/src/createEventCrawler.ts +1 -8
  140. package/src/effect/EffectEventCrawler.ts +124 -0
  141. package/src/effect/EffectInMemoryEventBus.ts +231 -0
  142. package/src/effect/EffectInMemoryEventQueries.ts +16 -0
  143. package/src/effect/EffectInMemoryEventRepository.ts +68 -0
  144. package/src/effect/EffectSubscriptions.ts +74 -0
  145. package/src/effect/index.ts +26 -0
  146. package/src/effect/ports/EffectEventBus.ts +17 -0
  147. package/src/effect/ports/EffectEventQueries.ts +9 -0
  148. package/src/effect/ports/EffectEventRepository.ts +27 -0
  149. package/src/filterEvents.ts +39 -0
  150. package/src/getSubscriptionIdsToPublish.ts +21 -0
  151. package/src/ports/EventQueries.ts +1 -1
  152. package/src/splitIntoChunks.ts +7 -0
@@ -1 +1 @@
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":"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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 { getSubscriptionIdsToPublish } from '../../getSubscriptionIdsToPublish.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 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 Object.keys(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"]}
@@ -21,28 +21,10 @@ __export(InMemoryEventQueries_exports, {
21
21
  createInMemoryEventQueries: () => createInMemoryEventQueries
22
22
  });
23
23
  module.exports = __toCommonJS(InMemoryEventQueries_exports);
24
+ var import_filterEvents = require("../../filterEvents.ts");
24
25
  const createInMemoryEventQueries = (helpers) => ({
25
26
  eventQueries: {
26
- getEvents: async ({ filters, limit }) => {
27
- const matchesContext = (event) => {
28
- if (!filters.context) return true;
29
- if (!event.context) return false;
30
- return Object.entries(filters.context).every(
31
- ([key, value]) => event.context?.[key] === value
32
- );
33
- };
34
- const matchesOccurredAt = (event) => {
35
- if (!filters.occurredAt) return true;
36
- const { from, to } = filters.occurredAt;
37
- const eventTime = event.occurredAt.getTime();
38
- if (from && eventTime < from.getTime()) return false;
39
- if (to && eventTime > to.getTime()) return false;
40
- return true;
41
- };
42
- return helpers.getAllEvents().filter(
43
- (event) => filters.statuses.includes(event.status) && matchesContext(event) && matchesOccurredAt(event)
44
- ).slice(0, limit);
45
- }
27
+ getEvents: async (params) => (0, import_filterEvents.filterEvents)(helpers.getAllEvents(), params)
46
28
  }
47
29
  });
48
30
  // Annotate the CommonJS export names for ESM import in node:
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/adapters/in-memory/InMemoryEventQueries.ts"],"sourcesContent":["import type { EventQueries } from \"../../ports/EventQueries.ts\";\nimport type { DefaultContext, GenericEvent } from \"../../types.ts\";\nimport type { InMemoryEventRepositoryHelpers } from \"./InMemoryEventRepository.ts\";\n\nexport const createInMemoryEventQueries = <\n Event extends GenericEvent<string, unknown, DefaultContext>,\n>(\n helpers: InMemoryEventRepositoryHelpers<Event>,\n): { eventQueries: EventQueries<Event> } => ({\n eventQueries: {\n getEvents: async ({ filters, limit }) => {\n const matchesContext = (event: Event): boolean => {\n if (!filters.context) return true;\n if (!event.context) return false;\n\n return Object.entries(filters.context).every(\n ([key, value]) => event.context?.[key] === value,\n );\n };\n\n const matchesOccurredAt = (event: Event): boolean => {\n if (!filters.occurredAt) return true;\n\n const { from, to } = filters.occurredAt;\n const eventTime = event.occurredAt.getTime();\n\n if (from && eventTime < from.getTime()) return false;\n if (to && eventTime > to.getTime()) return false;\n\n return true;\n };\n\n return helpers\n .getAllEvents()\n .filter(\n (event) =>\n filters.statuses.includes(event.status) &&\n matchesContext(event) &&\n matchesOccurredAt(event),\n )\n .slice(0, limit);\n },\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIO,MAAM,6BAA6B,CAGxC,aAC2C;AAAA,EAC3C,cAAc;AAAA,IACZ,WAAW,OAAO,EAAE,SAAS,MAAM,MAAM;AACvC,YAAM,iBAAiB,CAAC,UAA0B;AAChD,YAAI,CAAC,QAAQ,QAAS,QAAO;AAC7B,YAAI,CAAC,MAAM,QAAS,QAAO;AAE3B,eAAO,OAAO,QAAQ,QAAQ,OAAO,EAAE;AAAA,UACrC,CAAC,CAAC,KAAK,KAAK,MAAM,MAAM,UAAU,GAAG,MAAM;AAAA,QAC7C;AAAA,MACF;AAEA,YAAM,oBAAoB,CAAC,UAA0B;AACnD,YAAI,CAAC,QAAQ,WAAY,QAAO;AAEhC,cAAM,EAAE,MAAM,GAAG,IAAI,QAAQ;AAC7B,cAAM,YAAY,MAAM,WAAW,QAAQ;AAE3C,YAAI,QAAQ,YAAY,KAAK,QAAQ,EAAG,QAAO;AAC/C,YAAI,MAAM,YAAY,GAAG,QAAQ,EAAG,QAAO;AAE3C,eAAO;AAAA,MACT;AAEA,aAAO,QACJ,aAAa,EACb;AAAA,QACC,CAAC,UACC,QAAQ,SAAS,SAAS,MAAM,MAAM,KACtC,eAAe,KAAK,KACpB,kBAAkB,KAAK;AAAA,MAC3B,EACC,MAAM,GAAG,KAAK;AAAA,IACnB;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/adapters/in-memory/InMemoryEventQueries.ts"],"sourcesContent":["import { filterEvents } from \"../../filterEvents.ts\";\nimport type { EventQueries } from \"../../ports/EventQueries.ts\";\nimport type { DefaultContext, GenericEvent } from \"../../types.ts\";\nimport type { InMemoryEventRepositoryHelpers } from \"./InMemoryEventRepository.ts\";\n\nexport const createInMemoryEventQueries = <\n Event extends GenericEvent<string, unknown, DefaultContext>,\n>(\n helpers: InMemoryEventRepositoryHelpers<Event>,\n): { eventQueries: EventQueries<Event> } => ({\n eventQueries: {\n getEvents: async (params) => filterEvents(helpers.getAllEvents(), params),\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAA6B;AAKtB,MAAM,6BAA6B,CAGxC,aAC2C;AAAA,EAC3C,cAAc;AAAA,IACZ,WAAW,OAAO,eAAW,kCAAa,QAAQ,aAAa,GAAG,MAAM;AAAA,EAC1E;AACF;","names":[]}
@@ -1,25 +1,7 @@
1
+ import { filterEvents } from "../../filterEvents.mjs";
1
2
  const createInMemoryEventQueries = (helpers) => ({
2
3
  eventQueries: {
3
- getEvents: async ({ filters, limit }) => {
4
- const matchesContext = (event) => {
5
- if (!filters.context) return true;
6
- if (!event.context) return false;
7
- return Object.entries(filters.context).every(
8
- ([key, value]) => event.context?.[key] === value
9
- );
10
- };
11
- const matchesOccurredAt = (event) => {
12
- if (!filters.occurredAt) return true;
13
- const { from, to } = filters.occurredAt;
14
- const eventTime = event.occurredAt.getTime();
15
- if (from && eventTime < from.getTime()) return false;
16
- if (to && eventTime > to.getTime()) return false;
17
- return true;
18
- };
19
- return helpers.getAllEvents().filter(
20
- (event) => filters.statuses.includes(event.status) && matchesContext(event) && matchesOccurredAt(event)
21
- ).slice(0, limit);
22
- }
4
+ getEvents: async (params) => filterEvents(helpers.getAllEvents(), params)
23
5
  }
24
6
  });
25
7
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/adapters/in-memory/InMemoryEventQueries.ts"],"sourcesContent":["import type { EventQueries } from '../../ports/EventQueries.mjs';\nimport type { DefaultContext, GenericEvent } from '../../types.mjs';\nimport type { InMemoryEventRepositoryHelpers } from './InMemoryEventRepository.mjs';\n\nexport const createInMemoryEventQueries = <\n Event extends GenericEvent<string, unknown, DefaultContext>,\n>(\n helpers: InMemoryEventRepositoryHelpers<Event>,\n): { eventQueries: EventQueries<Event> } => ({\n eventQueries: {\n getEvents: async ({ filters, limit }) => {\n const matchesContext = (event: Event): boolean => {\n if (!filters.context) return true;\n if (!event.context) return false;\n\n return Object.entries(filters.context).every(\n ([key, value]) => event.context?.[key] === value,\n );\n };\n\n const matchesOccurredAt = (event: Event): boolean => {\n if (!filters.occurredAt) return true;\n\n const { from, to } = filters.occurredAt;\n const eventTime = event.occurredAt.getTime();\n\n if (from && eventTime < from.getTime()) return false;\n if (to && eventTime > to.getTime()) return false;\n\n return true;\n };\n\n return helpers\n .getAllEvents()\n .filter(\n (event) =>\n filters.statuses.includes(event.status) &&\n matchesContext(event) &&\n matchesOccurredAt(event),\n )\n .slice(0, limit);\n },\n },\n});\n"],"mappings":"AAIO,MAAM,6BAA6B,CAGxC,aAC2C;AAAA,EAC3C,cAAc;AAAA,IACZ,WAAW,OAAO,EAAE,SAAS,MAAM,MAAM;AACvC,YAAM,iBAAiB,CAAC,UAA0B;AAChD,YAAI,CAAC,QAAQ,QAAS,QAAO;AAC7B,YAAI,CAAC,MAAM,QAAS,QAAO;AAE3B,eAAO,OAAO,QAAQ,QAAQ,OAAO,EAAE;AAAA,UACrC,CAAC,CAAC,KAAK,KAAK,MAAM,MAAM,UAAU,GAAG,MAAM;AAAA,QAC7C;AAAA,MACF;AAEA,YAAM,oBAAoB,CAAC,UAA0B;AACnD,YAAI,CAAC,QAAQ,WAAY,QAAO;AAEhC,cAAM,EAAE,MAAM,GAAG,IAAI,QAAQ;AAC7B,cAAM,YAAY,MAAM,WAAW,QAAQ;AAE3C,YAAI,QAAQ,YAAY,KAAK,QAAQ,EAAG,QAAO;AAC/C,YAAI,MAAM,YAAY,GAAG,QAAQ,EAAG,QAAO;AAE3C,eAAO;AAAA,MACT;AAEA,aAAO,QACJ,aAAa,EACb;AAAA,QACC,CAAC,UACC,QAAQ,SAAS,SAAS,MAAM,MAAM,KACtC,eAAe,KAAK,KACpB,kBAAkB,KAAK;AAAA,MAC3B,EACC,MAAM,GAAG,KAAK;AAAA,IACnB;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/adapters/in-memory/InMemoryEventQueries.ts"],"sourcesContent":["import { filterEvents } from '../../filterEvents.mjs';\nimport type { EventQueries } from '../../ports/EventQueries.mjs';\nimport type { DefaultContext, GenericEvent } from '../../types.mjs';\nimport type { InMemoryEventRepositoryHelpers } from './InMemoryEventRepository.mjs';\n\nexport const createInMemoryEventQueries = <\n Event extends GenericEvent<string, unknown, DefaultContext>,\n>(\n helpers: InMemoryEventRepositoryHelpers<Event>,\n): { eventQueries: EventQueries<Event> } => ({\n eventQueries: {\n getEvents: async (params) => filterEvents(helpers.getAllEvents(), params),\n },\n});\n"],"mappings":"AAAA,SAAS,oBAAoB;AAKtB,MAAM,6BAA6B,CAGxC,aAC2C;AAAA,EAC3C,cAAc;AAAA,IACZ,WAAW,OAAO,WAAW,aAAa,QAAQ,aAAa,GAAG,MAAM;AAAA,EAC1E;AACF;","names":[]}
@@ -22,6 +22,7 @@ __export(KyselyEventQueries_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(KyselyEventQueries_exports);
24
24
  var import_kysely = require("kysely");
25
+ var import_mapEventRow = require("./mapEventRow.ts");
25
26
  const createKyselyEventQueries = (db) => {
26
27
  const eventsDb = db;
27
28
  return {
@@ -39,15 +40,7 @@ const createKyselyEventQueries = (db) => {
39
40
  query = query.where("occurredAt", "<=", filters.occurredAt.to);
40
41
  }
41
42
  const rows = await query.execute();
42
- return rows.map(
43
- (row) => ({
44
- ...row,
45
- context: row.context ?? void 0,
46
- flowId: row.flowId ?? void 0,
47
- causedByEventId: row.causedByEventId ?? void 0,
48
- priority: row.priority ?? void 0
49
- })
50
- );
43
+ return rows.map((row) => (0, import_mapEventRow.mapEventRow)(row));
51
44
  }
52
45
  };
53
46
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/adapters/kysely/KyselyEventQueries.ts"],"sourcesContent":["import type { Kysely, SqlBool } from \"kysely\";\nimport { sql } from \"kysely\";\nimport type { EventQueries } from \"../../ports/EventQueries.ts\";\nimport type { DefaultContext, GenericEvent } from \"../../types.ts\";\nimport type { EventsTable } from \"./types.ts\";\n\nexport const createKyselyEventQueries = <\n Event extends GenericEvent<string, unknown, DefaultContext>,\n DB extends EventsTable = EventsTable,\n>(\n db: Kysely<DB>,\n): EventQueries<Event> => {\n const eventsDb = db as unknown as Kysely<EventsTable>;\n return {\n getEvents: async ({ filters, limit }) => {\n let query = eventsDb\n .selectFrom(\"events\")\n .selectAll()\n .where(\"status\", \"in\", filters.statuses)\n .limit(limit);\n\n if (filters.context) {\n for (const [key, value] of Object.entries(filters.context)) {\n query = query.where(sql<SqlBool>`context->>${key} = ${value}`);\n }\n }\n\n if (filters.occurredAt?.from) {\n query = query.where(\"occurredAt\", \">=\", filters.occurredAt.from);\n }\n\n if (filters.occurredAt?.to) {\n query = query.where(\"occurredAt\", \"<=\", filters.occurredAt.to);\n }\n\n const rows = await query.execute();\n return rows.map(\n (row: EventsTable[\"events\"]) =>\n ({\n ...row,\n context: row.context ?? undefined,\n flowId: row.flowId ?? undefined,\n causedByEventId: row.causedByEventId ?? undefined,\n priority: row.priority ?? undefined,\n }) as Event,\n );\n },\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,oBAAoB;AAKb,MAAM,2BAA2B,CAItC,OACwB;AACxB,QAAM,WAAW;AACjB,SAAO;AAAA,IACL,WAAW,OAAO,EAAE,SAAS,MAAM,MAAM;AACvC,UAAI,QAAQ,SACT,WAAW,QAAQ,EACnB,UAAU,EACV,MAAM,UAAU,MAAM,QAAQ,QAAQ,EACtC,MAAM,KAAK;AAEd,UAAI,QAAQ,SAAS;AACnB,mBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,OAAO,GAAG;AAC1D,kBAAQ,MAAM,MAAM,8BAAyB,GAAG,MAAM,KAAK,EAAE;AAAA,QAC/D;AAAA,MACF;AAEA,UAAI,QAAQ,YAAY,MAAM;AAC5B,gBAAQ,MAAM,MAAM,cAAc,MAAM,QAAQ,WAAW,IAAI;AAAA,MACjE;AAEA,UAAI,QAAQ,YAAY,IAAI;AAC1B,gBAAQ,MAAM,MAAM,cAAc,MAAM,QAAQ,WAAW,EAAE;AAAA,MAC/D;AAEA,YAAM,OAAO,MAAM,MAAM,QAAQ;AACjC,aAAO,KAAK;AAAA,QACV,CAAC,SACE;AAAA,UACC,GAAG;AAAA,UACH,SAAS,IAAI,WAAW;AAAA,UACxB,QAAQ,IAAI,UAAU;AAAA,UACtB,iBAAiB,IAAI,mBAAmB;AAAA,UACxC,UAAU,IAAI,YAAY;AAAA,QAC5B;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/adapters/kysely/KyselyEventQueries.ts"],"sourcesContent":["import type { Kysely, SqlBool } from \"kysely\";\nimport { sql } from \"kysely\";\nimport type { EventQueries } from \"../../ports/EventQueries.ts\";\nimport type { DefaultContext, GenericEvent } from \"../../types.ts\";\nimport { mapEventRow } from \"./mapEventRow.ts\";\nimport type { EventsTable } from \"./types.ts\";\n\nexport const createKyselyEventQueries = <\n Event extends GenericEvent<string, unknown, DefaultContext>,\n DB extends EventsTable = EventsTable,\n>(\n db: Kysely<DB>,\n): EventQueries<Event> => {\n const eventsDb = db as unknown as Kysely<EventsTable>;\n return {\n getEvents: async ({ filters, limit }) => {\n let query = eventsDb\n .selectFrom(\"events\")\n .selectAll()\n .where(\"status\", \"in\", filters.statuses)\n .limit(limit);\n\n if (filters.context) {\n for (const [key, value] of Object.entries(filters.context)) {\n query = query.where(sql<SqlBool>`context->>${key} = ${value}`);\n }\n }\n\n if (filters.occurredAt?.from) {\n query = query.where(\"occurredAt\", \">=\", filters.occurredAt.from);\n }\n\n if (filters.occurredAt?.to) {\n query = query.where(\"occurredAt\", \"<=\", filters.occurredAt.to);\n }\n\n const rows = await query.execute();\n return rows.map((row: EventsTable[\"events\"]) => mapEventRow<Event>(row));\n },\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,oBAAoB;AAGpB,yBAA4B;AAGrB,MAAM,2BAA2B,CAItC,OACwB;AACxB,QAAM,WAAW;AACjB,SAAO;AAAA,IACL,WAAW,OAAO,EAAE,SAAS,MAAM,MAAM;AACvC,UAAI,QAAQ,SACT,WAAW,QAAQ,EACnB,UAAU,EACV,MAAM,UAAU,MAAM,QAAQ,QAAQ,EACtC,MAAM,KAAK;AAEd,UAAI,QAAQ,SAAS;AACnB,mBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,OAAO,GAAG;AAC1D,kBAAQ,MAAM,MAAM,8BAAyB,GAAG,MAAM,KAAK,EAAE;AAAA,QAC/D;AAAA,MACF;AAEA,UAAI,QAAQ,YAAY,MAAM;AAC5B,gBAAQ,MAAM,MAAM,cAAc,MAAM,QAAQ,WAAW,IAAI;AAAA,MACjE;AAEA,UAAI,QAAQ,YAAY,IAAI;AAC1B,gBAAQ,MAAM,MAAM,cAAc,MAAM,QAAQ,WAAW,EAAE;AAAA,MAC/D;AAEA,YAAM,OAAO,MAAM,MAAM,QAAQ;AACjC,aAAO,KAAK,IAAI,CAAC,YAA+B,gCAAmB,GAAG,CAAC;AAAA,IACzE;AAAA,EACF;AACF;","names":[]}
@@ -1,4 +1,5 @@
1
1
  import { sql } from "kysely";
2
+ import { mapEventRow } from "./mapEventRow.mjs";
2
3
  const createKyselyEventQueries = (db) => {
3
4
  const eventsDb = db;
4
5
  return {
@@ -16,15 +17,7 @@ const createKyselyEventQueries = (db) => {
16
17
  query = query.where("occurredAt", "<=", filters.occurredAt.to);
17
18
  }
18
19
  const rows = await query.execute();
19
- return rows.map(
20
- (row) => ({
21
- ...row,
22
- context: row.context ?? void 0,
23
- flowId: row.flowId ?? void 0,
24
- causedByEventId: row.causedByEventId ?? void 0,
25
- priority: row.priority ?? void 0
26
- })
27
- );
20
+ return rows.map((row) => mapEventRow(row));
28
21
  }
29
22
  };
30
23
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/adapters/kysely/KyselyEventQueries.ts"],"sourcesContent":["import type { Kysely, SqlBool } from \"kysely\";\nimport { sql } from \"kysely\";\nimport type { EventQueries } from '../../ports/EventQueries.mjs';\nimport type { DefaultContext, GenericEvent } from '../../types.mjs';\nimport type { EventsTable } from './types.mjs';\n\nexport const createKyselyEventQueries = <\n Event extends GenericEvent<string, unknown, DefaultContext>,\n DB extends EventsTable = EventsTable,\n>(\n db: Kysely<DB>,\n): EventQueries<Event> => {\n const eventsDb = db as unknown as Kysely<EventsTable>;\n return {\n getEvents: async ({ filters, limit }) => {\n let query = eventsDb\n .selectFrom(\"events\")\n .selectAll()\n .where(\"status\", \"in\", filters.statuses)\n .limit(limit);\n\n if (filters.context) {\n for (const [key, value] of Object.entries(filters.context)) {\n query = query.where(sql<SqlBool>`context->>${key} = ${value}`);\n }\n }\n\n if (filters.occurredAt?.from) {\n query = query.where(\"occurredAt\", \">=\", filters.occurredAt.from);\n }\n\n if (filters.occurredAt?.to) {\n query = query.where(\"occurredAt\", \"<=\", filters.occurredAt.to);\n }\n\n const rows = await query.execute();\n return rows.map(\n (row: EventsTable[\"events\"]) =>\n ({\n ...row,\n context: row.context ?? undefined,\n flowId: row.flowId ?? undefined,\n causedByEventId: row.causedByEventId ?? undefined,\n priority: row.priority ?? undefined,\n }) as Event,\n );\n },\n };\n};\n"],"mappings":"AACA,SAAS,WAAW;AAKb,MAAM,2BAA2B,CAItC,OACwB;AACxB,QAAM,WAAW;AACjB,SAAO;AAAA,IACL,WAAW,OAAO,EAAE,SAAS,MAAM,MAAM;AACvC,UAAI,QAAQ,SACT,WAAW,QAAQ,EACnB,UAAU,EACV,MAAM,UAAU,MAAM,QAAQ,QAAQ,EACtC,MAAM,KAAK;AAEd,UAAI,QAAQ,SAAS;AACnB,mBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,OAAO,GAAG;AAC1D,kBAAQ,MAAM,MAAM,gBAAyB,GAAG,MAAM,KAAK,EAAE;AAAA,QAC/D;AAAA,MACF;AAEA,UAAI,QAAQ,YAAY,MAAM;AAC5B,gBAAQ,MAAM,MAAM,cAAc,MAAM,QAAQ,WAAW,IAAI;AAAA,MACjE;AAEA,UAAI,QAAQ,YAAY,IAAI;AAC1B,gBAAQ,MAAM,MAAM,cAAc,MAAM,QAAQ,WAAW,EAAE;AAAA,MAC/D;AAEA,YAAM,OAAO,MAAM,MAAM,QAAQ;AACjC,aAAO,KAAK;AAAA,QACV,CAAC,SACE;AAAA,UACC,GAAG;AAAA,UACH,SAAS,IAAI,WAAW;AAAA,UACxB,QAAQ,IAAI,UAAU;AAAA,UACtB,iBAAiB,IAAI,mBAAmB;AAAA,UACxC,UAAU,IAAI,YAAY;AAAA,QAC5B;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/adapters/kysely/KyselyEventQueries.ts"],"sourcesContent":["import type { Kysely, SqlBool } from \"kysely\";\nimport { sql } from \"kysely\";\nimport type { EventQueries } from '../../ports/EventQueries.mjs';\nimport type { DefaultContext, GenericEvent } from '../../types.mjs';\nimport { mapEventRow } from './mapEventRow.mjs';\nimport type { EventsTable } from './types.mjs';\n\nexport const createKyselyEventQueries = <\n Event extends GenericEvent<string, unknown, DefaultContext>,\n DB extends EventsTable = EventsTable,\n>(\n db: Kysely<DB>,\n): EventQueries<Event> => {\n const eventsDb = db as unknown as Kysely<EventsTable>;\n return {\n getEvents: async ({ filters, limit }) => {\n let query = eventsDb\n .selectFrom(\"events\")\n .selectAll()\n .where(\"status\", \"in\", filters.statuses)\n .limit(limit);\n\n if (filters.context) {\n for (const [key, value] of Object.entries(filters.context)) {\n query = query.where(sql<SqlBool>`context->>${key} = ${value}`);\n }\n }\n\n if (filters.occurredAt?.from) {\n query = query.where(\"occurredAt\", \">=\", filters.occurredAt.from);\n }\n\n if (filters.occurredAt?.to) {\n query = query.where(\"occurredAt\", \"<=\", filters.occurredAt.to);\n }\n\n const rows = await query.execute();\n return rows.map((row: EventsTable[\"events\"]) => mapEventRow<Event>(row));\n },\n };\n};\n"],"mappings":"AACA,SAAS,WAAW;AAGpB,SAAS,mBAAmB;AAGrB,MAAM,2BAA2B,CAItC,OACwB;AACxB,QAAM,WAAW;AACjB,SAAO;AAAA,IACL,WAAW,OAAO,EAAE,SAAS,MAAM,MAAM;AACvC,UAAI,QAAQ,SACT,WAAW,QAAQ,EACnB,UAAU,EACV,MAAM,UAAU,MAAM,QAAQ,QAAQ,EACtC,MAAM,KAAK;AAEd,UAAI,QAAQ,SAAS;AACnB,mBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,OAAO,GAAG;AAC1D,kBAAQ,MAAM,MAAM,gBAAyB,GAAG,MAAM,KAAK,EAAE;AAAA,QAC/D;AAAA,MACF;AAEA,UAAI,QAAQ,YAAY,MAAM;AAC5B,gBAAQ,MAAM,MAAM,cAAc,MAAM,QAAQ,WAAW,IAAI;AAAA,MACjE;AAEA,UAAI,QAAQ,YAAY,IAAI;AAC1B,gBAAQ,MAAM,MAAM,cAAc,MAAM,QAAQ,WAAW,EAAE;AAAA,MAC/D;AAEA,YAAM,OAAO,MAAM,MAAM,QAAQ;AACjC,aAAO,KAAK,IAAI,CAAC,QAA+B,YAAmB,GAAG,CAAC;AAAA,IACzE;AAAA,EACF;AACF;","names":[]}
@@ -21,29 +21,28 @@ __export(KyselyEventRepository_exports, {
21
21
  createKyselyEventRepository: () => createKyselyEventRepository
22
22
  });
23
23
  module.exports = __toCommonJS(KyselyEventRepository_exports);
24
- var import_kysely = require("kysely");
25
- const jsonb = (value) => import_kysely.sql`${JSON.stringify(value)}::jsonb`;
24
+ var import_jsonb = require("./jsonb.ts");
26
25
  const createKyselyEventRepository = (db) => {
27
26
  const eventsDb = db;
28
27
  return {
29
28
  save: async (event) => {
30
29
  await eventsDb.insertInto("events").values({
31
30
  ...event,
32
- payload: jsonb(event.payload),
33
- triggeredByActor: jsonb(event.triggeredByActor),
34
- context: jsonb(event.context),
35
- publications: jsonb(event.publications)
31
+ payload: (0, import_jsonb.jsonb)(event.payload),
32
+ triggeredByActor: (0, import_jsonb.jsonb)(event.triggeredByActor),
33
+ context: (0, import_jsonb.jsonb)(event.context),
34
+ publications: (0, import_jsonb.jsonb)(event.publications)
36
35
  }).onConflict(
37
36
  (oc) => oc.column("id").doUpdateSet({
38
37
  topic: event.topic,
39
- payload: jsonb(event.payload),
40
- triggeredByActor: jsonb(event.triggeredByActor),
41
- context: jsonb(event.context),
38
+ payload: (0, import_jsonb.jsonb)(event.payload),
39
+ triggeredByActor: (0, import_jsonb.jsonb)(event.triggeredByActor),
40
+ context: (0, import_jsonb.jsonb)(event.context),
42
41
  status: event.status,
43
42
  flowId: event.flowId,
44
43
  causedByEventId: event.causedByEventId,
45
44
  occurredAt: event.occurredAt,
46
- publications: jsonb(event.publications),
45
+ publications: (0, import_jsonb.jsonb)(event.publications),
47
46
  priority: event.priority
48
47
  })
49
48
  ).execute();
@@ -53,10 +52,10 @@ const createKyselyEventRepository = (db) => {
53
52
  await eventsDb.insertInto("events").values(
54
53
  events.map((event) => ({
55
54
  ...event,
56
- payload: jsonb(event.payload),
57
- triggeredByActor: jsonb(event.triggeredByActor),
58
- context: jsonb(event.context),
59
- publications: jsonb(event.publications)
55
+ payload: (0, import_jsonb.jsonb)(event.payload),
56
+ triggeredByActor: (0, import_jsonb.jsonb)(event.triggeredByActor),
57
+ context: (0, import_jsonb.jsonb)(event.context),
58
+ publications: (0, import_jsonb.jsonb)(event.publications)
60
59
  }))
61
60
  ).execute();
62
61
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/adapters/kysely/KyselyEventRepository.ts"],"sourcesContent":["import { type Kysely, type RawBuilder, sql } from \"kysely\";\nimport type { EventRepository } from \"../../ports/EventRepository.ts\";\nimport type { DefaultContext, GenericEvent } from \"../../types.ts\";\nimport type { EventsTable } from \"./types.ts\";\n\nconst jsonb = <T>(value: T): RawBuilder<T> =>\n sql`${JSON.stringify(value)}::jsonb`;\n\nexport const createKyselyEventRepository = <\n Event extends GenericEvent<string, unknown, DefaultContext>,\n DB extends EventsTable = EventsTable,\n>(\n db: Kysely<DB>,\n): EventRepository<Event> => {\n const eventsDb = db as unknown as Kysely<EventsTable>;\n return {\n save: async (event) => {\n await eventsDb\n .insertInto(\"events\")\n .values({\n ...event,\n payload: jsonb(event.payload),\n triggeredByActor: jsonb(event.triggeredByActor),\n context: jsonb(event.context),\n publications: jsonb(event.publications),\n })\n .onConflict((oc) =>\n oc.column(\"id\").doUpdateSet({\n topic: event.topic,\n payload: jsonb(event.payload),\n triggeredByActor: jsonb(event.triggeredByActor),\n context: jsonb(event.context),\n status: event.status,\n flowId: event.flowId,\n causedByEventId: event.causedByEventId,\n occurredAt: event.occurredAt,\n publications: jsonb(event.publications),\n priority: event.priority,\n }),\n )\n .execute();\n },\n\n saveNewEventsBatch: async (events) => {\n if (events.length === 0) return;\n await eventsDb\n .insertInto(\"events\")\n .values(\n events.map((event) => ({\n ...event,\n payload: jsonb(event.payload),\n triggeredByActor: jsonb(event.triggeredByActor),\n context: jsonb(event.context),\n publications: jsonb(event.publications),\n })),\n )\n .execute();\n },\n\n markEventsAsInProcess: async (events) => {\n if (events.length === 0) return;\n const ids = events.map((e) => e.id);\n\n // Lock the rows to prevent concurrent processing\n const lockedRows = await eventsDb\n .selectFrom(\"events\")\n .select(\"id\")\n .where(\"id\", \"in\", ids)\n .forUpdate()\n .skipLocked()\n .execute();\n\n if (lockedRows.length === 0) return;\n const lockedIds = lockedRows.map((r) => r.id);\n\n // Update status to in-process (only for locked rows)\n await eventsDb\n .updateTable(\"events\")\n .set({ status: \"in-process\" })\n .where(\"id\", \"in\", lockedIds)\n .execute();\n },\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAkD;AAKlD,MAAM,QAAQ,CAAI,UAChB,oBAAM,KAAK,UAAU,KAAK,CAAC;AAEtB,MAAM,8BAA8B,CAIzC,OAC2B;AAC3B,QAAM,WAAW;AACjB,SAAO;AAAA,IACL,MAAM,OAAO,UAAU;AACrB,YAAM,SACH,WAAW,QAAQ,EACnB,OAAO;AAAA,QACN,GAAG;AAAA,QACH,SAAS,MAAM,MAAM,OAAO;AAAA,QAC5B,kBAAkB,MAAM,MAAM,gBAAgB;AAAA,QAC9C,SAAS,MAAM,MAAM,OAAO;AAAA,QAC5B,cAAc,MAAM,MAAM,YAAY;AAAA,MACxC,CAAC,EACA;AAAA,QAAW,CAAC,OACX,GAAG,OAAO,IAAI,EAAE,YAAY;AAAA,UAC1B,OAAO,MAAM;AAAA,UACb,SAAS,MAAM,MAAM,OAAO;AAAA,UAC5B,kBAAkB,MAAM,MAAM,gBAAgB;AAAA,UAC9C,SAAS,MAAM,MAAM,OAAO;AAAA,UAC5B,QAAQ,MAAM;AAAA,UACd,QAAQ,MAAM;AAAA,UACd,iBAAiB,MAAM;AAAA,UACvB,YAAY,MAAM;AAAA,UAClB,cAAc,MAAM,MAAM,YAAY;AAAA,UACtC,UAAU,MAAM;AAAA,QAClB,CAAC;AAAA,MACH,EACC,QAAQ;AAAA,IACb;AAAA,IAEA,oBAAoB,OAAO,WAAW;AACpC,UAAI,OAAO,WAAW,EAAG;AACzB,YAAM,SACH,WAAW,QAAQ,EACnB;AAAA,QACC,OAAO,IAAI,CAAC,WAAW;AAAA,UACrB,GAAG;AAAA,UACH,SAAS,MAAM,MAAM,OAAO;AAAA,UAC5B,kBAAkB,MAAM,MAAM,gBAAgB;AAAA,UAC9C,SAAS,MAAM,MAAM,OAAO;AAAA,UAC5B,cAAc,MAAM,MAAM,YAAY;AAAA,QACxC,EAAE;AAAA,MACJ,EACC,QAAQ;AAAA,IACb;AAAA,IAEA,uBAAuB,OAAO,WAAW;AACvC,UAAI,OAAO,WAAW,EAAG;AACzB,YAAM,MAAM,OAAO,IAAI,CAAC,MAAM,EAAE,EAAE;AAGlC,YAAM,aAAa,MAAM,SACtB,WAAW,QAAQ,EACnB,OAAO,IAAI,EACX,MAAM,MAAM,MAAM,GAAG,EACrB,UAAU,EACV,WAAW,EACX,QAAQ;AAEX,UAAI,WAAW,WAAW,EAAG;AAC7B,YAAM,YAAY,WAAW,IAAI,CAAC,MAAM,EAAE,EAAE;AAG5C,YAAM,SACH,YAAY,QAAQ,EACpB,IAAI,EAAE,QAAQ,aAAa,CAAC,EAC5B,MAAM,MAAM,MAAM,SAAS,EAC3B,QAAQ;AAAA,IACb;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/adapters/kysely/KyselyEventRepository.ts"],"sourcesContent":["import type { Kysely } from \"kysely\";\nimport type { EventRepository } from \"../../ports/EventRepository.ts\";\nimport type { DefaultContext, GenericEvent } from \"../../types.ts\";\nimport { jsonb } from \"./jsonb.ts\";\nimport type { EventsTable } from \"./types.ts\";\n\nexport const createKyselyEventRepository = <\n Event extends GenericEvent<string, unknown, DefaultContext>,\n DB extends EventsTable = EventsTable,\n>(\n db: Kysely<DB>,\n): EventRepository<Event> => {\n const eventsDb = db as unknown as Kysely<EventsTable>;\n return {\n save: async (event) => {\n await eventsDb\n .insertInto(\"events\")\n .values({\n ...event,\n payload: jsonb(event.payload),\n triggeredByActor: jsonb(event.triggeredByActor),\n context: jsonb(event.context),\n publications: jsonb(event.publications),\n })\n .onConflict((oc) =>\n oc.column(\"id\").doUpdateSet({\n topic: event.topic,\n payload: jsonb(event.payload),\n triggeredByActor: jsonb(event.triggeredByActor),\n context: jsonb(event.context),\n status: event.status,\n flowId: event.flowId,\n causedByEventId: event.causedByEventId,\n occurredAt: event.occurredAt,\n publications: jsonb(event.publications),\n priority: event.priority,\n }),\n )\n .execute();\n },\n\n saveNewEventsBatch: async (events) => {\n if (events.length === 0) return;\n await eventsDb\n .insertInto(\"events\")\n .values(\n events.map((event) => ({\n ...event,\n payload: jsonb(event.payload),\n triggeredByActor: jsonb(event.triggeredByActor),\n context: jsonb(event.context),\n publications: jsonb(event.publications),\n })),\n )\n .execute();\n },\n\n markEventsAsInProcess: async (events) => {\n if (events.length === 0) return;\n const ids = events.map((e) => e.id);\n\n // Lock the rows to prevent concurrent processing\n const lockedRows = await eventsDb\n .selectFrom(\"events\")\n .select(\"id\")\n .where(\"id\", \"in\", ids)\n .forUpdate()\n .skipLocked()\n .execute();\n\n if (lockedRows.length === 0) return;\n const lockedIds = lockedRows.map((r) => r.id);\n\n // Update status to in-process (only for locked rows)\n await eventsDb\n .updateTable(\"events\")\n .set({ status: \"in-process\" })\n .where(\"id\", \"in\", lockedIds)\n .execute();\n },\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,mBAAsB;AAGf,MAAM,8BAA8B,CAIzC,OAC2B;AAC3B,QAAM,WAAW;AACjB,SAAO;AAAA,IACL,MAAM,OAAO,UAAU;AACrB,YAAM,SACH,WAAW,QAAQ,EACnB,OAAO;AAAA,QACN,GAAG;AAAA,QACH,aAAS,oBAAM,MAAM,OAAO;AAAA,QAC5B,sBAAkB,oBAAM,MAAM,gBAAgB;AAAA,QAC9C,aAAS,oBAAM,MAAM,OAAO;AAAA,QAC5B,kBAAc,oBAAM,MAAM,YAAY;AAAA,MACxC,CAAC,EACA;AAAA,QAAW,CAAC,OACX,GAAG,OAAO,IAAI,EAAE,YAAY;AAAA,UAC1B,OAAO,MAAM;AAAA,UACb,aAAS,oBAAM,MAAM,OAAO;AAAA,UAC5B,sBAAkB,oBAAM,MAAM,gBAAgB;AAAA,UAC9C,aAAS,oBAAM,MAAM,OAAO;AAAA,UAC5B,QAAQ,MAAM;AAAA,UACd,QAAQ,MAAM;AAAA,UACd,iBAAiB,MAAM;AAAA,UACvB,YAAY,MAAM;AAAA,UAClB,kBAAc,oBAAM,MAAM,YAAY;AAAA,UACtC,UAAU,MAAM;AAAA,QAClB,CAAC;AAAA,MACH,EACC,QAAQ;AAAA,IACb;AAAA,IAEA,oBAAoB,OAAO,WAAW;AACpC,UAAI,OAAO,WAAW,EAAG;AACzB,YAAM,SACH,WAAW,QAAQ,EACnB;AAAA,QACC,OAAO,IAAI,CAAC,WAAW;AAAA,UACrB,GAAG;AAAA,UACH,aAAS,oBAAM,MAAM,OAAO;AAAA,UAC5B,sBAAkB,oBAAM,MAAM,gBAAgB;AAAA,UAC9C,aAAS,oBAAM,MAAM,OAAO;AAAA,UAC5B,kBAAc,oBAAM,MAAM,YAAY;AAAA,QACxC,EAAE;AAAA,MACJ,EACC,QAAQ;AAAA,IACb;AAAA,IAEA,uBAAuB,OAAO,WAAW;AACvC,UAAI,OAAO,WAAW,EAAG;AACzB,YAAM,MAAM,OAAO,IAAI,CAAC,MAAM,EAAE,EAAE;AAGlC,YAAM,aAAa,MAAM,SACtB,WAAW,QAAQ,EACnB,OAAO,IAAI,EACX,MAAM,MAAM,MAAM,GAAG,EACrB,UAAU,EACV,WAAW,EACX,QAAQ;AAEX,UAAI,WAAW,WAAW,EAAG;AAC7B,YAAM,YAAY,WAAW,IAAI,CAAC,MAAM,EAAE,EAAE;AAG5C,YAAM,SACH,YAAY,QAAQ,EACpB,IAAI,EAAE,QAAQ,aAAa,CAAC,EAC5B,MAAM,MAAM,MAAM,SAAS,EAC3B,QAAQ;AAAA,IACb;AAAA,EACF;AACF;","names":[]}
@@ -1,5 +1,4 @@
1
- import { sql } from "kysely";
2
- const jsonb = (value) => sql`${JSON.stringify(value)}::jsonb`;
1
+ import { jsonb } from "./jsonb.mjs";
3
2
  const createKyselyEventRepository = (db) => {
4
3
  const eventsDb = db;
5
4
  return {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/adapters/kysely/KyselyEventRepository.ts"],"sourcesContent":["import { type Kysely, type RawBuilder, sql } from \"kysely\";\nimport type { EventRepository } from '../../ports/EventRepository.mjs';\nimport type { DefaultContext, GenericEvent } from '../../types.mjs';\nimport type { EventsTable } from './types.mjs';\n\nconst jsonb = <T>(value: T): RawBuilder<T> =>\n sql`${JSON.stringify(value)}::jsonb`;\n\nexport const createKyselyEventRepository = <\n Event extends GenericEvent<string, unknown, DefaultContext>,\n DB extends EventsTable = EventsTable,\n>(\n db: Kysely<DB>,\n): EventRepository<Event> => {\n const eventsDb = db as unknown as Kysely<EventsTable>;\n return {\n save: async (event) => {\n await eventsDb\n .insertInto(\"events\")\n .values({\n ...event,\n payload: jsonb(event.payload),\n triggeredByActor: jsonb(event.triggeredByActor),\n context: jsonb(event.context),\n publications: jsonb(event.publications),\n })\n .onConflict((oc) =>\n oc.column(\"id\").doUpdateSet({\n topic: event.topic,\n payload: jsonb(event.payload),\n triggeredByActor: jsonb(event.triggeredByActor),\n context: jsonb(event.context),\n status: event.status,\n flowId: event.flowId,\n causedByEventId: event.causedByEventId,\n occurredAt: event.occurredAt,\n publications: jsonb(event.publications),\n priority: event.priority,\n }),\n )\n .execute();\n },\n\n saveNewEventsBatch: async (events) => {\n if (events.length === 0) return;\n await eventsDb\n .insertInto(\"events\")\n .values(\n events.map((event) => ({\n ...event,\n payload: jsonb(event.payload),\n triggeredByActor: jsonb(event.triggeredByActor),\n context: jsonb(event.context),\n publications: jsonb(event.publications),\n })),\n )\n .execute();\n },\n\n markEventsAsInProcess: async (events) => {\n if (events.length === 0) return;\n const ids = events.map((e) => e.id);\n\n // Lock the rows to prevent concurrent processing\n const lockedRows = await eventsDb\n .selectFrom(\"events\")\n .select(\"id\")\n .where(\"id\", \"in\", ids)\n .forUpdate()\n .skipLocked()\n .execute();\n\n if (lockedRows.length === 0) return;\n const lockedIds = lockedRows.map((r) => r.id);\n\n // Update status to in-process (only for locked rows)\n await eventsDb\n .updateTable(\"events\")\n .set({ status: \"in-process\" })\n .where(\"id\", \"in\", lockedIds)\n .execute();\n },\n };\n};\n"],"mappings":"AAAA,SAAuC,WAAW;AAKlD,MAAM,QAAQ,CAAI,UAChB,MAAM,KAAK,UAAU,KAAK,CAAC;AAEtB,MAAM,8BAA8B,CAIzC,OAC2B;AAC3B,QAAM,WAAW;AACjB,SAAO;AAAA,IACL,MAAM,OAAO,UAAU;AACrB,YAAM,SACH,WAAW,QAAQ,EACnB,OAAO;AAAA,QACN,GAAG;AAAA,QACH,SAAS,MAAM,MAAM,OAAO;AAAA,QAC5B,kBAAkB,MAAM,MAAM,gBAAgB;AAAA,QAC9C,SAAS,MAAM,MAAM,OAAO;AAAA,QAC5B,cAAc,MAAM,MAAM,YAAY;AAAA,MACxC,CAAC,EACA;AAAA,QAAW,CAAC,OACX,GAAG,OAAO,IAAI,EAAE,YAAY;AAAA,UAC1B,OAAO,MAAM;AAAA,UACb,SAAS,MAAM,MAAM,OAAO;AAAA,UAC5B,kBAAkB,MAAM,MAAM,gBAAgB;AAAA,UAC9C,SAAS,MAAM,MAAM,OAAO;AAAA,UAC5B,QAAQ,MAAM;AAAA,UACd,QAAQ,MAAM;AAAA,UACd,iBAAiB,MAAM;AAAA,UACvB,YAAY,MAAM;AAAA,UAClB,cAAc,MAAM,MAAM,YAAY;AAAA,UACtC,UAAU,MAAM;AAAA,QAClB,CAAC;AAAA,MACH,EACC,QAAQ;AAAA,IACb;AAAA,IAEA,oBAAoB,OAAO,WAAW;AACpC,UAAI,OAAO,WAAW,EAAG;AACzB,YAAM,SACH,WAAW,QAAQ,EACnB;AAAA,QACC,OAAO,IAAI,CAAC,WAAW;AAAA,UACrB,GAAG;AAAA,UACH,SAAS,MAAM,MAAM,OAAO;AAAA,UAC5B,kBAAkB,MAAM,MAAM,gBAAgB;AAAA,UAC9C,SAAS,MAAM,MAAM,OAAO;AAAA,UAC5B,cAAc,MAAM,MAAM,YAAY;AAAA,QACxC,EAAE;AAAA,MACJ,EACC,QAAQ;AAAA,IACb;AAAA,IAEA,uBAAuB,OAAO,WAAW;AACvC,UAAI,OAAO,WAAW,EAAG;AACzB,YAAM,MAAM,OAAO,IAAI,CAAC,MAAM,EAAE,EAAE;AAGlC,YAAM,aAAa,MAAM,SACtB,WAAW,QAAQ,EACnB,OAAO,IAAI,EACX,MAAM,MAAM,MAAM,GAAG,EACrB,UAAU,EACV,WAAW,EACX,QAAQ;AAEX,UAAI,WAAW,WAAW,EAAG;AAC7B,YAAM,YAAY,WAAW,IAAI,CAAC,MAAM,EAAE,EAAE;AAG5C,YAAM,SACH,YAAY,QAAQ,EACpB,IAAI,EAAE,QAAQ,aAAa,CAAC,EAC5B,MAAM,MAAM,MAAM,SAAS,EAC3B,QAAQ;AAAA,IACb;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/adapters/kysely/KyselyEventRepository.ts"],"sourcesContent":["import type { Kysely } from \"kysely\";\nimport type { EventRepository } from '../../ports/EventRepository.mjs';\nimport type { DefaultContext, GenericEvent } from '../../types.mjs';\nimport { jsonb } from './jsonb.mjs';\nimport type { EventsTable } from './types.mjs';\n\nexport const createKyselyEventRepository = <\n Event extends GenericEvent<string, unknown, DefaultContext>,\n DB extends EventsTable = EventsTable,\n>(\n db: Kysely<DB>,\n): EventRepository<Event> => {\n const eventsDb = db as unknown as Kysely<EventsTable>;\n return {\n save: async (event) => {\n await eventsDb\n .insertInto(\"events\")\n .values({\n ...event,\n payload: jsonb(event.payload),\n triggeredByActor: jsonb(event.triggeredByActor),\n context: jsonb(event.context),\n publications: jsonb(event.publications),\n })\n .onConflict((oc) =>\n oc.column(\"id\").doUpdateSet({\n topic: event.topic,\n payload: jsonb(event.payload),\n triggeredByActor: jsonb(event.triggeredByActor),\n context: jsonb(event.context),\n status: event.status,\n flowId: event.flowId,\n causedByEventId: event.causedByEventId,\n occurredAt: event.occurredAt,\n publications: jsonb(event.publications),\n priority: event.priority,\n }),\n )\n .execute();\n },\n\n saveNewEventsBatch: async (events) => {\n if (events.length === 0) return;\n await eventsDb\n .insertInto(\"events\")\n .values(\n events.map((event) => ({\n ...event,\n payload: jsonb(event.payload),\n triggeredByActor: jsonb(event.triggeredByActor),\n context: jsonb(event.context),\n publications: jsonb(event.publications),\n })),\n )\n .execute();\n },\n\n markEventsAsInProcess: async (events) => {\n if (events.length === 0) return;\n const ids = events.map((e) => e.id);\n\n // Lock the rows to prevent concurrent processing\n const lockedRows = await eventsDb\n .selectFrom(\"events\")\n .select(\"id\")\n .where(\"id\", \"in\", ids)\n .forUpdate()\n .skipLocked()\n .execute();\n\n if (lockedRows.length === 0) return;\n const lockedIds = lockedRows.map((r) => r.id);\n\n // Update status to in-process (only for locked rows)\n await eventsDb\n .updateTable(\"events\")\n .set({ status: \"in-process\" })\n .where(\"id\", \"in\", lockedIds)\n .execute();\n },\n };\n};\n"],"mappings":"AAGA,SAAS,aAAa;AAGf,MAAM,8BAA8B,CAIzC,OAC2B;AAC3B,QAAM,WAAW;AACjB,SAAO;AAAA,IACL,MAAM,OAAO,UAAU;AACrB,YAAM,SACH,WAAW,QAAQ,EACnB,OAAO;AAAA,QACN,GAAG;AAAA,QACH,SAAS,MAAM,MAAM,OAAO;AAAA,QAC5B,kBAAkB,MAAM,MAAM,gBAAgB;AAAA,QAC9C,SAAS,MAAM,MAAM,OAAO;AAAA,QAC5B,cAAc,MAAM,MAAM,YAAY;AAAA,MACxC,CAAC,EACA;AAAA,QAAW,CAAC,OACX,GAAG,OAAO,IAAI,EAAE,YAAY;AAAA,UAC1B,OAAO,MAAM;AAAA,UACb,SAAS,MAAM,MAAM,OAAO;AAAA,UAC5B,kBAAkB,MAAM,MAAM,gBAAgB;AAAA,UAC9C,SAAS,MAAM,MAAM,OAAO;AAAA,UAC5B,QAAQ,MAAM;AAAA,UACd,QAAQ,MAAM;AAAA,UACd,iBAAiB,MAAM;AAAA,UACvB,YAAY,MAAM;AAAA,UAClB,cAAc,MAAM,MAAM,YAAY;AAAA,UACtC,UAAU,MAAM;AAAA,QAClB,CAAC;AAAA,MACH,EACC,QAAQ;AAAA,IACb;AAAA,IAEA,oBAAoB,OAAO,WAAW;AACpC,UAAI,OAAO,WAAW,EAAG;AACzB,YAAM,SACH,WAAW,QAAQ,EACnB;AAAA,QACC,OAAO,IAAI,CAAC,WAAW;AAAA,UACrB,GAAG;AAAA,UACH,SAAS,MAAM,MAAM,OAAO;AAAA,UAC5B,kBAAkB,MAAM,MAAM,gBAAgB;AAAA,UAC9C,SAAS,MAAM,MAAM,OAAO;AAAA,UAC5B,cAAc,MAAM,MAAM,YAAY;AAAA,QACxC,EAAE;AAAA,MACJ,EACC,QAAQ;AAAA,IACb;AAAA,IAEA,uBAAuB,OAAO,WAAW;AACvC,UAAI,OAAO,WAAW,EAAG;AACzB,YAAM,MAAM,OAAO,IAAI,CAAC,MAAM,EAAE,EAAE;AAGlC,YAAM,aAAa,MAAM,SACtB,WAAW,QAAQ,EACnB,OAAO,IAAI,EACX,MAAM,MAAM,MAAM,GAAG,EACrB,UAAU,EACV,WAAW,EACX,QAAQ;AAEX,UAAI,WAAW,WAAW,EAAG;AAC7B,YAAM,YAAY,WAAW,IAAI,CAAC,MAAM,EAAE,EAAE;AAG5C,YAAM,SACH,YAAY,QAAQ,EACpB,IAAI,EAAE,QAAQ,aAAa,CAAC,EAC5B,MAAM,MAAM,MAAM,SAAS,EAC3B,QAAQ;AAAA,IACb;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,30 @@
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 jsonb_exports = {};
20
+ __export(jsonb_exports, {
21
+ jsonb: () => jsonb
22
+ });
23
+ module.exports = __toCommonJS(jsonb_exports);
24
+ var import_kysely = require("kysely");
25
+ const jsonb = (value) => import_kysely.sql`${JSON.stringify(value)}::jsonb`;
26
+ // Annotate the CommonJS export names for ESM import in node:
27
+ 0 && (module.exports = {
28
+ jsonb
29
+ });
30
+ //# sourceMappingURL=jsonb.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/adapters/kysely/jsonb.ts"],"sourcesContent":["import { type RawBuilder, sql } from \"kysely\";\n\nexport const jsonb = <T>(value: T): RawBuilder<T> =>\n sql`${JSON.stringify(value)}::jsonb`;\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAqC;AAE9B,MAAM,QAAQ,CAAI,UACvB,oBAAM,KAAK,UAAU,KAAK,CAAC;","names":[]}
@@ -0,0 +1,5 @@
1
+ import { RawBuilder } from 'kysely';
2
+
3
+ declare const jsonb: <T>(value: T) => RawBuilder<T>;
4
+
5
+ export { jsonb };
@@ -0,0 +1,5 @@
1
+ import { RawBuilder } from 'kysely';
2
+
3
+ declare const jsonb: <T>(value: T) => RawBuilder<T>;
4
+
5
+ export { jsonb };
@@ -0,0 +1,6 @@
1
+ import { sql } from "kysely";
2
+ const jsonb = (value) => sql`${JSON.stringify(value)}::jsonb`;
3
+ export {
4
+ jsonb
5
+ };
6
+ //# sourceMappingURL=jsonb.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/adapters/kysely/jsonb.ts"],"sourcesContent":["import { type RawBuilder, sql } from \"kysely\";\n\nexport const jsonb = <T>(value: T): RawBuilder<T> =>\n sql`${JSON.stringify(value)}::jsonb`;\n"],"mappings":"AAAA,SAA0B,WAAW;AAE9B,MAAM,QAAQ,CAAI,UACvB,MAAM,KAAK,UAAU,KAAK,CAAC;","names":[]}
@@ -0,0 +1,35 @@
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 mapEventRow_exports = {};
20
+ __export(mapEventRow_exports, {
21
+ mapEventRow: () => mapEventRow
22
+ });
23
+ module.exports = __toCommonJS(mapEventRow_exports);
24
+ const mapEventRow = (row) => ({
25
+ ...row,
26
+ context: row.context ?? void 0,
27
+ flowId: row.flowId ?? void 0,
28
+ causedByEventId: row.causedByEventId ?? void 0,
29
+ priority: row.priority ?? void 0
30
+ });
31
+ // Annotate the CommonJS export names for ESM import in node:
32
+ 0 && (module.exports = {
33
+ mapEventRow
34
+ });
35
+ //# sourceMappingURL=mapEventRow.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/adapters/kysely/mapEventRow.ts"],"sourcesContent":["import type { DefaultContext, GenericEvent } from \"../../types.ts\";\nimport type { EventsTable } from \"./types.ts\";\n\nexport const mapEventRow = <\n Event extends GenericEvent<string, unknown, DefaultContext>,\n>(\n row: EventsTable[\"events\"],\n): Event =>\n ({\n ...row,\n context: row.context ?? undefined,\n flowId: row.flowId ?? undefined,\n causedByEventId: row.causedByEventId ?? undefined,\n priority: row.priority ?? undefined,\n }) as Event;\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGO,MAAM,cAAc,CAGzB,SAEC;AAAA,EACC,GAAG;AAAA,EACH,SAAS,IAAI,WAAW;AAAA,EACxB,QAAQ,IAAI,UAAU;AAAA,EACtB,iBAAiB,IAAI,mBAAmB;AAAA,EACxC,UAAU,IAAI,YAAY;AAC5B;","names":[]}
@@ -0,0 +1,6 @@
1
+ import { GenericEvent, DefaultContext } from '../../types.cjs';
2
+ import { EventsTable } from './types.cjs';
3
+
4
+ declare const mapEventRow: <Event extends GenericEvent<string, unknown, DefaultContext>>(row: EventsTable["events"]) => Event;
5
+
6
+ export { mapEventRow };
@@ -0,0 +1,6 @@
1
+ import { GenericEvent, DefaultContext } from '../../types.js';
2
+ import { EventsTable } from './types.js';
3
+
4
+ declare const mapEventRow: <Event extends GenericEvent<string, unknown, DefaultContext>>(row: EventsTable["events"]) => Event;
5
+
6
+ export { mapEventRow };
@@ -0,0 +1,11 @@
1
+ const mapEventRow = (row) => ({
2
+ ...row,
3
+ context: row.context ?? void 0,
4
+ flowId: row.flowId ?? void 0,
5
+ causedByEventId: row.causedByEventId ?? void 0,
6
+ priority: row.priority ?? void 0
7
+ });
8
+ export {
9
+ mapEventRow
10
+ };
11
+ //# sourceMappingURL=mapEventRow.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/adapters/kysely/mapEventRow.ts"],"sourcesContent":["import type { DefaultContext, GenericEvent } from '../../types.mjs';\nimport type { EventsTable } from './types.mjs';\n\nexport const mapEventRow = <\n Event extends GenericEvent<string, unknown, DefaultContext>,\n>(\n row: EventsTable[\"events\"],\n): Event =>\n ({\n ...row,\n context: row.context ?? undefined,\n flowId: row.flowId ?? undefined,\n causedByEventId: row.causedByEventId ?? undefined,\n priority: row.priority ?? undefined,\n }) as Event;\n"],"mappings":"AAGO,MAAM,cAAc,CAGzB,SAEC;AAAA,EACC,GAAG;AAAA,EACH,SAAS,IAAI,WAAW;AAAA,EACxB,QAAQ,IAAI,UAAU;AAAA,EACtB,iBAAiB,IAAI,mBAAmB;AAAA,EACxC,UAAU,IAAI,YAAY;AAC5B;","names":[]}
@@ -21,13 +21,7 @@ __export(createEventCrawler_exports, {
21
21
  createEventCrawler: () => createEventCrawler
22
22
  });
23
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
- };
24
+ var import_splitIntoChunks = require("./splitIntoChunks.ts");
31
25
  const createEventCrawler = ({
32
26
  withUow,
33
27
  eventQueries,
@@ -39,7 +33,7 @@ const createEventCrawler = ({
39
33
  const newEventsIntervalMs = options.newEventsIntervalMs ?? 1e4;
40
34
  const failedEventsIntervalMs = options.failedEventsIntervalMs ?? 6e4;
41
35
  const publishEventsInParallel = async (events) => {
42
- const eventChunks = splitIntoChunks(events, maxParallelProcessing);
36
+ const eventChunks = (0, import_splitIntoChunks.splitIntoChunks)(events, maxParallelProcessing);
43
37
  for (const chunk of eventChunks) {
44
38
  await Promise.all(chunk.map((event) => eventBus.publish(event)));
45
39
  }
@@ -1 +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 (for traditional server environments)\n * - `processNewEvents()`: Manually trigger new event processing\n * - `retryFailedEvents()`: Manually trigger failed event retry\n * - `triggerProcessing()`: Process both new and failed events (for serverless environments)\n *\n * @example\n * ```typescript\n * const crawler = createEventCrawler({\n * withUow,\n * eventQueries,\n * eventBus,\n * options: { batchSize: 50, newEventsIntervalMs: 5000 },\n * });\n *\n * // Traditional server mode: Start background processing\n * crawler.start();\n *\n * // Serverless mode: Trigger on-demand after saving events\n * await withUow(async (uow) => {\n * await uow.eventRepository.save(event);\n * }, {\n * afterCommit: () => {\n * crawler.triggerProcessing().catch(console.error);\n * }\n * });\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 oneMinuteAgo = new Date(Date.now() - 60_000);\n\n const events = await eventQueries.getEvents({\n filters: {\n statuses: [\"to-republish\", \"failed-but-will-retry\"],\n occurredAt: { to: oneMinuteAgo },\n },\n limit: batchSize,\n });\n\n if (events.length === 0) return;\n\n await publishEventsInParallel(events);\n };\n\n const triggerProcessing = async (): Promise<void> => {\n // Use Promise.allSettled to ensure both processing steps run independently\n // If processNewEvents fails, retryFailedEvents will still execute\n const results = await Promise.allSettled([\n processNewEvents(),\n retryFailedEvents(),\n ]);\n\n // Re-throw if both failed\n const errors = results\n .filter((r) => r.status === \"rejected\")\n .map((r) => (r as PromiseRejectedResult).reason);\n\n if (errors.length > 0) {\n throw new AggregateError(errors, \"Event processing failed\");\n }\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 triggerProcessing,\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;AAwCO,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,eAAe,IAAI,KAAK,KAAK,IAAI,IAAI,GAAM;AAEjD,UAAM,SAAS,MAAM,aAAa,UAAU;AAAA,MAC1C,SAAS;AAAA,QACP,UAAU,CAAC,gBAAgB,uBAAuB;AAAA,QAClD,YAAY,EAAE,IAAI,aAAa;AAAA,MACjC;AAAA,MACA,OAAO;AAAA,IACT,CAAC;AAED,QAAI,OAAO,WAAW,EAAG;AAEzB,UAAM,wBAAwB,MAAM;AAAA,EACtC;AAEA,QAAM,oBAAoB,YAA2B;AAGnD,UAAM,UAAU,MAAM,QAAQ,WAAW;AAAA,MACvC,iBAAiB;AAAA,MACjB,kBAAkB;AAAA,IACpB,CAAC;AAGD,UAAM,SAAS,QACZ,OAAO,CAAC,MAAM,EAAE,WAAW,UAAU,EACrC,IAAI,CAAC,MAAO,EAA4B,MAAM;AAEjD,QAAI,OAAO,SAAS,GAAG;AACrB,YAAM,IAAI,eAAe,QAAQ,yBAAyB;AAAA,IAC5D;AAAA,EACF;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,IACA;AAAA,EACF;AACF;","names":[]}
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 { splitIntoChunks } from \"./splitIntoChunks.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\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 (for traditional server environments)\n * - `processNewEvents()`: Manually trigger new event processing\n * - `retryFailedEvents()`: Manually trigger failed event retry\n * - `triggerProcessing()`: Process both new and failed events (for serverless environments)\n *\n * @example\n * ```typescript\n * const crawler = createEventCrawler({\n * withUow,\n * eventQueries,\n * eventBus,\n * options: { batchSize: 50, newEventsIntervalMs: 5000 },\n * });\n *\n * // Traditional server mode: Start background processing\n * crawler.start();\n *\n * // Serverless mode: Trigger on-demand after saving events\n * await withUow(async (uow) => {\n * await uow.eventRepository.save(event);\n * }, {\n * afterCommit: () => {\n * crawler.triggerProcessing().catch(console.error);\n * }\n * });\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 oneMinuteAgo = new Date(Date.now() - 60_000);\n\n const events = await eventQueries.getEvents({\n filters: {\n statuses: [\"to-republish\", \"failed-but-will-retry\"],\n occurredAt: { to: oneMinuteAgo },\n },\n limit: batchSize,\n });\n\n if (events.length === 0) return;\n\n await publishEventsInParallel(events);\n };\n\n const triggerProcessing = async (): Promise<void> => {\n // Use Promise.allSettled to ensure both processing steps run independently\n // If processNewEvents fails, retryFailedEvents will still execute\n const results = await Promise.allSettled([\n processNewEvents(),\n retryFailedEvents(),\n ]);\n\n // Re-throw if both failed\n const errors = results\n .filter((r) => r.status === \"rejected\")\n .map((r) => (r as PromiseRejectedResult).reason);\n\n if (errors.length > 0) {\n throw new AggregateError(errors, \"Event processing failed\");\n }\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 triggerProcessing,\n start,\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,6BAAgC;AAqDzB,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,kBAAc,wCAAgB,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,eAAe,IAAI,KAAK,KAAK,IAAI,IAAI,GAAM;AAEjD,UAAM,SAAS,MAAM,aAAa,UAAU;AAAA,MAC1C,SAAS;AAAA,QACP,UAAU,CAAC,gBAAgB,uBAAuB;AAAA,QAClD,YAAY,EAAE,IAAI,aAAa;AAAA,MACjC;AAAA,MACA,OAAO;AAAA,IACT,CAAC;AAED,QAAI,OAAO,WAAW,EAAG;AAEzB,UAAM,wBAAwB,MAAM;AAAA,EACtC;AAEA,QAAM,oBAAoB,YAA2B;AAGnD,UAAM,UAAU,MAAM,QAAQ,WAAW;AAAA,MACvC,iBAAiB;AAAA,MACjB,kBAAkB;AAAA,IACpB,CAAC;AAGD,UAAM,SAAS,QACZ,OAAO,CAAC,MAAM,EAAE,WAAW,UAAU,EACrC,IAAI,CAAC,MAAO,EAA4B,MAAM;AAEjD,QAAI,OAAO,SAAS,GAAG;AACrB,YAAM,IAAI,eAAe,QAAQ,yBAAyB;AAAA,IAC5D;AAAA,EACF;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,IACA;AAAA,EACF;AACF;","names":[]}
@@ -1,10 +1,4 @@
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
- };
1
+ import { splitIntoChunks } from "./splitIntoChunks.mjs";
8
2
  const createEventCrawler = ({
9
3
  withUow,
10
4
  eventQueries,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/createEventCrawler.ts"],"sourcesContent":["import type { EventBus } from './ports/EventBus.mjs';\nimport type { EventQueries } from './ports/EventQueries.mjs';\nimport type { WithEventsUow } from './ports/EventRepository.mjs';\nimport type { DefaultContext, GenericEvent } from './types.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 (for traditional server environments)\n * - `processNewEvents()`: Manually trigger new event processing\n * - `retryFailedEvents()`: Manually trigger failed event retry\n * - `triggerProcessing()`: Process both new and failed events (for serverless environments)\n *\n * @example\n * ```typescript\n * const crawler = createEventCrawler({\n * withUow,\n * eventQueries,\n * eventBus,\n * options: { batchSize: 50, newEventsIntervalMs: 5000 },\n * });\n *\n * // Traditional server mode: Start background processing\n * crawler.start();\n *\n * // Serverless mode: Trigger on-demand after saving events\n * await withUow(async (uow) => {\n * await uow.eventRepository.save(event);\n * }, {\n * afterCommit: () => {\n * crawler.triggerProcessing().catch(console.error);\n * }\n * });\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 oneMinuteAgo = new Date(Date.now() - 60_000);\n\n const events = await eventQueries.getEvents({\n filters: {\n statuses: [\"to-republish\", \"failed-but-will-retry\"],\n occurredAt: { to: oneMinuteAgo },\n },\n limit: batchSize,\n });\n\n if (events.length === 0) return;\n\n await publishEventsInParallel(events);\n };\n\n const triggerProcessing = async (): Promise<void> => {\n // Use Promise.allSettled to ensure both processing steps run independently\n // If processNewEvents fails, retryFailedEvents will still execute\n const results = await Promise.allSettled([\n processNewEvents(),\n retryFailedEvents(),\n ]);\n\n // Re-throw if both failed\n const errors = results\n .filter((r) => r.status === \"rejected\")\n .map((r) => (r as PromiseRejectedResult).reason);\n\n if (errors.length > 0) {\n throw new AggregateError(errors, \"Event processing failed\");\n }\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 triggerProcessing,\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;AAwCO,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,eAAe,IAAI,KAAK,KAAK,IAAI,IAAI,GAAM;AAEjD,UAAM,SAAS,MAAM,aAAa,UAAU;AAAA,MAC1C,SAAS;AAAA,QACP,UAAU,CAAC,gBAAgB,uBAAuB;AAAA,QAClD,YAAY,EAAE,IAAI,aAAa;AAAA,MACjC;AAAA,MACA,OAAO;AAAA,IACT,CAAC;AAED,QAAI,OAAO,WAAW,EAAG;AAEzB,UAAM,wBAAwB,MAAM;AAAA,EACtC;AAEA,QAAM,oBAAoB,YAA2B;AAGnD,UAAM,UAAU,MAAM,QAAQ,WAAW;AAAA,MACvC,iBAAiB;AAAA,MACjB,kBAAkB;AAAA,IACpB,CAAC;AAGD,UAAM,SAAS,QACZ,OAAO,CAAC,MAAM,EAAE,WAAW,UAAU,EACrC,IAAI,CAAC,MAAO,EAA4B,MAAM;AAEjD,QAAI,OAAO,SAAS,GAAG;AACrB,YAAM,IAAI,eAAe,QAAQ,yBAAyB;AAAA,IAC5D;AAAA,EACF;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,IACA;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/createEventCrawler.ts"],"sourcesContent":["import type { EventBus } from './ports/EventBus.mjs';\nimport type { EventQueries } from './ports/EventQueries.mjs';\nimport type { WithEventsUow } from './ports/EventRepository.mjs';\nimport { splitIntoChunks } from './splitIntoChunks.mjs';\nimport type { DefaultContext, GenericEvent } from './types.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\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 (for traditional server environments)\n * - `processNewEvents()`: Manually trigger new event processing\n * - `retryFailedEvents()`: Manually trigger failed event retry\n * - `triggerProcessing()`: Process both new and failed events (for serverless environments)\n *\n * @example\n * ```typescript\n * const crawler = createEventCrawler({\n * withUow,\n * eventQueries,\n * eventBus,\n * options: { batchSize: 50, newEventsIntervalMs: 5000 },\n * });\n *\n * // Traditional server mode: Start background processing\n * crawler.start();\n *\n * // Serverless mode: Trigger on-demand after saving events\n * await withUow(async (uow) => {\n * await uow.eventRepository.save(event);\n * }, {\n * afterCommit: () => {\n * crawler.triggerProcessing().catch(console.error);\n * }\n * });\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 oneMinuteAgo = new Date(Date.now() - 60_000);\n\n const events = await eventQueries.getEvents({\n filters: {\n statuses: [\"to-republish\", \"failed-but-will-retry\"],\n occurredAt: { to: oneMinuteAgo },\n },\n limit: batchSize,\n });\n\n if (events.length === 0) return;\n\n await publishEventsInParallel(events);\n };\n\n const triggerProcessing = async (): Promise<void> => {\n // Use Promise.allSettled to ensure both processing steps run independently\n // If processNewEvents fails, retryFailedEvents will still execute\n const results = await Promise.allSettled([\n processNewEvents(),\n retryFailedEvents(),\n ]);\n\n // Re-throw if both failed\n const errors = results\n .filter((r) => r.status === \"rejected\")\n .map((r) => (r as PromiseRejectedResult).reason);\n\n if (errors.length > 0) {\n throw new AggregateError(errors, \"Event processing failed\");\n }\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 triggerProcessing,\n start,\n };\n};\n"],"mappings":"AAGA,SAAS,uBAAuB;AAqDzB,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,eAAe,IAAI,KAAK,KAAK,IAAI,IAAI,GAAM;AAEjD,UAAM,SAAS,MAAM,aAAa,UAAU;AAAA,MAC1C,SAAS;AAAA,QACP,UAAU,CAAC,gBAAgB,uBAAuB;AAAA,QAClD,YAAY,EAAE,IAAI,aAAa;AAAA,MACjC;AAAA,MACA,OAAO;AAAA,IACT,CAAC;AAED,QAAI,OAAO,WAAW,EAAG;AAEzB,UAAM,wBAAwB,MAAM;AAAA,EACtC;AAEA,QAAM,oBAAoB,YAA2B;AAGnD,UAAM,UAAU,MAAM,QAAQ,WAAW;AAAA,MACvC,iBAAiB;AAAA,MACjB,kBAAkB;AAAA,IACpB,CAAC;AAGD,UAAM,SAAS,QACZ,OAAO,CAAC,MAAM,EAAE,WAAW,UAAU,EACrC,IAAI,CAAC,MAAO,EAA4B,MAAM;AAEjD,QAAI,OAAO,SAAS,GAAG;AACrB,YAAM,IAAI,eAAe,QAAQ,yBAAyB;AAAA,IAC5D;AAAA,EACF;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,IACA;AAAA,EACF;AACF;","names":[]}