@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,259 @@
1
+ ---
2
+ to: src/infrastructure/broadcast/websocket-broadcast.backend.ts
3
+ force: true
4
+ ---
5
+ import { Injectable, Logger } from '@nestjs/common'
6
+ import {
7
+ WebSocketGateway,
8
+ WebSocketServer,
9
+ SubscribeMessage,
10
+ OnGatewayConnection,
11
+ OnGatewayDisconnect,
12
+ ConnectedSocket,
13
+ MessageBody,
14
+ } from '@nestjs/websockets'
15
+ import type { Server, Socket } from 'socket.io'
16
+ import type {
17
+ BroadcastBackend,
18
+ BroadcastHandler,
19
+ } from './broadcast-backend.interface'
20
+
21
+ interface SubscribePayload {
22
+ channels: string[]
23
+ }
24
+
25
+ interface UnsubscribePayload {
26
+ channels: string[]
27
+ }
28
+
29
+ interface BroadcastMessage {
30
+ channel: string
31
+ event: string
32
+ payload: Record<string, unknown>
33
+ }
34
+
35
+ /**
36
+ * WebSocket-based broadcast backend using Socket.IO.
37
+ * Clients connect and subscribe to channels to receive real-time domain events.
38
+ *
39
+ * Protocol:
40
+ * Client → Server: { "subscribe": ["session", "agent"] }
41
+ * Client → Server: { "unsubscribe": ["session"] }
42
+ * Server → Client: { "channel": "session", "event": "session.running", "payload": {...} }
43
+ */
44
+ @Injectable()
45
+ @WebSocketGateway({
46
+ path: '<%= websocketPath %>',
47
+ cors: {
48
+ origin: '<%= corsOrigin %>',
49
+ credentials: <%= corsCredentials %>,
50
+ },
51
+ })
52
+ export class WebSocketBroadcastBackend
53
+ implements BroadcastBackend, OnGatewayConnection, OnGatewayDisconnect
54
+ {
55
+ private readonly logger = new Logger(WebSocketBroadcastBackend.name)
56
+
57
+ @WebSocketServer()
58
+ private server!: Server
59
+
60
+ /** channel -> set of subscribed sockets */
61
+ private channelSubscribers = new Map<string, Set<Socket>>()
62
+
63
+ /** socket -> set of channels subscribed to */
64
+ private socketChannels = new Map<Socket, Set<string>>()
65
+
66
+ /** server-side handlers for channels */
67
+ private handlers = new Map<string, Set<BroadcastHandler>>()
68
+
69
+ private closed = false
70
+
71
+ readonly supportsPush = true
72
+
73
+ handleConnection(client: Socket): void {
74
+ this.logger.log(`Client connected: ${client.id}`)
75
+ this.socketChannels.set(client, new Set())
76
+ }
77
+
78
+ handleDisconnect(client: Socket): void {
79
+ this.logger.log(`Client disconnected: ${client.id}`)
80
+
81
+ // Remove client from all channel subscriptions
82
+ const channels = this.socketChannels.get(client)
83
+ if (channels) {
84
+ for (const channel of channels) {
85
+ const subscribers = this.channelSubscribers.get(channel)
86
+ if (subscribers) {
87
+ subscribers.delete(client)
88
+ if (subscribers.size === 0) {
89
+ this.channelSubscribers.delete(channel)
90
+ }
91
+ }
92
+ }
93
+ }
94
+ this.socketChannels.delete(client)
95
+ }
96
+
97
+ @SubscribeMessage('subscribe')
98
+ handleSubscribe(
99
+ @ConnectedSocket() client: Socket,
100
+ @MessageBody() data: SubscribePayload,
101
+ ): { subscribed: string[] } {
102
+ const channels = data?.channels ?? []
103
+ const subscribedChannels: string[] = []
104
+
105
+ for (const channel of channels) {
106
+ if (typeof channel !== 'string' || channel.length === 0) {
107
+ continue
108
+ }
109
+
110
+ // Add to channel subscribers
111
+ let subscribers = this.channelSubscribers.get(channel)
112
+ if (!subscribers) {
113
+ subscribers = new Set()
114
+ this.channelSubscribers.set(channel, subscribers)
115
+ }
116
+ subscribers.add(client)
117
+
118
+ // Track which channels this socket is subscribed to
119
+ const socketChans = this.socketChannels.get(client)
120
+ if (socketChans) {
121
+ socketChans.add(channel)
122
+ }
123
+
124
+ subscribedChannels.push(channel)
125
+ this.logger.debug(`Client ${client.id} subscribed to channel: ${channel}`)
126
+ }
127
+
128
+ return { subscribed: subscribedChannels }
129
+ }
130
+
131
+ @SubscribeMessage('unsubscribe')
132
+ handleUnsubscribe(
133
+ @ConnectedSocket() client: Socket,
134
+ @MessageBody() data: UnsubscribePayload,
135
+ ): { unsubscribed: string[] } {
136
+ const channels = data?.channels ?? []
137
+ const unsubscribedChannels: string[] = []
138
+
139
+ for (const channel of channels) {
140
+ if (typeof channel !== 'string' || channel.length === 0) {
141
+ continue
142
+ }
143
+
144
+ // Remove from channel subscribers
145
+ const subscribers = this.channelSubscribers.get(channel)
146
+ if (subscribers) {
147
+ subscribers.delete(client)
148
+ if (subscribers.size === 0) {
149
+ this.channelSubscribers.delete(channel)
150
+ }
151
+ }
152
+
153
+ // Remove from socket's channel list
154
+ const socketChans = this.socketChannels.get(client)
155
+ if (socketChans) {
156
+ socketChans.delete(channel)
157
+ }
158
+
159
+ unsubscribedChannels.push(channel)
160
+ this.logger.debug(
161
+ `Client ${client.id} unsubscribed from channel: ${channel}`,
162
+ )
163
+ }
164
+
165
+ return { unsubscribed: unsubscribedChannels }
166
+ }
167
+
168
+ async broadcast(
169
+ channel: string,
170
+ eventType: string,
171
+ payload: Record<string, unknown>,
172
+ ): Promise<void> {
173
+ if (this.closed) {
174
+ throw new Error('Broadcast backend is closed')
175
+ }
176
+
177
+ const message: BroadcastMessage = {
178
+ channel,
179
+ event: eventType,
180
+ payload,
181
+ }
182
+
183
+ // Send to WebSocket clients
184
+ const subscribers = this.channelSubscribers.get(channel)
185
+ if (subscribers && subscribers.size > 0) {
186
+ for (const socket of subscribers) {
187
+ socket.emit('broadcast', message)
188
+ }
189
+ this.logger.debug(
190
+ `Broadcast to ${subscribers.size} clients on channel "${channel}": ${eventType}`,
191
+ )
192
+ }
193
+
194
+ // Call server-side handlers
195
+ const channelHandlers = this.handlers.get(channel)
196
+ if (channelHandlers && channelHandlers.size > 0) {
197
+ const promises = Array.from(channelHandlers).map((handler) =>
198
+ handler(eventType, payload).catch((error) => {
199
+ this.logger.error(
200
+ `Handler error on channel "${channel}": ${error.message}`,
201
+ )
202
+ }),
203
+ )
204
+ await Promise.all(promises)
205
+ }
206
+ }
207
+
208
+ async subscribe(channel: string, handler: BroadcastHandler): Promise<void> {
209
+ if (this.closed) {
210
+ throw new Error('Broadcast backend is closed')
211
+ }
212
+
213
+ let channelHandlers = this.handlers.get(channel)
214
+ if (!channelHandlers) {
215
+ channelHandlers = new Set()
216
+ this.handlers.set(channel, channelHandlers)
217
+ }
218
+ channelHandlers.add(handler)
219
+ }
220
+
221
+ async unsubscribe(channel: string): Promise<void> {
222
+ this.handlers.delete(channel)
223
+ }
224
+
225
+ async healthCheck(): Promise<boolean> {
226
+ return !this.closed && this.server !== undefined
227
+ }
228
+
229
+ async close(): Promise<void> {
230
+ this.closed = true
231
+
232
+ // Disconnect all clients
233
+ for (const socket of this.socketChannels.keys()) {
234
+ socket.disconnect(true)
235
+ }
236
+
237
+ this.channelSubscribers.clear()
238
+ this.socketChannels.clear()
239
+ this.handlers.clear()
240
+ }
241
+
242
+ /**
243
+ * Get statistics about current connections (for monitoring)
244
+ */
245
+ getStats(): {
246
+ totalConnections: number
247
+ channelCounts: Record<string, number>
248
+ } {
249
+ const channelCounts: Record<string, number> = {}
250
+ for (const [channel, subscribers] of this.channelSubscribers) {
251
+ channelCounts[channel] = subscribers.size
252
+ }
253
+
254
+ return {
255
+ totalConnections: this.socketChannels.size,
256
+ channelCounts,
257
+ }
258
+ }
259
+ }
@@ -0,0 +1,55 @@
1
+ ---
2
+ to: "<%= generate.commands ? outputPaths.createCommand : '' %>"
3
+ skip_if: <%= !isCleanArchitecture %>
4
+ force: true
5
+ ---
6
+ <% if (outputPaths.createCommand) { -%>
7
+ /**
8
+ * Create <%= className %> Command
9
+ * Generated by entity codegen - do not edit directly
10
+ *
11
+ * EXTENSION POINTS (add business logic here):
12
+ * - Validation: Add domain validation rules before creating
13
+ * - Defaults: Compute default values not handled by DTO
14
+ * - Side effects: Emit events, send notifications, create related entities
15
+ * - Authorization: Check user permissions beyond route-level auth
16
+ * - Audit: Log creation for compliance/debugging
17
+ */
18
+
19
+ import { Inject, Injectable } from '@nestjs/common';
20
+ import { <%= repositoryToken %> } from '<%= imports.constants %>';
21
+ import type { Create<%= className %>Input, I<%= className %>Repository } from '<%= imports.domain %>';
22
+ import { <%= className %> } from '<%= imports.domain %>';
23
+ import type { Create<%= className %>Dto } from '<%= imports.schemas %>';
24
+
25
+ @Injectable()
26
+ export class <%= createCommandClass %> {
27
+ constructor(
28
+ @Inject(<%= repositoryToken %>)
29
+ private readonly <%= camelName %>Repository: I<%= className %>Repository,
30
+ ) {}
31
+
32
+ async execute(dto: Create<%= className %>Dto): Promise<<%= className %>> {
33
+ // TODO: Add pre-create validation and business rules here
34
+
35
+ // Map DTO to domain input
36
+ const input: Create<%= className %>Input = {
37
+ <% fields.forEach((field) => { -%>
38
+ <% if (field.required) { -%>
39
+ <%= field.camelName %>: dto.<%= field.camelName %>,
40
+ <% } else if (field.nullable) { -%>
41
+ <%= field.camelName %>: dto.<%= field.camelName %> ?? null,
42
+ <% } else { -%>
43
+ <%= field.camelName %>: dto.<%= field.camelName %>,
44
+ <% } -%>
45
+ <% }) -%>
46
+ };
47
+
48
+ const created = await this.<%= camelName %>Repository.create(input);
49
+
50
+ // TODO: Add post-create side effects here (events, notifications, etc.)
51
+
52
+ return created;
53
+ }
54
+ }
55
+ <% } -%>
@@ -0,0 +1,45 @@
1
+ ---
2
+ to: "<%= generate.commands ? outputPaths.deleteCommand : '' %>"
3
+ skip_if: <%= !isCleanArchitecture %>
4
+ force: true
5
+ ---
6
+ <% if (outputPaths.deleteCommand) { -%>
7
+ /**
8
+ * Delete <%= className %> Command
9
+ * Generated by entity codegen - do not edit directly
10
+ *
11
+ * EXTENSION POINTS (add business logic here):
12
+ * - Authorization: Check if user can delete this specific record
13
+ * - Referential integrity: Check for dependent records, cascade or block
14
+ * - Soft delete: Mark as deleted instead of hard delete
15
+ * - Side effects: Emit events, clean up related data, notify subscribers
16
+ * - Audit: Log deletion for compliance/debugging
17
+ */
18
+
19
+ import { Inject, Injectable, NotFoundException } from '@nestjs/common';
20
+ import { <%= repositoryToken %> } from '<%= imports.constants %>';
21
+ import type { I<%= className %>Repository } from '<%= imports.domain %>';
22
+ import { <%= className %> } from '<%= imports.domain %>';
23
+
24
+ @Injectable()
25
+ export class <%= deleteCommandClass %> {
26
+ constructor(
27
+ @Inject(<%= repositoryToken %>)
28
+ private readonly <%= camelName %>Repository: I<%= className %>Repository,
29
+ ) {}
30
+
31
+ async execute(id: string): Promise<<%= className %>> {
32
+ // TODO: Add pre-delete validation here
33
+ // e.g., check for dependent records, verify user permissions
34
+
35
+ const deleted = await this.<%= camelName %>Repository.delete(id);
36
+ if (!deleted) {
37
+ throw new NotFoundException(`<%= className %> with id ${id} not found`);
38
+ }
39
+
40
+ // TODO: Add post-delete side effects here (events, cleanup, etc.)
41
+
42
+ return deleted;
43
+ }
44
+ }
45
+ <% } -%>
@@ -0,0 +1,149 @@
1
+ ---
2
+ to: "<%= generate.commands ? outputPaths.commandsGroupedIndex : '' %>"
3
+ skip_if: <%= !isCleanArchitecture %>
4
+ force: true
5
+ ---
6
+ <% if (outputPaths.commandsGroupedIndex) { -%>
7
+ /**
8
+ * <%= className %> Commands Module
9
+ * Generated by entity codegen - do not edit directly
10
+ *
11
+ * This file contains all command classes for <%= className %>
12
+ * using grouped file layout (file_grouping: "grouped")
13
+ */
14
+
15
+ import { Inject, Injectable, NotFoundException } from '@nestjs/common';
16
+ import { <%= repositoryToken %> } from '<%= imports.constants %>';
17
+ import type { Create<%= className %>Input, I<%= className %>Repository, Update<%= className %>Input } from '<%= imports.domain %>';
18
+ import { <%= className %> } from '<%= imports.domain %>';
19
+ import type { Create<%= className %>Dto, Update<%= className %>Dto } from '<%= imports.schemas %>';
20
+
21
+ // ============================================================================
22
+ // Create Command
23
+ // ============================================================================
24
+
25
+ /**
26
+ * Create <%= className %> Command
27
+ *
28
+ * EXTENSION POINTS (add business logic here):
29
+ * - Validation: Add domain validation rules before creating
30
+ * - Defaults: Compute default values not handled by DTO
31
+ * - Side effects: Emit events, send notifications, create related entities
32
+ * - Authorization: Check user permissions beyond route-level auth
33
+ * - Audit: Log creation for compliance/debugging
34
+ */
35
+ @Injectable()
36
+ export class <%= createCommandClass %> {
37
+ constructor(
38
+ @Inject(<%= repositoryToken %>)
39
+ private readonly <%= camelName %>Repository: I<%= className %>Repository,
40
+ ) {}
41
+
42
+ async execute(dto: Create<%= className %>Dto): Promise<<%= className %>> {
43
+ // TODO: Add pre-create validation and business rules here
44
+
45
+ // Map DTO to domain input
46
+ const input: Create<%= className %>Input = {
47
+ <% fields.forEach((field) => { -%>
48
+ <% if (field.required) { -%>
49
+ <%= field.camelName %>: dto.<%= field.camelName %>,
50
+ <% } else if (field.nullable) { -%>
51
+ <%= field.camelName %>: dto.<%= field.camelName %> ?? null,
52
+ <% } else { -%>
53
+ <%= field.camelName %>: dto.<%= field.camelName %>,
54
+ <% } -%>
55
+ <% }) -%>
56
+ };
57
+
58
+ const created = await this.<%= camelName %>Repository.create(input);
59
+
60
+ // TODO: Add post-create side effects here (events, notifications, etc.)
61
+
62
+ return created;
63
+ }
64
+ }
65
+
66
+ // ============================================================================
67
+ // Update Command
68
+ // ============================================================================
69
+
70
+ /**
71
+ * Update <%= className %> Command
72
+ *
73
+ * EXTENSION POINTS (add business logic here):
74
+ * - Validation: Add domain validation rules (e.g., state transitions)
75
+ * - Authorization: Check if user can modify this specific record
76
+ * - Conflict detection: Optimistic locking, version checks
77
+ * - Side effects: Emit events, invalidate caches, notify subscribers
78
+ * - Audit: Log changes for compliance/debugging
79
+ */
80
+ @Injectable()
81
+ export class <%= updateCommandClass %> {
82
+ constructor(
83
+ @Inject(<%= repositoryToken %>)
84
+ private readonly <%= camelName %>Repository: I<%= className %>Repository,
85
+ ) {}
86
+
87
+ async execute(id: string, dto: Update<%= className %>Dto): Promise<<%= className %>> {
88
+ const existing = await this.<%= camelName %>Repository.findById(id);
89
+ if (!existing) {
90
+ throw new NotFoundException(`<%= className %> with id ${id} not found`);
91
+ }
92
+
93
+ // TODO: Add pre-update validation and business rules here
94
+ // e.g., check state transitions, verify user permissions on this record
95
+
96
+ // Map DTO to domain input (only include defined fields)
97
+ const input: Update<%= className %>Input = {
98
+ <% fields.forEach((field) => { -%>
99
+ ...(dto.<%= field.camelName %> !== undefined && { <%= field.camelName %>: dto.<%= field.camelName %> }),
100
+ <% }) -%>
101
+ };
102
+
103
+ const updated = await this.<%= camelName %>Repository.update(id, input);
104
+ if (!updated) {
105
+ throw new NotFoundException(`<%= className %> with id ${id} not found`);
106
+ }
107
+
108
+ // TODO: Add post-update side effects here (events, cache invalidation, etc.)
109
+
110
+ return updated;
111
+ }
112
+ }
113
+
114
+ // ============================================================================
115
+ // Delete Command
116
+ // ============================================================================
117
+
118
+ /**
119
+ * Delete <%= className %> Command
120
+ *
121
+ * EXTENSION POINTS (add business logic here):
122
+ * - Authorization: Check if user can delete this specific record
123
+ * - Referential integrity: Check for dependent records, cascade or block
124
+ * - Soft delete: Mark as deleted instead of hard delete
125
+ * - Side effects: Emit events, clean up related data, notify subscribers
126
+ * - Audit: Log deletion for compliance/debugging
127
+ */
128
+ @Injectable()
129
+ export class <%= deleteCommandClass %> {
130
+ constructor(
131
+ @Inject(<%= repositoryToken %>)
132
+ private readonly <%= camelName %>Repository: I<%= className %>Repository,
133
+ ) {}
134
+
135
+ async execute(id: string): Promise<<%= className %>> {
136
+ // TODO: Add pre-delete validation here
137
+ // e.g., check for dependent records, verify user permissions
138
+
139
+ const deleted = await this.<%= camelName %>Repository.delete(id);
140
+ if (!deleted) {
141
+ throw new NotFoundException(`<%= className %> with id ${id} not found`);
142
+ }
143
+
144
+ // TODO: Add post-delete side effects here (events, cleanup, etc.)
145
+
146
+ return deleted;
147
+ }
148
+ }
149
+ <% } -%>
@@ -0,0 +1,15 @@
1
+ ---
2
+ to: "<%= generate.commands ? outputPaths.commandsIndex : '' %>"
3
+ skip_if: <%= !isCleanArchitecture %>
4
+ force: true
5
+ ---
6
+ <% if (outputPaths.commandsIndex) { -%>
7
+ /**
8
+ * <%= className %> Commands Barrel Export
9
+ * Generated by entity codegen - do not edit directly
10
+ */
11
+
12
+ export * from './<%= fileNames.createCommand.replace('.ts', '') %>';
13
+ export * from './<%= fileNames.updateCommand.replace('.ts', '') %>';
14
+ export * from './<%= fileNames.deleteCommand.replace('.ts', '') %>';
15
+ <% } -%>
@@ -0,0 +1,58 @@
1
+ ---
2
+ to: "<%= generate.commands ? outputPaths.updateCommand : '' %>"
3
+ skip_if: <%= !isCleanArchitecture %>
4
+ force: true
5
+ ---
6
+ <% if (outputPaths.updateCommand) { -%>
7
+ /**
8
+ * Update <%= className %> Command
9
+ * Generated by entity codegen - do not edit directly
10
+ *
11
+ * EXTENSION POINTS (add business logic here):
12
+ * - Validation: Add domain validation rules (e.g., state transitions)
13
+ * - Authorization: Check if user can modify this specific record
14
+ * - Conflict detection: Optimistic locking, version checks
15
+ * - Side effects: Emit events, invalidate caches, notify subscribers
16
+ * - Audit: Log changes for compliance/debugging
17
+ */
18
+
19
+ import { Inject, Injectable, NotFoundException } from '@nestjs/common';
20
+ import { <%= repositoryToken %> } from '<%= imports.constants %>';
21
+ import type { I<%= className %>Repository, Update<%= className %>Input } from '<%= imports.domain %>';
22
+ import { <%= className %> } from '<%= imports.domain %>';
23
+ import type { Update<%= className %>Dto } from '<%= imports.schemas %>';
24
+
25
+ @Injectable()
26
+ export class <%= updateCommandClass %> {
27
+ constructor(
28
+ @Inject(<%= repositoryToken %>)
29
+ private readonly <%= camelName %>Repository: I<%= className %>Repository,
30
+ ) {}
31
+
32
+ async execute(id: string, dto: Update<%= className %>Dto): Promise<<%= className %>> {
33
+ const existing = await this.<%= camelName %>Repository.findById(id);
34
+ if (!existing) {
35
+ throw new NotFoundException(`<%= className %> with id ${id} not found`);
36
+ }
37
+
38
+ // TODO: Add pre-update validation and business rules here
39
+ // e.g., check state transitions, verify user permissions on this record
40
+
41
+ // Map DTO to domain input (only include defined fields)
42
+ const input: Update<%= className %>Input = {
43
+ <% fields.forEach((field) => { -%>
44
+ ...(dto.<%= field.camelName %> !== undefined && { <%= field.camelName %>: dto.<%= field.camelName %> }),
45
+ <% }) -%>
46
+ };
47
+
48
+ const updated = await this.<%= camelName %>Repository.update(id, input);
49
+ if (!updated) {
50
+ throw new NotFoundException(`<%= className %> with id ${id} not found`);
51
+ }
52
+
53
+ // TODO: Add post-update side effects here (events, cache invalidation, etc.)
54
+
55
+ return updated;
56
+ }
57
+ }
58
+ <% } -%>
@@ -0,0 +1,36 @@
1
+ ---
2
+ to: "<%= hasDeclarativeQueries ? `${basePaths.backendSrc}/${paths.queries}/declarative-queries.ts` : '' %>"
3
+ skip_if: <%= !isCleanArchitecture %>
4
+ force: true
5
+ ---
6
+ <% if (hasDeclarativeQueries) { -%>
7
+ /**
8
+ * Declarative Query Classes for <%= className %>
9
+ * Generated from queries: block in entity YAML - do not edit directly
10
+ */
11
+
12
+ import { Inject, Injectable } from '@nestjs/common';
13
+ import { <%= repositoryToken %> } from '<%= imports.constants %>';
14
+ import type { I<%= className %>Repository } from '<%= imports.domain %>';
15
+ import type { <%= className %> } from '<%= imports.domain %>';
16
+
17
+ <% processedQueries.forEach((q) => { -%>
18
+ @Injectable()
19
+ export class <%= q.useCaseClassName %> {
20
+ constructor(
21
+ @Inject(<%= repositoryToken %>)
22
+ private readonly repository: I<%= className %>Repository,
23
+ ) {}
24
+
25
+ async execute(<%- q.params.map(p => `${p.camelName}: ${p.tsType}`).join(', ') %>): Promise<<%- q.returnType %>> {
26
+ return this.repository.<%= q.methodName %>(<%= q.params.map(p => p.camelName).join(', ') %>);
27
+ }
28
+ }
29
+
30
+ <% }) -%>
31
+ export const declarativeQueryClasses = [
32
+ <% processedQueries.forEach((q) => { -%>
33
+ <%= q.useCaseClassName %>,
34
+ <% }) -%>
35
+ ];
36
+ <% } -%>
@@ -0,0 +1,42 @@
1
+ ---
2
+ to: "<%= generate.queries ? outputPaths.getByIdQuery : '' %>"
3
+ skip_if: <%= !isCleanArchitecture %>
4
+ force: true
5
+ ---
6
+ <% if (outputPaths.getByIdQuery) { -%>
7
+ /**
8
+ * Get <%= className %> By ID Query
9
+ * Generated by entity codegen - do not edit directly
10
+ *
11
+ * EXTENSION POINTS (add query logic here):
12
+ * - Authorization: Check if user can access this specific record
13
+ * - Enrichment: Add computed fields or related data
14
+ * - Caching: Add cache layer for frequently accessed records
15
+ */
16
+
17
+ import { Inject, Injectable, NotFoundException } from '@nestjs/common';
18
+ import { <%= repositoryToken %> } from '<%= imports.constants %>';
19
+ import type { I<%= className %>Repository<%= hasRelationships ? `, ${className}With` : '' %> } from '<%= imports.domain %>';
20
+ import { <%= className %> } from '<%= imports.domain %>';
21
+
22
+ @Injectable()
23
+ export class <%= getByIdQueryClass %> {
24
+ constructor(
25
+ @Inject(<%= repositoryToken %>)
26
+ private readonly <%= camelName %>Repository: I<%= className %>Repository,
27
+ ) {}
28
+
29
+ async execute(id: string<%= hasRelationships ? `, include?: ${className}With` : '' %>): Promise<<%= className %>> {
30
+ // TODO: Add authorization check if needed (row-level security)
31
+
32
+ const entity = await this.<%= camelName %>Repository.findById(id<%= hasRelationships ? ', include' : '' %>);
33
+ if (!entity) {
34
+ throw new NotFoundException(`<%= className %> with id ${id} not found`);
35
+ }
36
+
37
+ // TODO: Add enrichment or computed fields if needed
38
+
39
+ return entity;
40
+ }
41
+ }
42
+ <% } -%>