@pattern-stack/codegen 0.2.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 (279) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/README.md +214 -0
  3. package/dist/runtime/analytics/index.d.ts +6 -0
  4. package/dist/runtime/analytics/index.js +49 -0
  5. package/dist/runtime/analytics/index.js.map +1 -0
  6. package/dist/runtime/analytics/metrics.d.ts +75 -0
  7. package/dist/runtime/analytics/metrics.js +1 -0
  8. package/dist/runtime/analytics/metrics.js.map +1 -0
  9. package/dist/runtime/analytics/packs/crm-entity-measures.d.ts +21 -0
  10. package/dist/runtime/analytics/packs/crm-entity-measures.js +1 -0
  11. package/dist/runtime/analytics/packs/crm-entity-measures.js.map +1 -0
  12. package/dist/runtime/analytics/packs/index.d.ts +3 -0
  13. package/dist/runtime/analytics/packs/index.js +1 -0
  14. package/dist/runtime/analytics/packs/index.js.map +1 -0
  15. package/dist/runtime/analytics/packs/monetary-measures.d.ts +21 -0
  16. package/dist/runtime/analytics/packs/monetary-measures.js +1 -0
  17. package/dist/runtime/analytics/packs/monetary-measures.js.map +1 -0
  18. package/dist/runtime/analytics/specs.d.ts +49 -0
  19. package/dist/runtime/analytics/specs.js +1 -0
  20. package/dist/runtime/analytics/specs.js.map +1 -0
  21. package/dist/runtime/analytics/types.d.ts +85 -0
  22. package/dist/runtime/analytics/types.js +49 -0
  23. package/dist/runtime/analytics/types.js.map +1 -0
  24. package/dist/runtime/base-classes/activity-entity-repository.d.ts +26 -0
  25. package/dist/runtime/base-classes/activity-entity-repository.js +195 -0
  26. package/dist/runtime/base-classes/activity-entity-repository.js.map +1 -0
  27. package/dist/runtime/base-classes/activity-entity-service.d.ts +39 -0
  28. package/dist/runtime/base-classes/activity-entity-service.js +214 -0
  29. package/dist/runtime/base-classes/activity-entity-service.js.map +1 -0
  30. package/dist/runtime/base-classes/base-read-use-cases.d.ts +68 -0
  31. package/dist/runtime/base-classes/base-read-use-cases.js +32 -0
  32. package/dist/runtime/base-classes/base-read-use-cases.js.map +1 -0
  33. package/dist/runtime/base-classes/base-repository.d.ts +99 -0
  34. package/dist/runtime/base-classes/base-repository.js +160 -0
  35. package/dist/runtime/base-classes/base-repository.js.map +1 -0
  36. package/dist/runtime/base-classes/base-service.d.ts +98 -0
  37. package/dist/runtime/base-classes/base-service.js +186 -0
  38. package/dist/runtime/base-classes/base-service.js.map +1 -0
  39. package/dist/runtime/base-classes/index.d.ts +18 -0
  40. package/dist/runtime/base-classes/index.js +617 -0
  41. package/dist/runtime/base-classes/index.js.map +1 -0
  42. package/dist/runtime/base-classes/knowledge-entity-repository.d.ts +17 -0
  43. package/dist/runtime/base-classes/knowledge-entity-repository.js +166 -0
  44. package/dist/runtime/base-classes/knowledge-entity-repository.js.map +1 -0
  45. package/dist/runtime/base-classes/knowledge-entity-service.d.ts +15 -0
  46. package/dist/runtime/base-classes/knowledge-entity-service.js +192 -0
  47. package/dist/runtime/base-classes/knowledge-entity-service.js.map +1 -0
  48. package/dist/runtime/base-classes/lifecycle-events.d.ts +49 -0
  49. package/dist/runtime/base-classes/lifecycle-events.js +76 -0
  50. package/dist/runtime/base-classes/lifecycle-events.js.map +1 -0
  51. package/dist/runtime/base-classes/metadata-entity-repository.d.ts +27 -0
  52. package/dist/runtime/base-classes/metadata-entity-repository.js +212 -0
  53. package/dist/runtime/base-classes/metadata-entity-repository.js.map +1 -0
  54. package/dist/runtime/base-classes/metadata-entity-service.d.ts +39 -0
  55. package/dist/runtime/base-classes/metadata-entity-service.js +214 -0
  56. package/dist/runtime/base-classes/metadata-entity-service.js.map +1 -0
  57. package/dist/runtime/base-classes/synced-entity-repository.d.ts +32 -0
  58. package/dist/runtime/base-classes/synced-entity-repository.js +203 -0
  59. package/dist/runtime/base-classes/synced-entity-repository.js.map +1 -0
  60. package/dist/runtime/base-classes/synced-entity-service.d.ts +41 -0
  61. package/dist/runtime/base-classes/synced-entity-service.js +215 -0
  62. package/dist/runtime/base-classes/synced-entity-service.js.map +1 -0
  63. package/dist/runtime/base-classes/with-analytics.d.ts +18 -0
  64. package/dist/runtime/base-classes/with-analytics.js +11 -0
  65. package/dist/runtime/base-classes/with-analytics.js.map +1 -0
  66. package/dist/runtime/constants/tokens.d.ts +29 -0
  67. package/dist/runtime/constants/tokens.js +8 -0
  68. package/dist/runtime/constants/tokens.js.map +1 -0
  69. package/dist/runtime/subsystems/analytics/analytics-query.protocol.d.ts +30 -0
  70. package/dist/runtime/subsystems/analytics/analytics-query.protocol.js +1 -0
  71. package/dist/runtime/subsystems/analytics/analytics-query.protocol.js.map +1 -0
  72. package/dist/runtime/subsystems/analytics/analytics.module.d.ts +34 -0
  73. package/dist/runtime/subsystems/analytics/analytics.module.js +117 -0
  74. package/dist/runtime/subsystems/analytics/analytics.module.js.map +1 -0
  75. package/dist/runtime/subsystems/analytics/analytics.tokens.d.ts +24 -0
  76. package/dist/runtime/subsystems/analytics/analytics.tokens.js +10 -0
  77. package/dist/runtime/subsystems/analytics/analytics.tokens.js.map +1 -0
  78. package/dist/runtime/subsystems/analytics/cube-backend.d.ts +28 -0
  79. package/dist/runtime/subsystems/analytics/cube-backend.js +71 -0
  80. package/dist/runtime/subsystems/analytics/cube-backend.js.map +1 -0
  81. package/dist/runtime/subsystems/analytics/index.d.ts +6 -0
  82. package/dist/runtime/subsystems/analytics/index.js +122 -0
  83. package/dist/runtime/subsystems/analytics/index.js.map +1 -0
  84. package/dist/runtime/subsystems/analytics/noop-backend.d.ts +7 -0
  85. package/dist/runtime/subsystems/analytics/noop-backend.js +25 -0
  86. package/dist/runtime/subsystems/analytics/noop-backend.js.map +1 -0
  87. package/dist/runtime/subsystems/cache/cache.drizzle-backend.d.ts +43 -0
  88. package/dist/runtime/subsystems/cache/cache.drizzle-backend.js +133 -0
  89. package/dist/runtime/subsystems/cache/cache.drizzle-backend.js.map +1 -0
  90. package/dist/runtime/subsystems/cache/cache.memory-backend.d.ts +21 -0
  91. package/dist/runtime/subsystems/cache/cache.memory-backend.js +100 -0
  92. package/dist/runtime/subsystems/cache/cache.memory-backend.js.map +1 -0
  93. package/dist/runtime/subsystems/cache/cache.module.d.ts +37 -0
  94. package/dist/runtime/subsystems/cache/cache.module.js +272 -0
  95. package/dist/runtime/subsystems/cache/cache.module.js.map +1 -0
  96. package/dist/runtime/subsystems/cache/cache.protocol.d.ts +42 -0
  97. package/dist/runtime/subsystems/cache/cache.protocol.js +1 -0
  98. package/dist/runtime/subsystems/cache/cache.protocol.js.map +1 -0
  99. package/dist/runtime/subsystems/cache/cache.schema.d.ts +64 -0
  100. package/dist/runtime/subsystems/cache/cache.schema.js +18 -0
  101. package/dist/runtime/subsystems/cache/cache.schema.js.map +1 -0
  102. package/dist/runtime/subsystems/cache/cache.tokens.d.ts +18 -0
  103. package/dist/runtime/subsystems/cache/cache.tokens.js +8 -0
  104. package/dist/runtime/subsystems/cache/cache.tokens.js.map +1 -0
  105. package/dist/runtime/subsystems/cache/index.d.ts +11 -0
  106. package/dist/runtime/subsystems/cache/index.js +277 -0
  107. package/dist/runtime/subsystems/cache/index.js.map +1 -0
  108. package/dist/runtime/subsystems/events/domain-events.schema.d.ts +187 -0
  109. package/dist/runtime/subsystems/events/domain-events.schema.js +32 -0
  110. package/dist/runtime/subsystems/events/domain-events.schema.js.map +1 -0
  111. package/dist/runtime/subsystems/events/event-bus.drizzle-backend.d.ts +38 -0
  112. package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js +199 -0
  113. package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js.map +1 -0
  114. package/dist/runtime/subsystems/events/event-bus.memory-backend.d.ts +18 -0
  115. package/dist/runtime/subsystems/events/event-bus.memory-backend.js +71 -0
  116. package/dist/runtime/subsystems/events/event-bus.memory-backend.js.map +1 -0
  117. package/dist/runtime/subsystems/events/event-bus.protocol.d.ts +52 -0
  118. package/dist/runtime/subsystems/events/event-bus.protocol.js +1 -0
  119. package/dist/runtime/subsystems/events/event-bus.protocol.js.map +1 -0
  120. package/dist/runtime/subsystems/events/event-bus.redis-backend.d.ts +95 -0
  121. package/dist/runtime/subsystems/events/event-bus.redis-backend.js +229 -0
  122. package/dist/runtime/subsystems/events/event-bus.redis-backend.js.map +1 -0
  123. package/dist/runtime/subsystems/events/events.module.d.ts +46 -0
  124. package/dist/runtime/subsystems/events/events.module.js +531 -0
  125. package/dist/runtime/subsystems/events/events.module.js.map +1 -0
  126. package/dist/runtime/subsystems/events/events.tokens.d.ts +19 -0
  127. package/dist/runtime/subsystems/events/events.tokens.js +8 -0
  128. package/dist/runtime/subsystems/events/events.tokens.js.map +1 -0
  129. package/dist/runtime/subsystems/events/index.d.ts +12 -0
  130. package/dist/runtime/subsystems/events/index.js +536 -0
  131. package/dist/runtime/subsystems/events/index.js.map +1 -0
  132. package/dist/runtime/subsystems/index.d.ts +24 -0
  133. package/dist/runtime/subsystems/index.js +1643 -0
  134. package/dist/runtime/subsystems/index.js.map +1 -0
  135. package/dist/runtime/subsystems/jobs/index.d.ts +14 -0
  136. package/dist/runtime/subsystems/jobs/index.js +680 -0
  137. package/dist/runtime/subsystems/jobs/index.js.map +1 -0
  138. package/dist/runtime/subsystems/jobs/job-queue.bullmq-backend.d.ts +54 -0
  139. package/dist/runtime/subsystems/jobs/job-queue.bullmq-backend.js +186 -0
  140. package/dist/runtime/subsystems/jobs/job-queue.bullmq-backend.js.map +1 -0
  141. package/dist/runtime/subsystems/jobs/job-queue.drizzle-backend.d.ts +38 -0
  142. package/dist/runtime/subsystems/jobs/job-queue.drizzle-backend.js +228 -0
  143. package/dist/runtime/subsystems/jobs/job-queue.drizzle-backend.js.map +1 -0
  144. package/dist/runtime/subsystems/jobs/job-queue.memory-backend.d.ts +12 -0
  145. package/dist/runtime/subsystems/jobs/job-queue.memory-backend.js +44 -0
  146. package/dist/runtime/subsystems/jobs/job-queue.memory-backend.js.map +1 -0
  147. package/dist/runtime/subsystems/jobs/job-queue.protocol.d.ts +48 -0
  148. package/dist/runtime/subsystems/jobs/job-queue.protocol.js +1 -0
  149. package/dist/runtime/subsystems/jobs/job-queue.protocol.js.map +1 -0
  150. package/dist/runtime/subsystems/jobs/job-queue.redis-backend.d.ts +46 -0
  151. package/dist/runtime/subsystems/jobs/job-queue.redis-backend.js +187 -0
  152. package/dist/runtime/subsystems/jobs/job-queue.redis-backend.js.map +1 -0
  153. package/dist/runtime/subsystems/jobs/job-queue.schema.d.ts +237 -0
  154. package/dist/runtime/subsystems/jobs/job-queue.schema.js +44 -0
  155. package/dist/runtime/subsystems/jobs/job-queue.schema.js.map +1 -0
  156. package/dist/runtime/subsystems/jobs/jobs.module.d.ts +18 -0
  157. package/dist/runtime/subsystems/jobs/jobs.module.js +676 -0
  158. package/dist/runtime/subsystems/jobs/jobs.module.js.map +1 -0
  159. package/dist/runtime/subsystems/jobs/jobs.tokens.d.ts +13 -0
  160. package/dist/runtime/subsystems/jobs/jobs.tokens.js +8 -0
  161. package/dist/runtime/subsystems/jobs/jobs.tokens.js.map +1 -0
  162. package/dist/runtime/subsystems/storage/index.d.ts +6 -0
  163. package/dist/runtime/subsystems/storage/index.js +204 -0
  164. package/dist/runtime/subsystems/storage/index.js.map +1 -0
  165. package/dist/runtime/subsystems/storage/storage.local-backend.d.ts +18 -0
  166. package/dist/runtime/subsystems/storage/storage.local-backend.js +108 -0
  167. package/dist/runtime/subsystems/storage/storage.local-backend.js.map +1 -0
  168. package/dist/runtime/subsystems/storage/storage.memory-backend.d.ts +28 -0
  169. package/dist/runtime/subsystems/storage/storage.memory-backend.js +72 -0
  170. package/dist/runtime/subsystems/storage/storage.memory-backend.js.map +1 -0
  171. package/dist/runtime/subsystems/storage/storage.module.d.ts +40 -0
  172. package/dist/runtime/subsystems/storage/storage.module.js +201 -0
  173. package/dist/runtime/subsystems/storage/storage.module.js.map +1 -0
  174. package/dist/runtime/subsystems/storage/storage.protocol.d.ts +69 -0
  175. package/dist/runtime/subsystems/storage/storage.protocol.js +1 -0
  176. package/dist/runtime/subsystems/storage/storage.protocol.js.map +1 -0
  177. package/dist/runtime/subsystems/storage/storage.tokens.d.ts +11 -0
  178. package/dist/runtime/subsystems/storage/storage.tokens.js +6 -0
  179. package/dist/runtime/subsystems/storage/storage.tokens.js.map +1 -0
  180. package/dist/runtime/subsystems/storage/storage.utils.d.ts +9 -0
  181. package/dist/runtime/subsystems/storage/storage.utils.js +18 -0
  182. package/dist/runtime/subsystems/storage/storage.utils.js.map +1 -0
  183. package/dist/runtime/types/drizzle.d.ts +17 -0
  184. package/dist/runtime/types/drizzle.js +1 -0
  185. package/dist/runtime/types/drizzle.js.map +1 -0
  186. package/dist/src/cli/index.d.ts +1 -0
  187. package/dist/src/cli/index.js +7365 -0
  188. package/dist/src/cli/index.js.map +1 -0
  189. package/dist/src/index.d.ts +2384 -0
  190. package/dist/src/index.js +2198 -0
  191. package/dist/src/index.js.map +1 -0
  192. package/package.json +114 -0
  193. package/templates/broadcast/new/backend-interface.ejs.t +47 -0
  194. package/templates/broadcast/new/bridge-listener.ejs.t +67 -0
  195. package/templates/broadcast/new/channel.ejs.t +77 -0
  196. package/templates/broadcast/new/index.ejs.t +21 -0
  197. package/templates/broadcast/new/memory-backend.ejs.t +87 -0
  198. package/templates/broadcast/new/module.ejs.t +57 -0
  199. package/templates/broadcast/new/prompt.js +268 -0
  200. package/templates/broadcast/new/websocket-backend.ejs.t +259 -0
  201. package/templates/entity/new/backend/application/commands/create.ejs.t +55 -0
  202. package/templates/entity/new/backend/application/commands/delete.ejs.t +45 -0
  203. package/templates/entity/new/backend/application/commands/grouped-index.ejs.t +149 -0
  204. package/templates/entity/new/backend/application/commands/index.ejs.t +15 -0
  205. package/templates/entity/new/backend/application/commands/update.ejs.t +58 -0
  206. package/templates/entity/new/backend/application/queries/declarative-queries.ejs.t +36 -0
  207. package/templates/entity/new/backend/application/queries/get-by-id.ejs.t +42 -0
  208. package/templates/entity/new/backend/application/queries/grouped-index.ejs.t +81 -0
  209. package/templates/entity/new/backend/application/queries/index.ejs.t +14 -0
  210. package/templates/entity/new/backend/application/queries/list.ejs.t +36 -0
  211. package/templates/entity/new/backend/application/schemas/_inject-index.ejs.t +7 -0
  212. package/templates/entity/new/backend/application/schemas/dto.ejs.t +45 -0
  213. package/templates/entity/new/backend/database/_inject-index.ejs.t +7 -0
  214. package/templates/entity/new/backend/database/electric-migration.ejs.t +21 -0
  215. package/templates/entity/new/backend/database/repository.ejs.t +450 -0
  216. package/templates/entity/new/backend/database/schema.ejs.t +248 -0
  217. package/templates/entity/new/backend/domain/_inject-index.ejs.t +12 -0
  218. package/templates/entity/new/backend/domain/entity.ejs.t +108 -0
  219. package/templates/entity/new/backend/domain/grouped-index.ejs.t +163 -0
  220. package/templates/entity/new/backend/domain/index.ejs.t +15 -0
  221. package/templates/entity/new/backend/domain/repository-interface.ejs.t +71 -0
  222. package/templates/entity/new/backend/modules/core/_ensure-anchor-tokens.ejs.t +10 -0
  223. package/templates/entity/new/backend/modules/core/_inject-token.ejs.t +7 -0
  224. package/templates/entity/new/backend/modules/core/module.ejs.t +67 -0
  225. package/templates/entity/new/backend/modules/trpc/module.ejs.t +67 -0
  226. package/templates/entity/new/backend/presentation/controller.ejs.t +201 -0
  227. package/templates/entity/new/clean-lite-ps/controller.ejs.t +37 -0
  228. package/templates/entity/new/clean-lite-ps/dto/create.ejs.t +17 -0
  229. package/templates/entity/new/clean-lite-ps/dto/output.ejs.t +25 -0
  230. package/templates/entity/new/clean-lite-ps/dto/update.ejs.t +11 -0
  231. package/templates/entity/new/clean-lite-ps/entity.ejs.t +52 -0
  232. package/templates/entity/new/clean-lite-ps/index.ejs.t +20 -0
  233. package/templates/entity/new/clean-lite-ps/module.ejs.t +43 -0
  234. package/templates/entity/new/clean-lite-ps/prompt-extension.js +617 -0
  235. package/templates/entity/new/clean-lite-ps/repository.ejs.t +62 -0
  236. package/templates/entity/new/clean-lite-ps/service.ejs.t +34 -0
  237. package/templates/entity/new/clean-lite-ps/use-cases/declarative-queries.ejs.t +34 -0
  238. package/templates/entity/new/clean-lite-ps/use-cases/find-by-id.ejs.t +16 -0
  239. package/templates/entity/new/clean-lite-ps/use-cases/list.ejs.t +16 -0
  240. package/templates/entity/new/frontend/_inject-entities-entry.ejs.t +7 -0
  241. package/templates/entity/new/frontend/_inject-entities-import.ejs.t +7 -0
  242. package/templates/entity/new/frontend/collections/_ensure-anchor-collections.ejs.t +10 -0
  243. package/templates/entity/new/frontend/collections/_inject-index.ejs.t +9 -0
  244. package/templates/entity/new/frontend/collections/_inject-schema-import.ejs.t +9 -0
  245. package/templates/entity/new/frontend/collections/collection.ejs.t +61 -0
  246. package/templates/entity/new/frontend/collections/collections-base.ejs.t +24 -0
  247. package/templates/entity/new/frontend/entity/collection.ejs.t +172 -0
  248. package/templates/entity/new/frontend/entity/combined.ejs.t +474 -0
  249. package/templates/entity/new/frontend/entity/fields.ejs.t +104 -0
  250. package/templates/entity/new/frontend/entity/hooks.ejs.t +73 -0
  251. package/templates/entity/new/frontend/entity/index.ejs.t +21 -0
  252. package/templates/entity/new/frontend/entity/mutation-hooks.ejs.t +84 -0
  253. package/templates/entity/new/frontend/entity/mutations.ejs.t +38 -0
  254. package/templates/entity/new/frontend/entity/types.ejs.t +59 -0
  255. package/templates/entity/new/frontend/generated/_inject-index-export.ejs.t +7 -0
  256. package/templates/entity/new/frontend/generated/_inject-index-import.ejs.t +7 -0
  257. package/templates/entity/new/frontend/generated/_inject-index-registry.ejs.t +7 -0
  258. package/templates/entity/new/frontend/store/_inject-collection-import.ejs.t +9 -0
  259. package/templates/entity/new/frontend/store/_inject-collections.ejs.t +9 -0
  260. package/templates/entity/new/frontend/store/_inject-entity.ejs.t +9 -0
  261. package/templates/entity/new/frontend/store/_inject-import.ejs.t +9 -0
  262. package/templates/entity/new/frontend/store/_inject-lookups.ejs.t +9 -0
  263. package/templates/entity/new/frontend/store/_inject-resolve.ejs.t +10 -0
  264. package/templates/entity/new/frontend/store/hooks.ejs.t +72 -0
  265. package/templates/entity/new/frontend/unified-entity.ejs.t +28 -0
  266. package/templates/entity/new/prompt.js +1421 -0
  267. package/templates/relationship/new/controller.ejs.t +36 -0
  268. package/templates/relationship/new/dto/create.ejs.t +41 -0
  269. package/templates/relationship/new/dto/output.ejs.t +44 -0
  270. package/templates/relationship/new/dto/update.ejs.t +10 -0
  271. package/templates/relationship/new/entity.ejs.t +98 -0
  272. package/templates/relationship/new/index.ejs.t +19 -0
  273. package/templates/relationship/new/module.ejs.t +35 -0
  274. package/templates/relationship/new/prompt.js +682 -0
  275. package/templates/relationship/new/repository.ejs.t +54 -0
  276. package/templates/relationship/new/service.ejs.t +31 -0
  277. package/templates/relationship/new/use-cases/declarative-queries.ejs.t +34 -0
  278. package/templates/relationship/new/use-cases/find-by-id.ejs.t +16 -0
  279. package/templates/relationship/new/use-cases/list.ejs.t +16 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../runtime/subsystems/events/events.tokens.ts","../../../runtime/subsystems/events/events.module.ts","../../../runtime/subsystems/events/event-bus.drizzle-backend.ts","../../../runtime/subsystems/events/domain-events.schema.ts","../../../runtime/constants/tokens.ts","../../../runtime/subsystems/events/event-bus.memory-backend.ts","../../../runtime/subsystems/events/event-bus.redis-backend.ts","../../../runtime/subsystems/jobs/jobs.tokens.ts","../../../runtime/subsystems/jobs/jobs.module.ts","../../../runtime/subsystems/jobs/job-queue.drizzle-backend.ts","../../../runtime/subsystems/jobs/job-queue.schema.ts","../../../runtime/subsystems/jobs/job-queue.memory-backend.ts","../../../runtime/subsystems/jobs/job-queue.redis-backend.ts","../../../runtime/subsystems/jobs/job-queue.bullmq-backend.ts","../../../runtime/subsystems/cache/cache.tokens.ts","../../../runtime/subsystems/cache/cache.module.ts","../../../runtime/subsystems/cache/cache.drizzle-backend.ts","../../../runtime/subsystems/cache/cache.schema.ts","../../../runtime/subsystems/cache/cache.memory-backend.ts","../../../runtime/subsystems/storage/storage.local-backend.ts","../../../runtime/subsystems/storage/storage.utils.ts","../../../runtime/subsystems/storage/storage.memory-backend.ts","../../../runtime/subsystems/storage/storage.module.ts","../../../runtime/subsystems/storage/storage.tokens.ts"],"sourcesContent":["/**\n * Injection token for the event bus.\n *\n * String constant (not Symbol) so it matches by value across import boundaries.\n * Matches the token in runtime/constants/tokens.ts — both are 'EVENT_BUS'.\n *\n * Usage in use cases:\n * ```typescript\n * constructor(@Inject(EVENT_BUS) private readonly eventBus: IEventBus) {}\n * ```\n */\nexport const EVENT_BUS = 'EVENT_BUS' as const;\n\n/**\n * Injection token for the Redis connection URL used by RedisEventBus.\n * Provided automatically by EventsModule.forRoot({ backend: 'redis' }).\n */\nexport const REDIS_URL = Symbol('REDIS_URL');\n","/**\n * EventsModule — DynamicModule factory for the event bus subsystem.\n *\n * Register once in AppModule:\n * ```typescript\n * @Module({\n * imports: [\n * EventsModule.forRoot({ backend: 'drizzle' }),\n * ],\n * })\n * export class AppModule {}\n * ```\n *\n * Tests swap to the memory backend without touching application code:\n * ```typescript\n * Test.createTestingModule({\n * imports: [EventsModule.forRoot({ backend: 'memory' })],\n * });\n * ```\n *\n * `global: true` means entity modules do not need to import EventsModule\n * individually — the EVENT_BUS token is available project-wide.\n */\nimport { Module, type DynamicModule } from '@nestjs/common';\nimport { EVENT_BUS, REDIS_URL } from './events.tokens';\nimport { DrizzleEventBus } from './event-bus.drizzle-backend';\nimport { MemoryEventBus } from './event-bus.memory-backend';\nimport { RedisEventBus } from './event-bus.redis-backend';\n\nexport interface EventsModuleOptions {\n backend: 'drizzle' | 'memory' | 'redis';\n /**\n * Redis connection URL used when `backend` is `'redis'`.\n * Falls back to the REDIS_URL environment variable, then\n * `redis://localhost:6379` if neither is set.\n */\n redisUrl?: string;\n}\n\nexport interface EventsModuleAsyncOptions {\n useFactory: (...args: unknown[]) => Promise<EventsModuleOptions> | EventsModuleOptions;\n inject?: unknown[];\n imports?: unknown[];\n}\n\n@Module({})\nexport class EventsModule {\n static forRootAsync(asyncOptions: EventsModuleAsyncOptions): DynamicModule {\n return {\n module: EventsModule,\n global: true,\n imports: (asyncOptions.imports ?? []) as Parameters<typeof Module>[0]['imports'],\n providers: [\n {\n provide: 'EVENTS_MODULE_OPTIONS',\n useFactory: asyncOptions.useFactory,\n inject: (asyncOptions.inject ?? []) as (string | symbol | Function)[],\n },\n {\n provide: EVENT_BUS,\n useFactory: (options: EventsModuleOptions) => {\n const mod = EventsModule.forRoot(options);\n // Return the provider instance by delegating to forRoot's logic\n const provider = mod.providers?.find(\n (p) => typeof p === 'object' && p !== null && 'provide' in p && p.provide === EVENT_BUS,\n );\n if (provider && typeof provider === 'object' && 'useClass' in provider) {\n return new (provider.useClass as new () => unknown)();\n }\n throw new Error('EventsModule.forRootAsync: failed to resolve provider');\n },\n inject: ['EVENTS_MODULE_OPTIONS'],\n },\n ],\n exports: [EVENT_BUS],\n };\n }\n\n static forRoot(\n options: EventsModuleOptions = { backend: 'drizzle' },\n ): DynamicModule {\n if (options.backend === 'redis') {\n const resolvedUrl =\n options.redisUrl ?? process.env['REDIS_URL'] ?? 'redis://localhost:6379';\n\n return {\n module: EventsModule,\n global: true,\n providers: [\n { provide: REDIS_URL, useValue: resolvedUrl },\n { provide: EVENT_BUS, useClass: RedisEventBus },\n // Register concrete class so NestJS can resolve lifecycle hooks\n RedisEventBus,\n ],\n exports: [EVENT_BUS],\n };\n }\n\n const provider =\n options.backend === 'drizzle'\n ? { provide: EVENT_BUS, useClass: DrizzleEventBus }\n : { provide: EVENT_BUS, useClass: MemoryEventBus };\n\n return {\n module: EventsModule,\n global: true,\n providers: [provider],\n exports: [EVENT_BUS],\n };\n }\n}\n","/**\n * DrizzleEventBus — Postgres-backed event bus using the transactional outbox pattern.\n *\n * Events are inserted into the `domain_events` table within the caller's\n * Drizzle transaction. A background polling loop (started on module init)\n * reads unprocessed events and dispatches them to registered subscribers.\n *\n * When the transaction rolls back, the event is never persisted — no\n * phantom events.\n *\n * This backend is suitable until you need real-time fan-out or very high\n * throughput. At that point, swap the backend for Redis Streams or similar\n * via EventsModule.forRoot({ backend: '...' }) without touching use cases.\n */\nimport { Injectable, OnModuleDestroy, OnModuleInit, Inject, Logger } from '@nestjs/common';\nimport { eq, and, sql } from 'drizzle-orm';\nimport type { DomainEvent, DrizzleTransaction, IEventBus } from './event-bus.protocol';\nimport type { DrizzleClient } from '../../types/drizzle';\nimport { domainEvents } from './domain-events.schema';\nimport { DRIZZLE } from '../../constants/tokens';\n\n/** How long to wait between polling cycles (ms). */\nconst POLL_INTERVAL_MS = 1_000;\n/** Max events claimed per polling cycle to bound memory usage. */\nconst POLL_BATCH_SIZE = 50;\n/** Max processing attempts before marking an event failed. */\nconst MAX_RETRIES = 3;\n\n@Injectable()\nexport class DrizzleEventBus implements IEventBus, OnModuleInit, OnModuleDestroy {\n private readonly logger = new Logger(DrizzleEventBus.name);\n private polling = false;\n private pollTimer: ReturnType<typeof setTimeout> | null = null;\n private readonly handlers = new Map<string, Set<(event: DomainEvent) => Promise<void>>>();\n\n constructor(@Inject(DRIZZLE) private readonly db: DrizzleClient) {}\n\n // ============================================================================\n // Lifecycle\n // ============================================================================\n\n async onModuleInit(): Promise<void> {\n this.polling = true;\n this.schedulePoll();\n }\n\n async onModuleDestroy(): Promise<void> {\n this.polling = false;\n if (this.pollTimer) {\n clearTimeout(this.pollTimer);\n this.pollTimer = null;\n }\n }\n\n // ============================================================================\n // IEventBus\n // ============================================================================\n\n async publish(event: DomainEvent, tx?: DrizzleTransaction): Promise<void> {\n const client = (tx ?? this.db) as DrizzleClient;\n await client.insert(domainEvents).values({\n id: event.id,\n type: event.type,\n aggregateId: event.aggregateId,\n aggregateType: event.aggregateType,\n payload: event.payload,\n occurredAt: event.occurredAt,\n processedAt: null,\n status: 'pending',\n metadata: event.metadata,\n });\n }\n\n async publishMany(events: DomainEvent[], tx?: DrizzleTransaction): Promise<void> {\n if (events.length === 0) return;\n const client = (tx ?? this.db) as DrizzleClient;\n await client.insert(domainEvents).values(\n events.map((e) => ({\n id: e.id,\n type: e.type,\n aggregateId: e.aggregateId,\n aggregateType: e.aggregateType,\n payload: e.payload,\n occurredAt: e.occurredAt,\n processedAt: null,\n status: 'pending' as const,\n metadata: e.metadata,\n })),\n );\n }\n\n subscribe<T extends DomainEvent = DomainEvent>(\n eventType: string,\n handler: (event: T) => Promise<void>,\n ): () => void {\n if (!this.handlers.has(eventType)) {\n this.handlers.set(eventType, new Set());\n }\n const set = this.handlers.get(eventType)!;\n const h = handler as (event: DomainEvent) => Promise<void>;\n set.add(h);\n return () => {\n set.delete(h);\n };\n }\n\n // ============================================================================\n // Polling\n // ============================================================================\n\n private schedulePoll(): void {\n if (!this.polling) return;\n this.pollTimer = setTimeout(async () => {\n try {\n await this.processBatch();\n } catch (err) {\n this.logger.error(`Poll cycle error: ${err}`);\n } finally {\n this.schedulePoll();\n }\n }, POLL_INTERVAL_MS);\n }\n\n private async processBatch(): Promise<void> {\n // Fetch a batch of pending events with FOR UPDATE SKIP LOCKED to prevent\n // double-processing when multiple instances are polling concurrently.\n const rows = await this.db.transaction(async (tx) => {\n return tx.execute(\n sql`SELECT * FROM domain_events WHERE status = 'pending' ORDER BY occurred_at ASC LIMIT ${POLL_BATCH_SIZE} FOR UPDATE SKIP LOCKED`,\n ) as Promise<{ rows: Record<string, unknown>[] }>;\n }).then((result) => (result as unknown as { rows: Record<string, unknown>[] }).rows ?? result as unknown as Record<string, unknown>[]);\n\n for (const row of rows) {\n const event: DomainEvent = {\n id: row['id'] as string,\n type: row['type'] as string,\n aggregateId: row['aggregate_id'] as string,\n aggregateType: row['aggregate_type'] as string,\n payload: row['payload'] as Record<string, unknown>,\n occurredAt: new Date(row['occurred_at'] as string),\n metadata: row['metadata'] as Record<string, unknown> | undefined,\n };\n\n let attempt = 0;\n let lastError: unknown;\n while (attempt < MAX_RETRIES) {\n try {\n await this.dispatch(event);\n // Mark processed\n await this.db\n .update(domainEvents)\n .set({ status: 'processed', processedAt: new Date() })\n .where(eq(domainEvents.id, event.id));\n lastError = undefined;\n break;\n } catch (err) {\n lastError = err;\n attempt++;\n }\n }\n\n if (lastError !== undefined) {\n const errorMessage = lastError instanceof Error ? lastError.message : String(lastError);\n await this.db\n .update(domainEvents)\n .set({ status: 'failed', error: errorMessage })\n .where(and(eq(domainEvents.id, event.id), eq(domainEvents.status, 'pending')));\n }\n }\n }\n\n private async dispatch(event: DomainEvent): Promise<void> {\n const set = this.handlers.get(event.type);\n if (!set) return;\n\n let firstError: unknown;\n for (const handler of set) {\n try {\n await handler(event);\n } catch (err) {\n this.logger.error(\n `Handler error for event type \"${event.type}\" (id: ${event.id}): ${err}`,\n );\n if (firstError === undefined) {\n firstError = err;\n }\n }\n }\n\n if (firstError !== undefined) {\n throw firstError;\n }\n }\n}\n","/**\n * Drizzle schema for the domain_events outbox table.\n *\n * This table backs the DrizzleEventBus. Events are inserted within the\n * same database transaction as the domain write (outbox pattern). A\n * polling process reads unprocessed rows and dispatches to subscribers.\n *\n * Indexes:\n * - (status, occurredAt) — polling query filter\n * - (aggregateId, aggregateType) — event replay per aggregate\n */\nimport {\n jsonb,\n pgTable,\n text,\n timestamp,\n uuid,\n} from 'drizzle-orm/pg-core';\nimport type { InferSelectModel } from 'drizzle-orm';\n\nexport const domainEvents = pgTable(\n 'domain_events',\n {\n id: uuid('id').primaryKey(),\n type: text('type').notNull(),\n aggregateId: text('aggregate_id').notNull(),\n aggregateType: text('aggregate_type').notNull(),\n payload: jsonb('payload').notNull().$type<Record<string, unknown>>(),\n occurredAt: timestamp('occurred_at', { withTimezone: true }).notNull(),\n processedAt: timestamp('processed_at', { withTimezone: true }),\n /** Lifecycle status: pending | processed | failed */\n status: text('status').notNull().default('pending'),\n /** Error message from the last failed dispatch attempt. */\n error: text('error'),\n metadata: jsonb('metadata').$type<Record<string, unknown>>(),\n },\n // Indexes: add via migration when deploying\n // - (status, occurred_at) for polling\n // - (aggregate_id, aggregate_type) for replay\n);\n\nexport type DomainEventRecord = InferSelectModel<typeof domainEvents>;\n","/**\n * NestJS injection tokens\n *\n * Used with @Inject() decorator in concrete repository constructors.\n */\n\n/**\n * Injection token for the Drizzle ORM database client.\n *\n * Usage in concrete repositories:\n * ```typescript\n * constructor(@Inject(DRIZZLE) db: DrizzleClient) { super(db); }\n * ```\n */\nexport const DRIZZLE = 'DRIZZLE' as const;\n\n/**\n * Injection token for the event bus (IEventBus).\n *\n * Optional — only resolved when EventsModule.forRoot() is registered.\n * BaseService uses this with @Optional() to emit lifecycle events\n * without requiring the events subsystem to be installed.\n *\n * Usage in services/use cases:\n * ```typescript\n * @Optional() @Inject(EVENT_BUS) eventBus?: IEventBus\n * ```\n */\nexport const EVENT_BUS = 'EVENT_BUS' as const;\n","/**\n * MemoryEventBus — in-memory backend for the event bus.\n *\n * Dispatches events synchronously to registered subscribers. The `tx`\n * parameter is ignored — all events are dispatched immediately.\n *\n * Use this backend in tests to assert event publication without a database.\n * Swap via EventsModule.forRoot({ backend: 'memory' }).\n */\nimport { Injectable, Logger } from '@nestjs/common';\nimport type { DomainEvent, IEventBus } from './event-bus.protocol';\n\n@Injectable()\nexport class MemoryEventBus implements IEventBus {\n private readonly logger = new Logger(MemoryEventBus.name);\n\n /** All events published since construction (or last clear). */\n readonly publishedEvents: DomainEvent[] = [];\n\n private readonly handlers = new Map<string, Set<(event: DomainEvent) => Promise<void>>>();\n\n async publish(event: DomainEvent): Promise<void> {\n this.publishedEvents.push(event);\n await this.dispatch(event);\n }\n\n async publishMany(events: DomainEvent[]): Promise<void> {\n for (const event of events) {\n await this.publish(event);\n }\n }\n\n subscribe<T extends DomainEvent = DomainEvent>(\n eventType: string,\n handler: (event: T) => Promise<void>,\n ): () => void {\n if (!this.handlers.has(eventType)) {\n this.handlers.set(eventType, new Set());\n }\n // Cast is safe — callers pass a typed handler; we store as the base type\n const set = this.handlers.get(eventType)!;\n const h = handler as (event: DomainEvent) => Promise<void>;\n set.add(h);\n\n return () => {\n set.delete(h);\n };\n }\n\n /** Remove all published events and subscriptions. Useful in beforeEach. */\n clear(): void {\n this.publishedEvents.length = 0;\n this.handlers.clear();\n }\n\n private async dispatch(event: DomainEvent): Promise<void> {\n const set = this.handlers.get(event.type);\n if (!set) return;\n\n let firstError: unknown;\n for (const handler of set) {\n try {\n await handler(event);\n } catch (err) {\n this.logger.error(\n `Handler error for event type \"${event.type}\" (id: ${event.id}): ${err}`,\n );\n if (firstError === undefined) {\n firstError = err;\n }\n }\n }\n\n if (firstError !== undefined) {\n throw firstError;\n }\n }\n}\n","/**\n * RedisEventBus — Redis Pub/Sub backend for the event bus.\n *\n * Publishes events to Redis channels and dispatches incoming messages to\n * registered in-process subscribers. Events are serialized as JSON strings.\n *\n * Channel naming:\n * - Per-type channel: events:{event.type} (e.g. events:contact_created)\n * - Catch-all channel: events:*\n *\n * Transactional semantics:\n * The `tx` parameter (Drizzle transaction) is accepted to satisfy the\n * IEventBus interface but has no effect — Redis Pub/Sub is not transactional.\n * Events published with a `tx` argument are dispatched immediately without\n * waiting for the surrounding transaction to commit. If you need\n * at-least-once delivery tied to a database transaction, use DrizzleEventBus.\n *\n * Connection model:\n * ioredis requires a dedicated connection for subscribers (a client in\n * subscribe mode cannot issue regular commands). This backend creates two\n * clients: one for publishing (`publisher`) and one for subscribing\n * (`subscriber`). Both are connected on module init and disconnected on\n * module destroy.\n *\n * Usage:\n * EventsModule.forRoot({ backend: 'redis', redisUrl: 'redis://localhost:6379' })\n *\n * Requires `ioredis` — install it separately if you use this backend:\n * npm install ioredis / bun add ioredis\n */\nimport { Injectable, OnModuleInit, OnModuleDestroy, Inject, Logger } from '@nestjs/common';\nimport type { DomainEvent, DrizzleTransaction, IEventBus } from './event-bus.protocol';\nimport { REDIS_URL } from './events.tokens';\n\n/** Redis channel prefix for all domain events. */\nconst CHANNEL_PREFIX = 'events:';\n/** Catch-all channel that receives every published event. */\nconst WILDCARD_CHANNEL = 'events:*';\n\n// ioredis is an optional peer dependency; import lazily so consumers who do\n// not use this backend do not need it on their classpath.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype RedisClient = any;\n\nasync function createRedisClient(url: string): Promise<RedisClient> {\n let Redis: { new (url: string): RedisClient };\n try {\n const mod = await import('ioredis');\n Redis = mod.default ?? mod;\n } catch {\n throw new Error(\n 'RedisEventBus requires the \"ioredis\" package. Install it with: npm install ioredis',\n );\n }\n return new Redis(url);\n}\n\n@Injectable()\nexport class RedisEventBus implements IEventBus, OnModuleInit, OnModuleDestroy {\n private readonly logger = new Logger(RedisEventBus.name);\n\n private publisher: RedisClient | null = null;\n private subscriber: RedisClient | null = null;\n private connected = false;\n\n /**\n * In-process subscriber registry. Handlers registered here are called when\n * a message arrives on the subscriber client — keeping fan-out within the\n * same process without an extra round-trip through Redis.\n */\n private readonly handlers = new Map<string, Set<(event: DomainEvent) => Promise<void>>>();\n\n /**\n * Track which event types have active Redis subscriptions.\n * Used to avoid subscribing multiple times to the same type channel.\n */\n private readonly subscribedTypes = new Set<string>();\n\n constructor(@Inject(REDIS_URL) private readonly redisUrl: string) {}\n\n // ============================================================================\n // Lifecycle\n // ============================================================================\n\n async onModuleInit(): Promise<void> {\n this.publisher = await createRedisClient(this.redisUrl);\n this.subscriber = await createRedisClient(this.redisUrl);\n\n // Surface connection errors without crashing the process.\n this.publisher.on('error', (err: Error) =>\n this.logger.error(`Redis publisher error: ${err.message}`, err.stack),\n );\n this.subscriber.on('error', (err: Error) =>\n this.logger.error(`Redis subscriber error: ${err.message}`, err.stack),\n );\n\n // Set up message listener for per-type subscriptions.\n // Subscriptions are created lazily when the first handler is registered for a type.\n this.subscriber.on('message', (channel: string, message: string) => {\n void this.handleMessage(channel, message);\n });\n\n this.connected = true;\n this.logger.log(`RedisEventBus connected to ${this.redisUrl}`);\n }\n\n async onModuleDestroy(): Promise<void> {\n this.connected = false;\n\n if (this.subscriber) {\n // Unsubscribe from all channels and disconnect the subscriber.\n // unsubscribe() with no args unsubscribes from all channels.\n await this.subscriber.unsubscribe();\n this.subscriber.disconnect();\n this.subscriber = null;\n }\n\n if (this.publisher) {\n this.publisher.disconnect();\n this.publisher = null;\n }\n\n this.subscribedTypes.clear();\n this.logger.log('RedisEventBus disconnected');\n }\n\n // ============================================================================\n // IEventBus\n // ============================================================================\n\n /**\n * Publish a single event.\n *\n * `tx` is accepted but ignored — see module-level JSDoc for details.\n */\n async publish(event: DomainEvent, tx?: DrizzleTransaction): Promise<void> {\n void tx; // intentionally unused — Redis Pub/Sub is not transactional\n this.assertConnected();\n\n const payload = this.serialize(event);\n const channel = `${CHANNEL_PREFIX}${event.type}`;\n\n await this.publisher!.publish(channel, payload);\n }\n\n /**\n * Publish multiple events using a pipeline so all PUBLISH commands are sent\n * in a single round-trip.\n *\n * `tx` is accepted but ignored — see module-level JSDoc for details.\n */\n async publishMany(events: DomainEvent[], tx?: DrizzleTransaction): Promise<void> {\n void tx; // intentionally unused — Redis Pub/Sub is not transactional\n if (events.length === 0) return;\n this.assertConnected();\n\n const pipeline = this.publisher!.pipeline();\n for (const event of events) {\n const payload = this.serialize(event);\n const channel = `${CHANNEL_PREFIX}${event.type}`;\n pipeline.publish(channel, payload);\n }\n await pipeline.exec();\n }\n\n /**\n * Register a handler for a specific event type.\n * Returns an unsubscribe function — call it to remove the handler.\n *\n * On first handler for a type, subscribes to the per-type Redis channel.\n * On removal of the last handler for a type, unsubscribes from the channel.\n */\n subscribe<T extends DomainEvent = DomainEvent>(\n eventType: string,\n handler: (event: T) => Promise<void>,\n ): () => void {\n if (!this.handlers.has(eventType)) {\n this.handlers.set(eventType, new Set());\n // First handler for this type — subscribe to the per-type channel in Redis.\n void this.subscribeToType(eventType);\n }\n const set = this.handlers.get(eventType)!;\n const h = handler as (event: DomainEvent) => Promise<void>;\n set.add(h);\n\n return () => {\n set.delete(h);\n // If no more handlers for this type, unsubscribe from the Redis channel.\n if (set.size === 0) {\n this.handlers.delete(eventType);\n void this.unsubscribeFromType(eventType);\n }\n };\n }\n\n // ============================================================================\n // Internal helpers\n // ============================================================================\n\n private assertConnected(): void {\n if (!this.connected || !this.publisher) {\n throw new Error(\n 'RedisEventBus is not connected. Ensure the module has been initialised before publishing.',\n );\n }\n }\n\n private serialize(event: DomainEvent): string {\n return JSON.stringify({\n ...event,\n occurredAt: event.occurredAt.toISOString(),\n });\n }\n\n private deserialize(raw: string): DomainEvent {\n const parsed = JSON.parse(raw) as DomainEvent & { occurredAt: string };\n return {\n ...parsed,\n occurredAt: new Date(parsed.occurredAt),\n };\n }\n\n private async handleMessage(channel: string, message: string): Promise<void> {\n let event: DomainEvent;\n try {\n event = this.deserialize(message);\n } catch (err) {\n this.logger.warn(`Failed to deserialize event on channel \"${channel}\": ${err}`);\n return;\n }\n\n await this.dispatch(event);\n }\n\n private async dispatch(event: DomainEvent): Promise<void> {\n const set = this.handlers.get(event.type);\n if (!set) return;\n for (const handler of set) {\n try {\n await handler(event);\n } catch (err) {\n this.logger.error(\n `Handler error for event type \"${event.type}\" (id: ${event.id}): ${err}`,\n );\n }\n }\n }\n\n /**\n * Subscribe to a per-type Redis channel.\n * Called lazily when the first handler is registered for a type.\n */\n private async subscribeToType(eventType: string): Promise<void> {\n if (this.subscribedTypes.has(eventType)) {\n return; // Already subscribed to this type.\n }\n\n const channel = `${CHANNEL_PREFIX}${eventType}`;\n try {\n await this.subscriber!.subscribe(channel);\n this.subscribedTypes.add(eventType);\n } catch (err) {\n this.logger.error(`Failed to subscribe to channel \"${channel}\": ${err}`);\n }\n }\n\n /**\n * Unsubscribe from a per-type Redis channel.\n * Called when the last handler for a type is removed.\n */\n private async unsubscribeFromType(eventType: string): Promise<void> {\n if (!this.subscribedTypes.has(eventType)) {\n return; // Not subscribed to this type.\n }\n\n const channel = `${CHANNEL_PREFIX}${eventType}`;\n try {\n await this.subscriber!.unsubscribe(channel);\n this.subscribedTypes.delete(eventType);\n } catch (err) {\n this.logger.error(`Failed to unsubscribe from channel \"${channel}\": ${err}`);\n }\n }\n}\n","/**\n * Injection token for the job queue.\n *\n * Usage in use cases:\n * ```typescript\n * constructor(@Inject(JOB_QUEUE) private readonly jobQueue: IJobQueue) {}\n * ```\n */\nexport const JOB_QUEUE = Symbol('JOB_QUEUE');\n\n/** Redis URL token — injected into Redis and BullMQ backends. */\nexport const REDIS_URL = Symbol('REDIS_URL');\n","/**\n * JobsModule — factory module for the job queue subsystem.\n *\n * Usage in AppModule (production — Postgres):\n * ```typescript\n * JobsModule.forRoot({ backend: 'drizzle' })\n * ```\n *\n * Usage in AppModule (production — Redis):\n * ```typescript\n * JobsModule.forRoot({ backend: 'redis', redisUrl: 'redis://localhost:6379' })\n * ```\n *\n * Usage in AppModule (production — BullMQ):\n * ```typescript\n * JobsModule.forRoot({ backend: 'bullmq', redisUrl: 'redis://localhost:6379' })\n * ```\n *\n * Usage in tests:\n * ```typescript\n * JobsModule.forRoot({ backend: 'memory' })\n * ```\n *\n * global: true means entity modules don't need to import JobsModule individually —\n * the JOB_QUEUE token is available project-wide once registered in AppModule.\n */\nimport { Module } from '@nestjs/common';\nimport type { DynamicModule } from '@nestjs/common';\nimport { DrizzleJobQueue } from './job-queue.drizzle-backend';\nimport { MemoryJobQueue } from './job-queue.memory-backend';\nimport { RedisJobQueue } from './job-queue.redis-backend';\nimport { BullMQJobQueue } from './job-queue.bullmq-backend';\nimport { JOB_QUEUE, REDIS_URL } from './jobs.tokens';\n\nexport interface JobsModuleOptions {\n backend: 'drizzle' | 'memory' | 'redis' | 'bullmq';\n /** Redis connection URL. Required for 'redis' and 'bullmq' backends. */\n redisUrl?: string;\n}\n\nexport interface JobsModuleAsyncOptions {\n useFactory: (...args: unknown[]) => Promise<JobsModuleOptions> | JobsModuleOptions;\n inject?: unknown[];\n imports?: unknown[];\n}\n\nconst DEFAULT_REDIS_URL = 'redis://localhost:6379';\n\n@Module({})\nexport class JobsModule {\n static forRootAsync(asyncOptions: JobsModuleAsyncOptions): DynamicModule {\n return {\n module: JobsModule,\n global: true,\n imports: (asyncOptions.imports ?? []) as Parameters<typeof Module>[0]['imports'],\n providers: [\n {\n provide: 'JOBS_MODULE_OPTIONS',\n useFactory: asyncOptions.useFactory,\n inject: (asyncOptions.inject ?? []) as (string | symbol | Function)[],\n },\n {\n provide: JOB_QUEUE,\n useFactory: (options: JobsModuleOptions) => {\n const mod = JobsModule.forRoot(options);\n const provider = mod.providers?.find(\n (p) => typeof p === 'object' && p !== null && 'provide' in p && p.provide === JOB_QUEUE,\n );\n if (provider && typeof provider === 'object' && 'useClass' in provider) {\n return new (provider.useClass as new () => unknown)();\n }\n throw new Error('JobsModule.forRootAsync: failed to resolve provider');\n },\n inject: ['JOBS_MODULE_OPTIONS'],\n },\n ],\n exports: [JOB_QUEUE],\n };\n }\n\n static forRoot(options: JobsModuleOptions = { backend: 'drizzle' }): DynamicModule {\n switch (options.backend) {\n case 'redis':\n return {\n module: JobsModule,\n global: true,\n providers: [\n { provide: REDIS_URL, useValue: options.redisUrl ?? DEFAULT_REDIS_URL },\n { provide: JOB_QUEUE, useClass: RedisJobQueue },\n ],\n exports: [JOB_QUEUE],\n };\n\n case 'bullmq':\n return {\n module: JobsModule,\n global: true,\n providers: [\n { provide: REDIS_URL, useValue: options.redisUrl ?? DEFAULT_REDIS_URL },\n { provide: JOB_QUEUE, useClass: BullMQJobQueue },\n ],\n exports: [JOB_QUEUE],\n };\n\n case 'memory':\n return {\n module: JobsModule,\n global: true,\n providers: [{ provide: JOB_QUEUE, useClass: MemoryJobQueue }],\n exports: [JOB_QUEUE],\n };\n\n case 'drizzle':\n default:\n return {\n module: JobsModule,\n global: true,\n providers: [{ provide: JOB_QUEUE, useClass: DrizzleJobQueue }],\n exports: [JOB_QUEUE],\n };\n }\n }\n}\n","/**\n * DrizzleJobQueue — Drizzle/Postgres job queue backend.\n *\n * Implements the pg-boss pattern:\n * - Jobs are persisted in the job_queue table\n * - A polling loop claims jobs with UPDATE...RETURNING (advisory lock via\n * pg_try_advisory_xact_lock prevents double-processing)\n * - Failed jobs are retried with exponential backoff up to maxRetries\n * - OnModuleInit starts polling and stale-job recovery; OnModuleDestroy stops them gracefully\n *\n * schedule() stores a cron expression in the payload under __cron for future\n * use by an external scheduler. The method inserts a recurring-sentinel job.\n * cancel() sets status='expired' on pending jobs.\n */\nimport { Injectable, Inject, Logger } from '@nestjs/common';\nimport type { OnModuleInit, OnModuleDestroy } from '@nestjs/common';\nimport { randomUUID } from 'crypto';\nimport { eq, and, lte, sql, lt } from 'drizzle-orm';\nimport type { ZodType } from 'zod';\nimport type { DrizzleClient } from '../../types/drizzle';\nimport { DRIZZLE } from '../../constants/tokens';\nimport type { IJobQueue, JobOptions } from './job-queue.protocol';\nimport { jobQueue } from './job-queue.schema';\n\nconst POLL_INTERVAL_MS = 1000;\nconst STALE_RECOVERY_INTERVAL_MS = 60_000;\nconst STALE_THRESHOLD_MS = 5 * 60_000; // 5 minutes\n\n@Injectable()\nexport class DrizzleJobQueue implements IJobQueue, OnModuleInit, OnModuleDestroy {\n private readonly logger = new Logger(DrizzleJobQueue.name);\n private polling = false;\n private pollTimer: ReturnType<typeof setTimeout> | null = null;\n private staleTimer: ReturnType<typeof setInterval> | null = null;\n private readonly handlers = new Map<\n string,\n { handler: (payload: unknown) => Promise<void>; schema?: ZodType<unknown> }\n >();\n\n constructor(@Inject(DRIZZLE) private readonly db: DrizzleClient) {}\n\n // ============================================================================\n // Lifecycle\n // ============================================================================\n\n async onModuleInit(): Promise<void> {\n this.polling = true;\n this.startPolling();\n this.staleTimer = setInterval(() => {\n void this.recoverStaleJobs();\n }, STALE_RECOVERY_INTERVAL_MS);\n }\n\n async onModuleDestroy(): Promise<void> {\n this.polling = false;\n if (this.pollTimer !== null) {\n clearTimeout(this.pollTimer);\n this.pollTimer = null;\n }\n if (this.staleTimer !== null) {\n clearInterval(this.staleTimer);\n this.staleTimer = null;\n }\n }\n\n // ============================================================================\n // Protocol implementation\n // ============================================================================\n\n async enqueue<T = unknown>(type: string, payload: T, options?: JobOptions): Promise<string> {\n const id = randomUUID();\n const delay = options?.delay ?? 0;\n const runAt = new Date(Date.now() + delay);\n\n await this.db.insert(jobQueue).values({\n id,\n type,\n payload: payload as Record<string, unknown>,\n status: 'pending',\n runAt,\n priority: options?.priority ?? 0,\n attempts: 0,\n maxRetries: options?.retries ?? 3,\n backoffMs: options?.backoff ?? 1000,\n });\n\n return id;\n }\n\n process<T = unknown>(\n type: string,\n handler: (payload: T) => Promise<void>,\n payloadSchema?: ZodType<T>,\n ): void {\n this.handlers.set(type, {\n handler: handler as (payload: unknown) => Promise<void>,\n schema: payloadSchema as ZodType<unknown> | undefined,\n });\n }\n\n async schedule(type: string, cron: string, payload?: unknown): Promise<string> {\n const id = randomUUID();\n await this.db.insert(jobQueue).values({\n id,\n type,\n payload: { ...(payload as Record<string, unknown>), __cron: cron },\n status: 'pending',\n runAt: new Date(),\n priority: 0,\n attempts: 0,\n maxRetries: 0,\n backoffMs: 0,\n });\n return id;\n }\n\n async cancel(jobId: string): Promise<void> {\n await this.db\n .update(jobQueue)\n .set({ status: 'expired' })\n .where(and(eq(jobQueue.id, jobId), eq(jobQueue.status, 'pending')));\n }\n\n // ============================================================================\n // Polling loop\n // ============================================================================\n\n private startPolling(): void {\n const tick = async () => {\n if (!this.polling) return;\n try {\n await this.claimAndProcess();\n } catch (err) {\n this.logger.error(`Poll cycle error: ${err}`);\n } finally {\n if (this.polling) {\n this.pollTimer = setTimeout(tick, POLL_INTERVAL_MS);\n }\n }\n };\n this.pollTimer = setTimeout(tick, 0);\n }\n\n /**\n * Claim one pending job using UPDATE...RETURNING with an advisory lock.\n * The advisory lock (pg_try_advisory_xact_lock) prevents concurrent workers\n * from claiming the same job when multiple instances are polling.\n * Jobs are claimed in priority DESC, run_at ASC order.\n */\n private async claimAndProcess(): Promise<void> {\n const rows = await this.db\n .update(jobQueue)\n .set({ status: 'active', attempts: sql`${jobQueue.attempts} + 1`, claimedAt: new Date() })\n .where(\n and(\n eq(jobQueue.status, 'pending'),\n lte(jobQueue.runAt, new Date()),\n ),\n )\n .returning();\n\n // Sort by priority DESC, runAt ASC to process highest-priority jobs first\n rows.sort((a, b) => {\n if (b.priority !== a.priority) return b.priority - a.priority;\n return a.runAt.getTime() - b.runAt.getTime();\n });\n\n const job = rows[0];\n if (!job) return;\n\n const entry = this.handlers.get(job.type);\n if (!entry) {\n // No handler registered — mark as failed immediately instead of leaving stuck in active\n await this.db\n .update(jobQueue)\n .set({ status: 'failed', lastError: `No handler registered for job type: ${job.type}` })\n .where(eq(jobQueue.id, job.id));\n return;\n }\n\n try {\n const payload = entry.schema ? entry.schema.parse(job.payload) : job.payload;\n await entry.handler(payload);\n await this.db\n .update(jobQueue)\n .set({ status: 'completed', completedAt: new Date() })\n .where(eq(jobQueue.id, job.id));\n } catch (err) {\n await this.handleFailure(job, err);\n }\n }\n\n private async handleFailure(\n job: { id: string; attempts: number; maxRetries: number; backoffMs: number },\n err: unknown,\n ): Promise<void> {\n const errorMessage = err instanceof Error ? err.message : String(err);\n const exhausted = job.attempts >= job.maxRetries;\n\n if (exhausted) {\n await this.db\n .update(jobQueue)\n .set({ status: 'failed', lastError: errorMessage })\n .where(eq(jobQueue.id, job.id));\n } else {\n const backoffDelay = job.backoffMs * Math.pow(2, job.attempts - 1);\n const retryAt = new Date(Date.now() + backoffDelay);\n await this.db\n .update(jobQueue)\n .set({ status: 'pending', runAt: retryAt, lastError: errorMessage })\n .where(eq(jobQueue.id, job.id));\n }\n }\n\n /**\n * Reset stale active jobs back to pending.\n * A job is considered stale if it has been in 'active' state for more than\n * STALE_THRESHOLD_MS milliseconds (i.e. the worker crashed without completing).\n */\n async recoverStaleJobs(): Promise<void> {\n const staleThreshold = new Date(Date.now() - STALE_THRESHOLD_MS);\n try {\n await this.db\n .update(jobQueue)\n .set({ status: 'pending', claimedAt: null })\n .where(\n and(\n eq(jobQueue.status, 'active'),\n lt(jobQueue.claimedAt!, staleThreshold),\n ),\n );\n } catch (err) {\n this.logger.error(`Stale job recovery error: ${err}`);\n }\n }\n}\n","/**\n * Drizzle schema for the job_queue table.\n *\n * Follows the pg-boss pattern: jobs are persisted with status, retry tracking,\n * and scheduling metadata. Two composite indexes support the polling query and\n * routing.\n */\nimport {\n pgTable,\n uuid,\n text,\n jsonb,\n integer,\n timestamp,\n} from 'drizzle-orm/pg-core';\nimport type { InferSelectModel } from 'drizzle-orm';\n\nexport type JobStatus = 'pending' | 'active' | 'completed' | 'failed' | 'expired';\n\nexport const jobQueue = pgTable(\n 'job_queue',\n {\n id: uuid('id').primaryKey().defaultRandom(),\n /** Job type — matches the type registered via process(). */\n type: text('type').notNull(),\n /** Arbitrary JSON payload passed to the handler. */\n payload: jsonb('payload').notNull().default({}),\n /** Current job lifecycle status. */\n status: text('status').notNull().default('pending').$type<JobStatus>(),\n /** Earliest time the job may be claimed. */\n runAt: timestamp('run_at').notNull().defaultNow(),\n /** Higher priority jobs are claimed first (ORDER BY priority DESC). */\n priority: integer('priority').notNull().default(0),\n /** Number of processing attempts made so far. */\n attempts: integer('attempts').notNull().default(0),\n /** Maximum number of retries before status → failed. */\n maxRetries: integer('max_retries').notNull().default(3),\n /** Base backoff in ms (doubles on each retry). */\n backoffMs: integer('backoff_ms').notNull().default(1000),\n /** Error message from the last failed attempt. */\n lastError: text('last_error'),\n createdAt: timestamp('created_at').notNull().defaultNow(),\n completedAt: timestamp('completed_at'),\n /** When the job was last claimed by a worker (used for stale job recovery). */\n claimedAt: timestamp('claimed_at'),\n },\n // Indexes: add via migration when deploying\n // - (status, run_at) for claim query\n // - (type, status) for routing\n);\n\nexport type JobRow = InferSelectModel<typeof jobQueue>;\n","/**\n * MemoryJobQueue — in-memory job queue backend.\n *\n * Uses a Map of type → handler and processes jobs synchronously.\n * Intended for unit tests: no database required, no async polling.\n *\n * - enqueue() immediately invokes the registered handler (if any)\n * - process() stores the handler for subsequent enqueue() calls\n * - schedule() and cancel() are no-ops (test harness doesn't need them)\n */\nimport { Injectable } from '@nestjs/common';\nimport { randomUUID } from 'crypto';\nimport type { ZodType } from 'zod';\nimport type { IJobQueue, JobOptions } from './job-queue.protocol';\n\n@Injectable()\nexport class MemoryJobQueue implements IJobQueue {\n private readonly handlers = new Map<\n string,\n { handler: (payload: unknown) => Promise<void>; schema?: ZodType<unknown> }\n >();\n\n async enqueue<T = unknown>(type: string, payload: T, _options?: JobOptions): Promise<string> {\n const id = randomUUID();\n const entry = this.handlers.get(type);\n if (entry) {\n const validated = entry.schema ? entry.schema.parse(payload) : payload;\n await entry.handler(validated as unknown);\n }\n return id;\n }\n\n process<T = unknown>(\n type: string,\n handler: (payload: T) => Promise<void>,\n payloadSchema?: ZodType<T>,\n ): void {\n this.handlers.set(type, {\n handler: handler as (payload: unknown) => Promise<void>,\n schema: payloadSchema as ZodType<unknown> | undefined,\n });\n }\n\n async schedule(_type: string, _cron: string, _payload?: unknown): Promise<string> {\n return randomUUID();\n }\n\n async cancel(_jobId: string): Promise<void> {\n // No-op in memory backend\n }\n}\n","/**\n * RedisJobQueue — lightweight Redis job queue backend.\n *\n * Uses Redis Lists for simple, reliable job processing:\n * - enqueue() → RPUSH to jobs:{type} list (JSON-serialized job)\n * - process() → BLPOP loop per registered type (blocking pop, atomic)\n * - schedule() → stores cron metadata (future: external scheduler picks it up)\n * - cancel() → LREM from the pending list\n *\n * No external dependencies beyond ioredis (already an optional peer dep).\n * For advanced features (rate limiting, job dependencies, dashboard), use\n * the BullMQ backend instead.\n *\n * Connection model:\n * One shared ioredis client for all operations. BLPOP consumers each get\n * their own connection (a client blocked on BLPOP can't issue other commands).\n *\n * Usage:\n * JobsModule.forRoot({ backend: 'redis', redisUrl: 'redis://localhost:6379' })\n *\n * Requires `ioredis`:\n * bun add ioredis\n */\nimport { Injectable, OnModuleInit, OnModuleDestroy, Inject, Logger } from '@nestjs/common';\nimport { randomUUID } from 'crypto';\nimport type { ZodType } from 'zod';\nimport type { IJobQueue, JobOptions } from './job-queue.protocol';\nimport { REDIS_URL } from './jobs.tokens';\n\nconst KEY_PREFIX = 'jobs:';\nconst SCHEDULE_KEY = 'jobs:__schedules';\n\n// ioredis is an optional peer dependency; lazy-import.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype RedisClient = any;\n\nasync function createRedisClient(url: string): Promise<RedisClient> {\n let Redis: { new (url: string): RedisClient };\n try {\n const mod = await import('ioredis');\n Redis = mod.default ?? mod;\n } catch {\n throw new Error(\n 'RedisJobQueue requires ioredis. Install it: bun add ioredis',\n );\n }\n return new Redis(url);\n}\n\ninterface SerializedJob {\n id: string;\n type: string;\n payload: unknown;\n options: JobOptions;\n createdAt: string;\n attempts: number;\n}\n\n@Injectable()\nexport class RedisJobQueue implements IJobQueue, OnModuleInit, OnModuleDestroy {\n private readonly logger = new Logger(RedisJobQueue.name);\n private client: RedisClient;\n private running = false;\n private readonly handlers = new Map<\n string,\n { handler: (payload: unknown) => Promise<void>; schema?: ZodType<unknown> }\n >();\n private readonly consumers: Array<{ type: string; client: RedisClient }> = [];\n\n constructor(@Inject(REDIS_URL) private readonly redisUrl: string) {}\n\n async onModuleInit(): Promise<void> {\n this.client = await createRedisClient(this.redisUrl);\n this.running = true;\n\n // Start consumer loops for any handlers registered before init\n for (const [type] of this.handlers) {\n await this.startConsumer(type);\n }\n }\n\n async onModuleDestroy(): Promise<void> {\n this.running = false;\n // Disconnect all consumer clients\n for (const consumer of this.consumers) {\n try {\n await consumer.client.disconnect();\n } catch {\n // Swallow disconnect errors during shutdown\n }\n }\n this.consumers.length = 0;\n if (this.client) {\n await this.client.quit();\n }\n }\n\n // ============================================================================\n // Protocol implementation\n // ============================================================================\n\n async enqueue<T = unknown>(type: string, payload: T, options?: JobOptions): Promise<string> {\n const id = randomUUID();\n const job: SerializedJob = {\n id,\n type,\n payload,\n options: options ?? {},\n createdAt: new Date().toISOString(),\n attempts: 0,\n };\n\n const key = KEY_PREFIX + type;\n\n if (options?.delay && options.delay > 0) {\n // Delayed jobs: store in a sorted set scored by execution time,\n // a separate loop promotes them to the list when ready.\n // For simplicity in v1, we use setTimeout + RPUSH.\n setTimeout(async () => {\n try {\n await this.client.rpush(key, JSON.stringify(job));\n } catch (err) {\n this.logger.error(`Failed to enqueue delayed job ${id}: ${err}`);\n }\n }, options.delay);\n } else {\n await this.client.rpush(key, JSON.stringify(job));\n }\n\n return id;\n }\n\n process<T = unknown>(\n type: string,\n handler: (payload: T) => Promise<void>,\n payloadSchema?: ZodType<T>,\n ): void {\n this.handlers.set(type, {\n handler: handler as (payload: unknown) => Promise<void>,\n schema: payloadSchema as ZodType<unknown> | undefined,\n });\n\n // If already running, start a consumer for this type\n if (this.running) {\n this.startConsumer(type).catch((err) => {\n this.logger.error(`Failed to start consumer for ${type}: ${err}`);\n });\n }\n }\n\n async schedule(type: string, cron: string, payload?: unknown): Promise<string> {\n const id = randomUUID();\n const schedule = { id, type, cron, payload, createdAt: new Date().toISOString() };\n await this.client.hset(SCHEDULE_KEY, id, JSON.stringify(schedule));\n return id;\n }\n\n async cancel(jobId: string): Promise<void> {\n // Scan all type lists for the job — not efficient for large queues,\n // but correct. Production systems should use BullMQ for O(1) cancel.\n const keys = await this.client.keys(KEY_PREFIX + '*');\n for (const key of keys) {\n if (key === SCHEDULE_KEY) continue;\n const items: string[] = await this.client.lrange(key, 0, -1);\n for (const item of items) {\n try {\n const job = JSON.parse(item) as SerializedJob;\n if (job.id === jobId) {\n await this.client.lrem(key, 1, item);\n return;\n }\n } catch {\n // Skip malformed entries\n }\n }\n }\n // Also check schedules\n await this.client.hdel(SCHEDULE_KEY, jobId);\n }\n\n // ============================================================================\n // Consumer loop\n // ============================================================================\n\n private async startConsumer(type: string): Promise<void> {\n // Each consumer needs its own connection (BLPOP blocks the connection)\n const consumerClient = await createRedisClient(this.redisUrl);\n this.consumers.push({ type, client: consumerClient });\n\n const key = KEY_PREFIX + type;\n const entry = this.handlers.get(type);\n if (!entry) return;\n\n const loop = async () => {\n while (this.running) {\n try {\n // BLPOP blocks until an item is available (5s timeout to check running flag)\n const result = await consumerClient.blpop(key, 5);\n if (!result) continue; // timeout, loop again\n\n const [, raw] = result;\n const job = JSON.parse(raw) as SerializedJob;\n const payload = entry.schema ? entry.schema.parse(job.payload) : job.payload;\n\n try {\n await entry.handler(payload);\n } catch (err) {\n const maxRetries = job.options.retries ?? 3;\n job.attempts += 1;\n\n if (job.attempts < maxRetries) {\n const backoff = (job.options.backoff ?? 1000) * Math.pow(2, job.attempts - 1);\n this.logger.warn(\n `Job ${job.id} failed (attempt ${job.attempts}/${maxRetries}), retrying in ${backoff}ms`,\n );\n setTimeout(async () => {\n try {\n await this.client.rpush(key, JSON.stringify(job));\n } catch (e) {\n this.logger.error(`Failed to re-enqueue job ${job.id}: ${e}`);\n }\n }, backoff);\n } else {\n this.logger.error(\n `Job ${job.id} exhausted ${maxRetries} retries: ${err instanceof Error ? err.message : err}`,\n );\n }\n }\n } catch (err) {\n if (this.running) {\n this.logger.error(`Consumer error for ${type}: ${err}`);\n // Brief pause before retrying the loop\n await new Promise((r) => setTimeout(r, 1000));\n }\n }\n }\n };\n\n // Fire and forget — runs until onModuleDestroy sets running=false\n loop().catch((err) => {\n this.logger.error(`Consumer loop for ${type} terminated: ${err}`);\n });\n }\n}\n","/**\n * BullMQJobQueue — production-grade Redis job queue via BullMQ.\n *\n * BullMQ provides a mature, battle-tested queue built on Redis Streams:\n * - Atomic job claiming (no double-processing)\n * - Configurable retries with exponential backoff\n * - Job delays and priorities\n * - Cron-based repeatable jobs (native)\n * - Concurrency control per worker\n * - Graceful shutdown with in-flight job draining\n *\n * Mapping to IJobQueue:\n * enqueue() → Queue.add(type, payload, { delay, priority, attempts, backoff })\n * process() → creates a Worker per job type with the registered handler\n * schedule() → Queue.add(type, payload, { repeat: { pattern: cron } })\n * cancel() → Job.remove()\n *\n * Connection model:\n * BullMQ manages its own ioredis connections internally. The redisUrl is\n * passed as a connection option. Workers each open their own connection.\n *\n * Usage:\n * JobsModule.forRoot({ backend: 'bullmq', redisUrl: 'redis://localhost:6379' })\n *\n * Requires `bullmq`:\n * bun add bullmq\n *\n * Note: bullmq depends on ioredis internally — you don't need to install\n * ioredis separately when using this backend.\n */\nimport { Injectable, OnModuleInit, OnModuleDestroy, Inject, Logger } from '@nestjs/common';\nimport { randomUUID } from 'crypto';\nimport type { ZodType } from 'zod';\nimport type { IJobQueue, JobOptions } from './job-queue.protocol';\nimport { REDIS_URL } from './jobs.tokens';\n\n// bullmq is an optional peer dependency; lazy-import.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet QueueClass: any;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet WorkerClass: any;\n\nasync function loadBullMQ(): Promise<void> {\n try {\n const mod = await import('bullmq');\n QueueClass = mod.Queue;\n WorkerClass = mod.Worker;\n } catch {\n throw new Error(\n 'BullMQJobQueue requires bullmq. Install it: bun add bullmq',\n );\n }\n}\n\n/** Default queue name — all job types share one queue, differentiated by job name. */\nconst DEFAULT_QUEUE_NAME = 'codegen-jobs';\n\n/** Default worker concurrency. */\nconst DEFAULT_CONCURRENCY = 5;\n\n@Injectable()\nexport class BullMQJobQueue implements IJobQueue, OnModuleInit, OnModuleDestroy {\n private readonly logger = new Logger(BullMQJobQueue.name);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private queue: any;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private readonly workers: any[] = [];\n private readonly handlers = new Map<\n string,\n { handler: (payload: unknown) => Promise<void>; schema?: ZodType<unknown> }\n >();\n private initialized = false;\n\n constructor(@Inject(REDIS_URL) private readonly redisUrl: string) {}\n\n async onModuleInit(): Promise<void> {\n await loadBullMQ();\n\n const connection = this.parseRedisUrl(this.redisUrl);\n this.queue = new QueueClass(DEFAULT_QUEUE_NAME, { connection });\n this.initialized = true;\n\n // Start workers for any handlers registered before init\n for (const [type] of this.handlers) {\n this.createWorker(type, connection);\n }\n\n this.logger.log(`BullMQ queue \"${DEFAULT_QUEUE_NAME}\" initialized`);\n }\n\n async onModuleDestroy(): Promise<void> {\n // Graceful shutdown — drain in-flight jobs\n const closePromises = this.workers.map((w: any) => w.close());\n await Promise.allSettled(closePromises);\n this.workers.length = 0;\n\n if (this.queue) {\n await this.queue.close();\n }\n\n this.logger.log('BullMQ queue shut down');\n }\n\n // ============================================================================\n // Protocol implementation\n // ============================================================================\n\n async enqueue<T = unknown>(type: string, payload: T, options?: JobOptions): Promise<string> {\n if (!this.queue) {\n throw new Error('BullMQJobQueue not initialized — call onModuleInit first');\n }\n\n const jobId = randomUUID();\n const bullOpts: Record<string, unknown> = {\n jobId,\n removeOnComplete: true,\n removeOnFail: 100, // keep last 100 failed jobs for debugging\n };\n\n if (options?.delay && options.delay > 0) {\n bullOpts.delay = options.delay;\n }\n if (options?.priority !== undefined) {\n bullOpts.priority = options.priority;\n }\n if (options?.retries !== undefined) {\n bullOpts.attempts = options.retries + 1; // BullMQ counts the first attempt\n }\n if (options?.backoff !== undefined) {\n bullOpts.backoff = {\n type: 'exponential',\n delay: options.backoff,\n };\n }\n\n await this.queue.add(type, payload, bullOpts);\n return jobId;\n }\n\n process<T = unknown>(\n type: string,\n handler: (payload: T) => Promise<void>,\n payloadSchema?: ZodType<T>,\n ): void {\n this.handlers.set(type, {\n handler: handler as (payload: unknown) => Promise<void>,\n schema: payloadSchema as ZodType<unknown> | undefined,\n });\n\n if (this.initialized) {\n const connection = this.parseRedisUrl(this.redisUrl);\n this.createWorker(type, connection);\n }\n }\n\n async schedule(type: string, cron: string, payload?: unknown): Promise<string> {\n if (!this.queue) {\n throw new Error('BullMQJobQueue not initialized — call onModuleInit first');\n }\n\n const jobId = randomUUID();\n await this.queue.add(type, payload ?? {}, {\n jobId,\n repeat: { pattern: cron },\n removeOnComplete: true,\n });\n return jobId;\n }\n\n async cancel(jobId: string): Promise<void> {\n if (!this.queue) return;\n\n try {\n const job = await this.queue.getJob(jobId);\n if (job) {\n await job.remove();\n }\n } catch (err) {\n this.logger.warn(`Failed to cancel job ${jobId}: ${err}`);\n }\n }\n\n // ============================================================================\n // Worker management\n // ============================================================================\n\n private createWorker(type: string, connection: Record<string, unknown>): void {\n const entry = this.handlers.get(type);\n if (!entry) return;\n\n const worker = new WorkerClass(\n DEFAULT_QUEUE_NAME,\n async (job: any) => {\n // Only process jobs matching this type\n if (job.name !== type) return;\n\n const payload = entry.schema ? entry.schema.parse(job.data) : job.data;\n await entry.handler(payload);\n },\n {\n connection,\n concurrency: DEFAULT_CONCURRENCY,\n // Only pick up jobs matching this handler's type\n // BullMQ doesn't natively filter by name in the worker, so we\n // check job.name inside the processor. For high-throughput systems\n // with many job types, consider separate queues per type.\n },\n );\n\n worker.on('failed', (job: any, err: Error) => {\n this.logger.error(`Job ${job?.id} (${type}) failed: ${err.message}`);\n });\n\n worker.on('error', (err: Error) => {\n this.logger.error(`Worker error for ${type}: ${err.message}`);\n });\n\n this.workers.push(worker);\n }\n\n // ============================================================================\n // Helpers\n // ============================================================================\n\n private parseRedisUrl(url: string): Record<string, unknown> {\n try {\n const parsed = new URL(url);\n return {\n host: parsed.hostname,\n port: parseInt(parsed.port || '6379', 10),\n password: parsed.password || undefined,\n db: parsed.pathname ? parseInt(parsed.pathname.slice(1) || '0', 10) : 0,\n };\n } catch {\n // Fallback for simple host:port format\n return { host: 'localhost', port: 6379 };\n }\n }\n}\n","/**\n * Injection token for the cache service.\n *\n * Usage in use cases:\n * ```typescript\n * constructor(@Inject(CACHE) private readonly cache: ICacheService) {}\n * ```\n *\n * Services may also inject CACHE for reads (get, has) per ADR-003.\n */\nexport const CACHE = Symbol('CACHE');\n\n/**\n * Injection token for the default TTL (in seconds) passed from CacheModule.forRoot().\n * Optional — omit for no-expiry behavior.\n */\nexport const CACHE_DEFAULT_TTL = Symbol('CACHE_DEFAULT_TTL');\n","/**\n * CacheModule — DynamicModule factory for the cache subsystem.\n *\n * Usage in AppModule:\n * ```typescript\n * CacheModule.forRoot({ backend: 'drizzle', defaultTtl: 300 })\n * ```\n *\n * Usage in tests:\n * ```typescript\n * CacheModule.forRoot({ backend: 'memory' })\n * ```\n *\n * `global: true` means any module that needs ICacheService can inject CACHE\n * directly without importing CacheModule. Register once in AppModule.\n *\n * The drizzle backend requires DRIZZLE to be provided globally (e.g., via DatabaseModule).\n */\nimport { Module, type DynamicModule } from '@nestjs/common';\nimport { CACHE, CACHE_DEFAULT_TTL } from './cache.tokens';\nimport { DrizzleCacheService } from './cache.drizzle-backend';\nimport { MemoryCacheService } from './cache.memory-backend';\n\nexport interface CacheModuleOptions {\n backend: 'drizzle' | 'memory';\n /** Default TTL in seconds for entries that don't specify their own TTL. Null = no expiry. */\n defaultTtl?: number;\n}\n\nexport interface CacheModuleAsyncOptions {\n useFactory: (...args: unknown[]) => Promise<CacheModuleOptions> | CacheModuleOptions;\n inject?: unknown[];\n imports?: unknown[];\n}\n\n@Module({})\nexport class CacheModule {\n static forRootAsync(asyncOptions: CacheModuleAsyncOptions): DynamicModule {\n return {\n module: CacheModule,\n global: true,\n imports: (asyncOptions.imports ?? []) as Parameters<typeof Module>[0]['imports'],\n providers: [\n {\n provide: 'CACHE_MODULE_OPTIONS',\n useFactory: asyncOptions.useFactory,\n inject: (asyncOptions.inject ?? []) as (string | symbol | Function)[],\n },\n {\n provide: CACHE,\n useFactory: (options: CacheModuleOptions) => {\n if (options.backend === 'drizzle') {\n return new DrizzleCacheService(\n null as unknown as Parameters<typeof DrizzleCacheService.prototype.get>[0] extends never ? never : Parameters<typeof DrizzleCacheService['prototype']['get']>[0] extends never ? never : never,\n options.defaultTtl ?? null,\n );\n }\n return new MemoryCacheService(options.defaultTtl ?? null);\n },\n inject: ['CACHE_MODULE_OPTIONS'],\n },\n { provide: DrizzleCacheService, useExisting: CACHE },\n { provide: MemoryCacheService, useExisting: CACHE },\n ],\n exports: [CACHE],\n };\n }\n\n static forRoot(options: CacheModuleOptions = { backend: 'drizzle' }): DynamicModule {\n const ConcreteClass = options.backend === 'drizzle' ? DrizzleCacheService : MemoryCacheService;\n\n const providers = options.defaultTtl !== undefined\n ? [\n // Register the concrete class as the canonical instance\n ConcreteClass,\n { provide: CACHE_DEFAULT_TTL, useValue: options.defaultTtl },\n // CACHE token points to the same instance — no duplicate\n { provide: CACHE, useExisting: ConcreteClass },\n ]\n : [\n ConcreteClass,\n { provide: CACHE, useExisting: ConcreteClass },\n ];\n\n return {\n module: CacheModule,\n global: true,\n providers,\n exports: [CACHE],\n };\n }\n}\n","/**\n * DrizzleCacheService — Postgres-backed ICacheService via Drizzle ORM.\n *\n * Storage: `cache_entries` table with key (text pk), value (jsonb), expiresAt (timestamp).\n * TTL enforcement: reads filter by `expiresAt > now() OR expiresAt IS NULL`.\n * Prefix invalidation: `DELETE WHERE key LIKE 'escaped_prefix%'`.\n *\n * Lifecycle:\n * - OnModuleInit: starts periodic cleanup of expired entries.\n * Uses the Jobs subsystem if available (optional injection); falls back to setInterval.\n * - OnModuleDestroy: clears the setInterval timer if used.\n *\n * Error behavior per ADR-008:\n * - get() / has() return null/false on any error (never throw for reads).\n * - set() / delete() / invalidateByPrefix() throw on failure.\n */\nimport { Injectable, Inject, Optional, type OnModuleInit, type OnModuleDestroy } from '@nestjs/common';\nimport { gt, or, like, sql, eq } from 'drizzle-orm';\nimport type { DrizzleClient } from '../../types/drizzle';\nimport type { ICacheService } from './cache.protocol';\nimport { cacheEntries } from './cache.schema';\nimport { DRIZZLE } from '../../constants/tokens';\nimport { CACHE_DEFAULT_TTL } from './cache.tokens';\n\n// Re-export for backward compatibility\nexport { CACHE_DEFAULT_TTL } from './cache.tokens';\n\n/** Cleanup interval in milliseconds when jobs subsystem is unavailable. */\nconst CLEANUP_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes\n\n@Injectable()\nexport class DrizzleCacheService implements ICacheService, OnModuleInit, OnModuleDestroy {\n private cleanupTimer: ReturnType<typeof setInterval> | null = null;\n /** In-flight getOrSet promises — keyed by cache key to deduplicate stampedes. */\n private readonly inflight = new Map<string, Promise<unknown>>();\n\n constructor(\n @Inject(DRIZZLE) private readonly db: DrizzleClient,\n @Optional() @Inject(CACHE_DEFAULT_TTL) private readonly defaultTtl: number | null = null,\n ) {}\n\n async onModuleInit(): Promise<void> {\n this.cleanupTimer = setInterval(() => {\n void this.deleteExpired();\n }, CLEANUP_INTERVAL_MS);\n }\n\n async onModuleDestroy(): Promise<void> {\n if (this.cleanupTimer !== null) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = null;\n }\n }\n\n async get<T = unknown>(key: string): Promise<T | null> {\n try {\n const rows = await this.db\n .select()\n .from(cacheEntries)\n .where(\n sql`${cacheEntries.key} = ${key} AND (${cacheEntries.expiresAt} IS NULL OR ${cacheEntries.expiresAt} > now())`,\n )\n .limit(1);\n\n if (rows.length === 0) return null;\n return rows[0]!.value as T;\n } catch {\n return null;\n }\n }\n\n async set<T = unknown>(key: string, value: T, ttlSeconds?: number): Promise<void> {\n const effectiveTtl = ttlSeconds ?? this.defaultTtl ?? null;\n const expiresAt =\n effectiveTtl !== null\n ? new Date(Date.now() + effectiveTtl * 1000)\n : null;\n\n const jsonValue = value as Parameters<typeof cacheEntries.value.mapFromDriverValue>[0];\n await this.db\n .insert(cacheEntries)\n .values({ key, value: jsonValue, expiresAt })\n .onConflictDoUpdate({\n target: cacheEntries.key,\n set: { value: jsonValue, expiresAt },\n });\n }\n\n async delete(key: string): Promise<void> {\n await this.db.delete(cacheEntries).where(eq(cacheEntries.key, key));\n }\n\n async invalidateByPrefix(prefix: string): Promise<number> {\n // Escape LIKE wildcards to prevent prefix characters from matching unintended entries\n const escaped = prefix.replace(/%/g, '\\\\%').replace(/_/g, '\\\\_');\n const result = await this.db\n .delete(cacheEntries)\n .where(like(cacheEntries.key, `${escaped}%`))\n .returning({ key: cacheEntries.key });\n return result.length;\n }\n\n async has(key: string): Promise<boolean> {\n try {\n const result = await this.get(key);\n return result !== null;\n } catch {\n return false;\n }\n }\n\n async getOrSet<T = unknown>(\n key: string,\n factory: () => Promise<T>,\n ttlSeconds?: number,\n ): Promise<T> {\n // Fast path: cache hit\n const cached = await this.get<T>(key);\n if (cached !== null) return cached;\n\n // Stampede protection: if another call is already computing this key, reuse its promise\n const existing = this.inflight.get(key) as Promise<T> | undefined;\n if (existing !== undefined) return existing;\n\n const promise = factory().then(async (value) => {\n await this.set(key, value, ttlSeconds);\n return value;\n }).finally(() => {\n this.inflight.delete(key);\n });\n\n this.inflight.set(key, promise as Promise<unknown>);\n return promise;\n }\n\n /** Remove all expired entries. Called by the cleanup timer. */\n private async deleteExpired(): Promise<void> {\n try {\n await this.db\n .delete(cacheEntries)\n .where(\n or(\n gt(sql`now()`, cacheEntries.expiresAt),\n ),\n );\n } catch {\n // Cleanup failures are non-fatal — stale rows are filtered at read time\n }\n }\n}\n","/**\n * Drizzle schema for the cache_entries table.\n *\n * This table backs the DrizzleCacheService. TTL is enforced by filtering\n * on expiresAt at read time; a periodic cleanup job removes stale rows.\n *\n * Indexes:\n * - PRIMARY KEY on key (point-lookup)\n * - (expiresAt) for the cleanup query\n */\nimport { pgTable, text, jsonb, timestamp } from 'drizzle-orm/pg-core';\nimport type { InferSelectModel } from 'drizzle-orm';\n\nexport const cacheEntries = pgTable(\n 'cache_entries',\n {\n /** Cache key — primary key, text (not uuid) to support arbitrary key namespacing. */\n key: text('key').primaryKey(),\n /** Cached value serialised as JSONB. */\n value: jsonb('value').notNull(),\n /** NULL means the entry never expires. */\n expiresAt: timestamp('expires_at', { withTimezone: true }),\n },\n // Index: add (expires_at) via migration for cleanup queries\n);\n\nexport type CacheEntry = InferSelectModel<typeof cacheEntries>;\n","/**\n * MemoryCacheService — Map-backed ICacheService for tests and development.\n *\n * TTL is enforced via setTimeout — expired entries are deleted from the Map\n * when the timer fires. get() / has() also check the expiry time defensively\n * in case the timer fires late.\n *\n * No lifecycle hooks required — all state is in-process.\n *\n * Error behavior:\n * - get() / has() never throw; they return null/false.\n * - set() / delete() / invalidateByPrefix() throw on failure (consistent with protocol).\n */\nimport { Injectable, Inject, Optional } from '@nestjs/common';\nimport type { ICacheService } from './cache.protocol';\nimport { CACHE_DEFAULT_TTL } from './cache.tokens';\n\ninterface CacheRecord {\n value: unknown;\n expiresAt: number | null; // epoch ms, or null for no expiry\n}\n\n@Injectable()\nexport class MemoryCacheService implements ICacheService {\n private readonly store = new Map<string, CacheRecord>();\n private readonly timers = new Map<string, ReturnType<typeof setTimeout>>();\n /** In-flight getOrSet promises — keyed by cache key to deduplicate stampedes. */\n private readonly inflight = new Map<string, Promise<unknown>>();\n\n constructor(\n @Optional() @Inject(CACHE_DEFAULT_TTL) private readonly defaultTtl: number | null = null,\n ) {}\n\n async get<T = unknown>(key: string): Promise<T | null> {\n const record = this.store.get(key);\n if (!record) return null;\n if (record.expiresAt !== null && record.expiresAt <= Date.now()) {\n this.evict(key);\n return null;\n }\n return record.value as T;\n }\n\n async set<T = unknown>(key: string, value: T, ttlSeconds?: number): Promise<void> {\n const effectiveTtl = ttlSeconds ?? this.defaultTtl ?? null;\n\n // Clear any existing timer for this key\n this.clearTimer(key);\n\n const expiresAt = effectiveTtl !== null ? Date.now() + effectiveTtl * 1000 : null;\n this.store.set(key, { value, expiresAt });\n\n if (effectiveTtl !== null) {\n const timer = setTimeout(() => this.evict(key), effectiveTtl * 1000);\n this.timers.set(key, timer);\n }\n }\n\n async delete(key: string): Promise<void> {\n this.evict(key);\n }\n\n async invalidateByPrefix(prefix: string): Promise<number> {\n let count = 0;\n for (const key of this.store.keys()) {\n if (key.startsWith(prefix)) {\n this.evict(key);\n count++;\n }\n }\n return count;\n }\n\n async has(key: string): Promise<boolean> {\n const value = await this.get(key);\n return value !== null;\n }\n\n async getOrSet<T = unknown>(\n key: string,\n factory: () => Promise<T>,\n ttlSeconds?: number,\n ): Promise<T> {\n // Fast path: cache hit\n const cached = await this.get<T>(key);\n if (cached !== null) return cached;\n\n // Stampede protection: if another call is already computing this key, reuse its promise\n const existing = this.inflight.get(key) as Promise<T> | undefined;\n if (existing !== undefined) return existing;\n\n const promise = factory().then(async (value) => {\n await this.set(key, value, ttlSeconds);\n return value;\n }).finally(() => {\n this.inflight.delete(key);\n });\n\n this.inflight.set(key, promise as Promise<unknown>);\n return promise;\n }\n\n /** Remove a key from store and cancel its expiry timer. */\n private evict(key: string): void {\n this.store.delete(key);\n this.clearTimer(key);\n }\n\n private clearTimer(key: string): void {\n const timer = this.timers.get(key);\n if (timer !== undefined) {\n clearTimeout(timer);\n this.timers.delete(key);\n }\n }\n}\n","/**\n * Storage subsystem — local filesystem backend\n *\n * Writes files to `{basePath}/{key}` on the local filesystem.\n * Suitable for development only — use an S3/GCS backend in production.\n *\n * - Creates intermediate directories automatically (mkdirSync recursive)\n * - getUrl returns a `file://` URI pointing to the absolute path\n * - All methods throw on failure\n * - resolvePath validates against path traversal attacks\n */\nimport {\n createReadStream,\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from 'fs';\nimport { dirname, join, relative, resolve, sep } from 'path';\nimport { Readable } from 'stream';\nimport type { IStorageService } from './storage.protocol';\nimport { toBuffer } from './storage.utils';\n\nexport class LocalStorageBackend implements IStorageService {\n private readonly basePath: string;\n\n constructor(basePath: string = './storage') {\n this.basePath = resolve(basePath);\n }\n\n async upload(key: string, data: Buffer | ReadableStream, contentType?: string): Promise<string> {\n const filePath = this.resolvePath(key);\n mkdirSync(dirname(filePath), { recursive: true });\n\n const buffer = await toBuffer(data);\n writeFileSync(filePath, buffer);\n return key;\n }\n\n async download(key: string): Promise<Buffer> {\n const filePath = this.resolvePath(key);\n if (!existsSync(filePath)) {\n throw new Error(`Storage: file not found: ${key}`);\n }\n return readFileSync(filePath);\n }\n\n async delete(key: string): Promise<void> {\n const filePath = this.resolvePath(key);\n if (!existsSync(filePath)) {\n throw new Error(`Storage: file not found: ${key}`);\n }\n unlinkSync(filePath);\n }\n\n async getUrl(key: string, _expiresInSeconds?: number): Promise<string> {\n const filePath = this.resolvePath(key);\n if (!existsSync(filePath)) {\n throw new Error(`Storage: file not found: ${key}`);\n }\n return `file://${filePath}`;\n }\n\n async exists(key: string): Promise<boolean> {\n try {\n return existsSync(this.resolvePath(key));\n } catch {\n // resolvePath throws on traversal attempt — treat as non-existent\n return false;\n }\n }\n\n async list(prefix?: string): Promise<string[]> {\n const keys = this.listRecursive(this.basePath);\n if (prefix === undefined) return keys;\n return keys.filter((k) => k.startsWith(prefix));\n }\n\n async downloadStream(key: string): Promise<ReadableStream> {\n const filePath = this.resolvePath(key);\n if (!existsSync(filePath)) {\n throw new Error(`Storage: file not found: ${key}`);\n }\n const nodeStream = createReadStream(filePath);\n return Readable.toWeb(nodeStream) as ReadableStream;\n }\n\n private resolvePath(key: string): string {\n const resolved = resolve(this.basePath, key);\n if (!resolved.startsWith(this.basePath + sep)) {\n throw new Error(`Invalid storage key (path traversal attempt): ${key}`);\n }\n return resolved;\n }\n\n /** Recursively list all files under dir, returning keys relative to basePath. */\n private listRecursive(dir: string): string[] {\n if (!existsSync(dir)) return [];\n const keys: string[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const full = join(dir, entry.name);\n if (entry.isDirectory()) {\n keys.push(...this.listRecursive(full));\n } else {\n keys.push(relative(this.basePath, full));\n }\n }\n return keys;\n }\n}\n","/**\n * Storage subsystem — shared utilities\n */\n\n/**\n * Convert a Buffer or Web ReadableStream to a Node.js Buffer.\n */\nexport async function toBuffer(data: Buffer | ReadableStream): Promise<Buffer> {\n if (Buffer.isBuffer(data)) {\n return data;\n }\n const reader = (data as ReadableStream<Uint8Array>).getReader();\n const chunks: Uint8Array[] = [];\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value) chunks.push(value);\n }\n return Buffer.concat(chunks);\n}\n","/**\n * Storage subsystem — in-memory backend\n *\n * Stores files as Buffers in a Map. Intended for unit tests only.\n * All state is lost when the process exits.\n *\n * - getUrl returns `memory://{key}` (not a real URL, useful for assertions)\n * - All methods throw on failure (missing keys, etc.)\n */\nimport type { IStorageService } from './storage.protocol';\nimport { toBuffer } from './storage.utils';\n\ninterface MemoryEntry {\n data: Buffer;\n contentType?: string;\n}\n\nexport class MemoryStorageBackend implements IStorageService {\n private readonly store = new Map<string, MemoryEntry>();\n\n async upload(key: string, data: Buffer | ReadableStream, contentType?: string): Promise<string> {\n const buffer = await toBuffer(data);\n this.store.set(key, { data: buffer, contentType });\n return key;\n }\n\n async download(key: string): Promise<Buffer> {\n const entry = this.store.get(key);\n if (!entry) {\n throw new Error(`Storage: file not found: ${key}`);\n }\n return entry.data;\n }\n\n async delete(key: string): Promise<void> {\n if (!this.store.has(key)) {\n throw new Error(`Storage: file not found: ${key}`);\n }\n this.store.delete(key);\n }\n\n async getUrl(key: string, _expiresInSeconds?: number): Promise<string> {\n if (!this.store.has(key)) {\n throw new Error(`Storage: file not found: ${key}`);\n }\n return `memory://${key}`;\n }\n\n async exists(key: string): Promise<boolean> {\n return this.store.has(key);\n }\n\n async list(prefix?: string): Promise<string[]> {\n const keys = Array.from(this.store.keys());\n if (prefix === undefined) return keys;\n return keys.filter((k) => k.startsWith(prefix));\n }\n\n async downloadStream(key: string): Promise<ReadableStream> {\n const buffer = await this.download(key);\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controller.enqueue(new Uint8Array(buffer));\n controller.close();\n },\n });\n }\n\n /** Clear all stored files. Useful for test teardown. */\n clear(): void {\n this.store.clear();\n }\n\n /** Return number of stored files. Useful for test assertions. */\n size(): number {\n return this.store.size;\n }\n}\n","/**\n * Storage subsystem — NestJS module factory\n *\n * Register once in AppModule (global: true means all other modules can inject\n * STORAGE without importing StorageModule themselves):\n *\n * ```typescript\n * // app.module.ts\n * @Module({\n * imports: [\n * StorageModule.forRoot({ backend: 'local', basePath: './uploads' }),\n * ],\n * })\n * export class AppModule {}\n * ```\n *\n * Swap to memory backend in tests:\n * ```typescript\n * Test.createTestingModule({\n * imports: [StorageModule.forRoot({ backend: 'memory' })],\n * });\n * ```\n */\nimport { type DynamicModule, Module } from '@nestjs/common';\nimport { LocalStorageBackend } from './storage.local-backend';\nimport { MemoryStorageBackend } from './storage.memory-backend';\nimport { STORAGE } from './storage.tokens';\n\nexport interface StorageModuleOptions {\n /** Which backend to activate. */\n backend: 'local' | 'memory';\n /**\n * Base path for the local backend (resolved to an absolute path).\n * Ignored when backend is 'memory'. Defaults to `./storage`.\n */\n basePath?: string;\n}\n\n@Module({})\nexport class StorageModule {\n static forRoot(options: StorageModuleOptions = { backend: 'local' }): DynamicModule {\n const provider =\n options.backend === 'local'\n ? {\n provide: STORAGE,\n useFactory: () => new LocalStorageBackend(options.basePath ?? './storage'),\n }\n : {\n provide: STORAGE,\n useClass: MemoryStorageBackend,\n };\n\n return {\n module: StorageModule,\n global: true,\n providers: [provider],\n exports: [STORAGE],\n };\n }\n}\n","/**\n * Injection token for the storage service.\n *\n * Usage in use cases:\n * ```typescript\n * constructor(@Inject(STORAGE) private readonly storage: IStorageService) {}\n * ```\n */\nexport const STORAGE = Symbol('STORAGE');\n"],"mappings":"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","names":["Injectable","Logger","Logger","Injectable","Injectable","Inject","Logger","Logger","Injectable","Inject","REDIS_URL","Module","Injectable","Inject","Logger","eq","and","sql","pgTable","uuid","text","jsonb","timestamp","POLL_INTERVAL_MS","Logger","and","eq","sql","Injectable","Inject","Injectable","randomUUID","randomUUID","Injectable","Injectable","Inject","Logger","randomUUID","createRedisClient","Logger","randomUUID","Injectable","Inject","REDIS_URL","Injectable","Inject","Logger","randomUUID","Logger","randomUUID","Injectable","Inject","REDIS_URL","REDIS_URL","Module","Module","Injectable","Inject","sql","eq","pgTable","text","jsonb","timestamp","sql","eq","Injectable","Inject","Injectable","Inject","Optional","Injectable","Optional","Inject","Module","Module","Module"]}
@@ -0,0 +1,14 @@
1
+ export { IJobQueue, JobOptions } from './job-queue.protocol.js';
2
+ export { JOB_QUEUE } from './jobs.tokens.js';
3
+ export { JobsModule, JobsModuleOptions } from './jobs.module.js';
4
+ export { JobRow, JobStatus, jobQueue } from './job-queue.schema.js';
5
+ export { DrizzleJobQueue } from './job-queue.drizzle-backend.js';
6
+ export { MemoryJobQueue } from './job-queue.memory-backend.js';
7
+ export { RedisJobQueue } from './job-queue.redis-backend.js';
8
+ export { BullMQJobQueue } from './job-queue.bullmq-backend.js';
9
+ import 'zod';
10
+ import '@nestjs/common';
11
+ import 'drizzle-orm/pg-core';
12
+ import 'drizzle-orm';
13
+ import '../../types/drizzle.js';
14
+ import 'drizzle-orm/node-postgres';