@archi-code/ddd 0.0.0-stage → 3.0.0-alpha.2

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 (336) hide show
  1. package/LICENSE +46 -0
  2. package/README.md +2795 -2
  3. package/SKILL.md +106 -0
  4. package/ddd-skills/archi-code-ddd/imports.md +94 -0
  5. package/ddd-skills/archi-code-ddd/layers.md +314 -0
  6. package/ddd-skills/archi-code-ddd/patterns.md +683 -0
  7. package/ddd-skills/archi-code-ddd/what-not-to-do.md +196 -0
  8. package/ddd-skills/archi-code-ddd/where-each-class-goes.md +64 -0
  9. package/ddd-skills/ddd-agregados/GUIA.md +114 -0
  10. package/ddd-skills/ddd-agregados/references/consistencia-eventual.md +158 -0
  11. package/ddd-skills/ddd-agregados/references/ejemplo-ecommerce.md +52 -0
  12. package/ddd-skills/ddd-agregados/references/fabricas.md +193 -0
  13. package/ddd-skills/ddd-agregados/references/implementacion-ts.md +706 -0
  14. package/ddd-skills/ddd-arquitectura/GUIA.md +80 -0
  15. package/ddd-skills/ddd-arquitectura/assets/dependency-cruiser.cjs +99 -0
  16. package/ddd-skills/ddd-arquitectura/references/estilos-adicionales.md +51 -0
  17. package/ddd-skills/ddd-arquitectura/references/estructura-hexagonal-ts.md +406 -0
  18. package/ddd-skills/ddd-arquitectura/references/modulos.md +48 -0
  19. package/ddd-skills/ddd-auditoria-refactorizacion/GUIA.md +85 -0
  20. package/ddd-skills/ddd-auditoria-refactorizacion/references/ejemplo-auditoria.md +314 -0
  21. package/ddd-skills/ddd-auditoria-refactorizacion/references/lista-comprobacion.md +54 -0
  22. package/ddd-skills/ddd-auditoria-refactorizacion/references/plan-migracion.md +73 -0
  23. package/ddd-skills/ddd-auditoria-refactorizacion/scripts/scan_ddd_smells.py +264 -0
  24. package/ddd-skills/ddd-context-mapping/GUIA.md +83 -0
  25. package/ddd-skills/ddd-context-mapping/references/anticorrupcion-ts.md +419 -0
  26. package/ddd-skills/ddd-context-mapping/references/estilos-integracion.md +152 -0
  27. package/ddd-skills/ddd-event-sourcing-cqrs/GUIA.md +92 -0
  28. package/ddd-skills/ddd-event-sourcing-cqrs/references/event-sourcing-ts.md +476 -0
  29. package/ddd-skills/ddd-event-sourcing-cqrs/references/proyecciones-cqrs-ts.md +285 -0
  30. package/ddd-skills/ddd-eventos-dominio/GUIA.md +106 -0
  31. package/ddd-skills/ddd-eventos-dominio/references/diseno-eventos.md +130 -0
  32. package/ddd-skills/ddd-eventos-dominio/references/ejemplo-ecommerce.md +240 -0
  33. package/ddd-skills/ddd-eventos-dominio/references/publicacion-ts.md +529 -0
  34. package/ddd-skills/ddd-orquestador/GUIA.md +40 -0
  35. package/ddd-skills/ddd-orquestador/references/chuleta-reglas.md +35 -0
  36. package/ddd-skills/ddd-repositorios-persistencia/GUIA.md +121 -0
  37. package/ddd-skills/ddd-repositorios-persistencia/references/implementacion-ts.md +314 -0
  38. package/ddd-skills/ddd-repositorios-persistencia/references/tests-repositorios.md +191 -0
  39. package/ddd-skills/ddd-repositorios-persistencia/references/transacciones-ts.md +301 -0
  40. package/ddd-skills/ddd-servicios-capa-aplicacion/GUIA.md +99 -0
  41. package/ddd-skills/ddd-servicios-capa-aplicacion/references/capa-aplicacion-ts.md +264 -0
  42. package/ddd-skills/ddd-servicios-capa-aplicacion/references/ejemplo-ecommerce.md +321 -0
  43. package/ddd-skills/ddd-servicios-capa-aplicacion/references/servicios-dominio-ts.md +190 -0
  44. package/ddd-skills/ddd-value-objects-entidades/GUIA.md +118 -0
  45. package/ddd-skills/ddd-value-objects-entidades/references/ejemplo-ecommerce.md +87 -0
  46. package/ddd-skills/ddd-value-objects-entidades/references/entidades-ts.md +218 -0
  47. package/ddd-skills/ddd-value-objects-entidades/references/persistencia-valores.md +88 -0
  48. package/ddd-skills/ddd-value-objects-entidades/references/specification-y-diseno-flexible.md +119 -0
  49. package/ddd-skills/ddd-value-objects-entidades/references/validacion.md +96 -0
  50. package/ddd-skills/ddd-value-objects-entidades/references/value-objects-ts.md +376 -0
  51. package/dist/cjs/application/event/event-bus.d.ts +4 -0
  52. package/dist/cjs/application/event/event-bus.js +2 -0
  53. package/dist/cjs/application/event/event-listener.d.ts +4 -0
  54. package/dist/cjs/application/event/event-listener.js +6 -0
  55. package/dist/cjs/application/event/listens-to.d.ts +15 -0
  56. package/dist/cjs/application/event/listens-to.js +28 -0
  57. package/dist/cjs/application/exceptions/aggregate-not-found.exception.d.ts +5 -0
  58. package/dist/cjs/application/exceptions/aggregate-not-found.exception.js +17 -0
  59. package/dist/cjs/application/exceptions/application-exception-code.d.ts +7 -0
  60. package/dist/cjs/application/exceptions/application-exception-code.js +11 -0
  61. package/dist/cjs/application/exceptions/application.exception.d.ts +6 -0
  62. package/dist/cjs/application/exceptions/application.exception.js +16 -0
  63. package/dist/cjs/application/exceptions/concurrency.exception.d.ts +5 -0
  64. package/dist/cjs/application/exceptions/concurrency.exception.js +17 -0
  65. package/dist/cjs/application/exceptions/not-allowed.exception.d.ts +5 -0
  66. package/dist/cjs/application/exceptions/not-allowed.exception.js +17 -0
  67. package/dist/cjs/application/exceptions/unexpected-error.exception.d.ts +5 -0
  68. package/dist/cjs/application/exceptions/unexpected-error.exception.js +17 -0
  69. package/dist/cjs/application/index.d.ts +14 -0
  70. package/dist/cjs/application/index.js +23 -0
  71. package/dist/cjs/application/ports/clock.d.ts +3 -0
  72. package/dist/cjs/application/ports/clock.js +2 -0
  73. package/dist/cjs/application/ports/logger.d.ts +8 -0
  74. package/dist/cjs/application/ports/logger.js +2 -0
  75. package/dist/cjs/application/use-case/use-case.d.ts +6 -0
  76. package/dist/cjs/application/use-case/use-case.js +25 -0
  77. package/dist/cjs/application/value-object-builder/value-object-builder.d.ts +16 -0
  78. package/dist/cjs/application/value-object-builder/value-object-builder.js +51 -0
  79. package/dist/cjs/domain/aggregate/aggregate-root.d.ts +9 -0
  80. package/dist/cjs/domain/aggregate/aggregate-root.js +17 -0
  81. package/dist/cjs/domain/entity/entity.d.ts +9 -0
  82. package/dist/cjs/domain/entity/entity.js +19 -0
  83. package/dist/cjs/domain/event/event-base.d.ts +23 -0
  84. package/dist/cjs/domain/event/event-base.js +21 -0
  85. package/dist/cjs/domain/exceptions/domain-exception-code.d.ts +7 -0
  86. package/dist/cjs/domain/exceptions/domain-exception-code.js +11 -0
  87. package/dist/cjs/domain/exceptions/domain.exception.d.ts +6 -0
  88. package/dist/cjs/domain/exceptions/domain.exception.js +16 -0
  89. package/dist/cjs/domain/exceptions/invalid-event-definition.exception.d.ts +4 -0
  90. package/dist/cjs/domain/exceptions/invalid-event-definition.exception.js +19 -0
  91. package/dist/cjs/domain/exceptions/required-value.exception.d.ts +4 -0
  92. package/dist/cjs/domain/exceptions/required-value.exception.js +20 -0
  93. package/dist/cjs/domain/exceptions/type-primitive.exception.d.ts +4 -0
  94. package/dist/cjs/domain/exceptions/type-primitive.exception.js +20 -0
  95. package/dist/cjs/domain/exceptions/validation.exception.d.ts +14 -0
  96. package/dist/cjs/domain/exceptions/validation.exception.js +23 -0
  97. package/dist/cjs/domain/index.d.ts +17 -0
  98. package/dist/cjs/domain/index.js +36 -0
  99. package/dist/cjs/domain/primitive/primitive-types.d.ts +20 -0
  100. package/dist/cjs/domain/primitive/primitive-types.js +2 -0
  101. package/dist/cjs/domain/repository/aggregate-finder.d.ts +4 -0
  102. package/dist/cjs/domain/repository/aggregate-finder.js +2 -0
  103. package/dist/cjs/domain/repository/aggregate-remover.d.ts +4 -0
  104. package/dist/cjs/domain/repository/aggregate-remover.js +2 -0
  105. package/dist/cjs/domain/repository/aggregate-saver.d.ts +4 -0
  106. package/dist/cjs/domain/repository/aggregate-saver.js +2 -0
  107. package/dist/cjs/domain/specification/specification.d.ts +9 -0
  108. package/dist/cjs/domain/specification/specification.js +44 -0
  109. package/dist/cjs/domain/type/abstract-type.d.ts +18 -0
  110. package/dist/cjs/domain/type/abstract-type.js +61 -0
  111. package/dist/cjs/domain/type/array-type.d.ts +17 -0
  112. package/dist/cjs/domain/type/array-type.js +64 -0
  113. package/dist/cjs/domain/type/boolean-type.d.ts +4 -0
  114. package/dist/cjs/domain/type/boolean-type.js +16 -0
  115. package/dist/cjs/domain/type/composite/composite-brand.d.ts +4 -0
  116. package/dist/cjs/domain/type/composite/composite-brand.js +15 -0
  117. package/dist/cjs/domain/type/composite/composite-field.d.ts +18 -0
  118. package/dist/cjs/domain/type/composite/composite-field.js +86 -0
  119. package/dist/cjs/domain/type/composite/composite-issues.d.ts +6 -0
  120. package/dist/cjs/domain/type/composite/composite-issues.js +35 -0
  121. package/dist/cjs/domain/type/composite/composite.d.ts +26 -0
  122. package/dist/cjs/domain/type/composite/composite.js +51 -0
  123. package/dist/cjs/domain/type/date-type.d.ts +19 -0
  124. package/dist/cjs/domain/type/date-type.js +70 -0
  125. package/dist/cjs/domain/type/enum-type.d.ts +7 -0
  126. package/dist/cjs/domain/type/enum-type.js +30 -0
  127. package/dist/cjs/domain/type/id-type.d.ts +7 -0
  128. package/dist/cjs/domain/type/id-type.js +17 -0
  129. package/dist/cjs/domain/type/index.d.ts +15 -0
  130. package/dist/cjs/domain/type/index.js +29 -0
  131. package/dist/cjs/domain/type/json-type.d.ts +9 -0
  132. package/dist/cjs/domain/type/json-type.js +46 -0
  133. package/dist/cjs/domain/type/number-type.d.ts +4 -0
  134. package/dist/cjs/domain/type/number-type.js +16 -0
  135. package/dist/cjs/domain/type/required/required-mark.d.ts +8 -0
  136. package/dist/cjs/domain/type/required/required-mark.js +13 -0
  137. package/dist/cjs/domain/type/required/required-type.d.ts +7 -0
  138. package/dist/cjs/domain/type/required/required-type.js +21 -0
  139. package/dist/cjs/domain/type/string-type.d.ts +4 -0
  140. package/dist/cjs/domain/type/string-type.js +16 -0
  141. package/dist/cjs/domain/type/uuid-type.d.ts +7 -0
  142. package/dist/cjs/domain/type/uuid-type.js +27 -0
  143. package/dist/cjs/infrastructure/clock/fixed-clock.d.ts +8 -0
  144. package/dist/cjs/infrastructure/clock/fixed-clock.js +19 -0
  145. package/dist/cjs/infrastructure/clock/system-clock.d.ts +4 -0
  146. package/dist/cjs/infrastructure/clock/system-clock.js +9 -0
  147. package/dist/cjs/infrastructure/event/domain-event-bus.d.ts +16 -0
  148. package/dist/cjs/infrastructure/event/domain-event-bus.js +60 -0
  149. package/dist/cjs/infrastructure/event/event-channel.d.ts +9 -0
  150. package/dist/cjs/infrastructure/event/event-channel.js +2 -0
  151. package/dist/cjs/infrastructure/event/event-registry.d.ts +9 -0
  152. package/dist/cjs/infrastructure/event/event-registry.js +43 -0
  153. package/dist/cjs/infrastructure/event/in-memory/emitter.d.ts +11 -0
  154. package/dist/cjs/infrastructure/event/in-memory/emitter.js +54 -0
  155. package/dist/cjs/infrastructure/event/in-memory/in-memory-event-channel.d.ts +16 -0
  156. package/dist/cjs/infrastructure/event/in-memory/in-memory-event-channel.js +50 -0
  157. package/dist/cjs/infrastructure/exceptions/event-delivery.exception.d.ts +5 -0
  158. package/dist/cjs/infrastructure/exceptions/event-delivery.exception.js +20 -0
  159. package/dist/cjs/infrastructure/exceptions/infrastructure-exception-code.d.ts +6 -0
  160. package/dist/cjs/infrastructure/exceptions/infrastructure-exception-code.js +10 -0
  161. package/dist/cjs/infrastructure/exceptions/infrastructure.exception.d.ts +6 -0
  162. package/dist/cjs/infrastructure/exceptions/infrastructure.exception.js +16 -0
  163. package/dist/cjs/infrastructure/exceptions/internal-error.exception.d.ts +5 -0
  164. package/dist/cjs/infrastructure/exceptions/internal-error.exception.js +17 -0
  165. package/dist/cjs/infrastructure/exceptions/kind/exception-classifier.d.ts +4 -0
  166. package/dist/cjs/infrastructure/exceptions/kind/exception-classifier.js +34 -0
  167. package/dist/cjs/infrastructure/exceptions/kind/exception-kind.d.ts +9 -0
  168. package/dist/cjs/infrastructure/exceptions/kind/exception-kind.js +13 -0
  169. package/dist/cjs/infrastructure/exceptions/unknown-event.exception.d.ts +4 -0
  170. package/dist/cjs/infrastructure/exceptions/unknown-event.exception.js +19 -0
  171. package/dist/cjs/infrastructure/index.d.ts +21 -0
  172. package/dist/cjs/infrastructure/index.js +33 -0
  173. package/dist/cjs/infrastructure/logging/console-logger.d.ts +17 -0
  174. package/dist/cjs/infrastructure/logging/console-logger.js +37 -0
  175. package/dist/cjs/infrastructure/logging/in-memory-logger.d.ts +15 -0
  176. package/dist/cjs/infrastructure/logging/in-memory-logger.js +27 -0
  177. package/dist/cjs/infrastructure/logging/log-serializer.d.ts +7 -0
  178. package/dist/cjs/infrastructure/logging/log-serializer.js +59 -0
  179. package/dist/cjs/infrastructure/logging/silent-logger.d.ts +7 -0
  180. package/dist/cjs/infrastructure/logging/silent-logger.js +18 -0
  181. package/dist/cjs/shared/exceptions/abstract.exception.d.ts +25 -0
  182. package/dist/cjs/shared/exceptions/abstract.exception.js +59 -0
  183. package/dist/cjs/shared/exceptions/brand/exception-brand.d.ts +6 -0
  184. package/dist/cjs/shared/exceptions/brand/exception-brand.js +29 -0
  185. package/dist/cjs/shared/exceptions/received/received-value.d.ts +4 -0
  186. package/dist/cjs/shared/exceptions/received/received-value.js +13 -0
  187. package/dist/cjs/shared/index.d.ts +8 -0
  188. package/dist/cjs/shared/index.js +13 -0
  189. package/dist/cjs/shared/issue-collection-error.d.ts +9 -0
  190. package/dist/cjs/shared/issue-collection-error.js +11 -0
  191. package/dist/cjs/shared/issue-collector.d.ts +8 -0
  192. package/dist/cjs/shared/issue-collector.js +41 -0
  193. package/dist/esm/application/event/event-bus.d.ts +4 -0
  194. package/dist/esm/application/event/event-bus.js +1 -0
  195. package/dist/esm/application/event/event-listener.d.ts +4 -0
  196. package/dist/esm/application/event/event-listener.js +2 -0
  197. package/dist/esm/application/event/listens-to.d.ts +15 -0
  198. package/dist/esm/application/event/listens-to.js +25 -0
  199. package/dist/esm/application/exceptions/aggregate-not-found.exception.d.ts +5 -0
  200. package/dist/esm/application/exceptions/aggregate-not-found.exception.js +13 -0
  201. package/dist/esm/application/exceptions/application-exception-code.d.ts +7 -0
  202. package/dist/esm/application/exceptions/application-exception-code.js +8 -0
  203. package/dist/esm/application/exceptions/application.exception.d.ts +6 -0
  204. package/dist/esm/application/exceptions/application.exception.js +12 -0
  205. package/dist/esm/application/exceptions/concurrency.exception.d.ts +5 -0
  206. package/dist/esm/application/exceptions/concurrency.exception.js +13 -0
  207. package/dist/esm/application/exceptions/not-allowed.exception.d.ts +5 -0
  208. package/dist/esm/application/exceptions/not-allowed.exception.js +13 -0
  209. package/dist/esm/application/exceptions/unexpected-error.exception.d.ts +5 -0
  210. package/dist/esm/application/exceptions/unexpected-error.exception.js +13 -0
  211. package/dist/esm/application/index.d.ts +14 -0
  212. package/dist/esm/application/index.js +10 -0
  213. package/dist/esm/application/ports/clock.d.ts +3 -0
  214. package/dist/esm/application/ports/clock.js +1 -0
  215. package/dist/esm/application/ports/logger.d.ts +8 -0
  216. package/dist/esm/application/ports/logger.js +1 -0
  217. package/dist/esm/application/use-case/use-case.d.ts +6 -0
  218. package/dist/esm/application/use-case/use-case.js +21 -0
  219. package/dist/esm/application/value-object-builder/value-object-builder.d.ts +16 -0
  220. package/dist/esm/application/value-object-builder/value-object-builder.js +47 -0
  221. package/dist/esm/domain/aggregate/aggregate-root.d.ts +9 -0
  222. package/dist/esm/domain/aggregate/aggregate-root.js +13 -0
  223. package/dist/esm/domain/entity/entity.d.ts +9 -0
  224. package/dist/esm/domain/entity/entity.js +15 -0
  225. package/dist/esm/domain/event/event-base.d.ts +23 -0
  226. package/dist/esm/domain/event/event-base.js +17 -0
  227. package/dist/esm/domain/exceptions/domain-exception-code.d.ts +7 -0
  228. package/dist/esm/domain/exceptions/domain-exception-code.js +8 -0
  229. package/dist/esm/domain/exceptions/domain.exception.d.ts +6 -0
  230. package/dist/esm/domain/exceptions/domain.exception.js +12 -0
  231. package/dist/esm/domain/exceptions/invalid-event-definition.exception.d.ts +4 -0
  232. package/dist/esm/domain/exceptions/invalid-event-definition.exception.js +15 -0
  233. package/dist/esm/domain/exceptions/required-value.exception.d.ts +4 -0
  234. package/dist/esm/domain/exceptions/required-value.exception.js +16 -0
  235. package/dist/esm/domain/exceptions/type-primitive.exception.d.ts +4 -0
  236. package/dist/esm/domain/exceptions/type-primitive.exception.js +16 -0
  237. package/dist/esm/domain/exceptions/validation.exception.d.ts +14 -0
  238. package/dist/esm/domain/exceptions/validation.exception.js +19 -0
  239. package/dist/esm/domain/index.d.ts +17 -0
  240. package/dist/esm/domain/index.js +12 -0
  241. package/dist/esm/domain/primitive/primitive-types.d.ts +20 -0
  242. package/dist/esm/domain/primitive/primitive-types.js +1 -0
  243. package/dist/esm/domain/repository/aggregate-finder.d.ts +4 -0
  244. package/dist/esm/domain/repository/aggregate-finder.js +1 -0
  245. package/dist/esm/domain/repository/aggregate-remover.d.ts +4 -0
  246. package/dist/esm/domain/repository/aggregate-remover.js +1 -0
  247. package/dist/esm/domain/repository/aggregate-saver.d.ts +4 -0
  248. package/dist/esm/domain/repository/aggregate-saver.js +1 -0
  249. package/dist/esm/domain/specification/specification.d.ts +9 -0
  250. package/dist/esm/domain/specification/specification.js +40 -0
  251. package/dist/esm/domain/type/abstract-type.d.ts +18 -0
  252. package/dist/esm/domain/type/abstract-type.js +57 -0
  253. package/dist/esm/domain/type/array-type.d.ts +17 -0
  254. package/dist/esm/domain/type/array-type.js +60 -0
  255. package/dist/esm/domain/type/boolean-type.d.ts +4 -0
  256. package/dist/esm/domain/type/boolean-type.js +12 -0
  257. package/dist/esm/domain/type/composite/composite-brand.d.ts +4 -0
  258. package/dist/esm/domain/type/composite/composite-brand.js +11 -0
  259. package/dist/esm/domain/type/composite/composite-field.d.ts +18 -0
  260. package/dist/esm/domain/type/composite/composite-field.js +82 -0
  261. package/dist/esm/domain/type/composite/composite-issues.d.ts +6 -0
  262. package/dist/esm/domain/type/composite/composite-issues.js +31 -0
  263. package/dist/esm/domain/type/composite/composite.d.ts +26 -0
  264. package/dist/esm/domain/type/composite/composite.js +48 -0
  265. package/dist/esm/domain/type/date-type.d.ts +19 -0
  266. package/dist/esm/domain/type/date-type.js +64 -0
  267. package/dist/esm/domain/type/enum-type.d.ts +7 -0
  268. package/dist/esm/domain/type/enum-type.js +26 -0
  269. package/dist/esm/domain/type/id-type.d.ts +7 -0
  270. package/dist/esm/domain/type/id-type.js +13 -0
  271. package/dist/esm/domain/type/index.d.ts +15 -0
  272. package/dist/esm/domain/type/index.js +12 -0
  273. package/dist/esm/domain/type/json-type.d.ts +9 -0
  274. package/dist/esm/domain/type/json-type.js +42 -0
  275. package/dist/esm/domain/type/number-type.d.ts +4 -0
  276. package/dist/esm/domain/type/number-type.js +12 -0
  277. package/dist/esm/domain/type/required/required-mark.d.ts +8 -0
  278. package/dist/esm/domain/type/required/required-mark.js +9 -0
  279. package/dist/esm/domain/type/required/required-type.d.ts +7 -0
  280. package/dist/esm/domain/type/required/required-type.js +18 -0
  281. package/dist/esm/domain/type/string-type.d.ts +4 -0
  282. package/dist/esm/domain/type/string-type.js +12 -0
  283. package/dist/esm/domain/type/uuid-type.d.ts +7 -0
  284. package/dist/esm/domain/type/uuid-type.js +23 -0
  285. package/dist/esm/infrastructure/clock/fixed-clock.d.ts +8 -0
  286. package/dist/esm/infrastructure/clock/fixed-clock.js +15 -0
  287. package/dist/esm/infrastructure/clock/system-clock.d.ts +4 -0
  288. package/dist/esm/infrastructure/clock/system-clock.js +5 -0
  289. package/dist/esm/infrastructure/event/domain-event-bus.d.ts +16 -0
  290. package/dist/esm/infrastructure/event/domain-event-bus.js +56 -0
  291. package/dist/esm/infrastructure/event/event-channel.d.ts +9 -0
  292. package/dist/esm/infrastructure/event/event-channel.js +1 -0
  293. package/dist/esm/infrastructure/event/event-registry.d.ts +9 -0
  294. package/dist/esm/infrastructure/event/event-registry.js +39 -0
  295. package/dist/esm/infrastructure/event/in-memory/emitter.d.ts +11 -0
  296. package/dist/esm/infrastructure/event/in-memory/emitter.js +50 -0
  297. package/dist/esm/infrastructure/event/in-memory/in-memory-event-channel.d.ts +16 -0
  298. package/dist/esm/infrastructure/event/in-memory/in-memory-event-channel.js +46 -0
  299. package/dist/esm/infrastructure/exceptions/event-delivery.exception.d.ts +5 -0
  300. package/dist/esm/infrastructure/exceptions/event-delivery.exception.js +16 -0
  301. package/dist/esm/infrastructure/exceptions/infrastructure-exception-code.d.ts +6 -0
  302. package/dist/esm/infrastructure/exceptions/infrastructure-exception-code.js +7 -0
  303. package/dist/esm/infrastructure/exceptions/infrastructure.exception.d.ts +6 -0
  304. package/dist/esm/infrastructure/exceptions/infrastructure.exception.js +12 -0
  305. package/dist/esm/infrastructure/exceptions/internal-error.exception.d.ts +5 -0
  306. package/dist/esm/infrastructure/exceptions/internal-error.exception.js +13 -0
  307. package/dist/esm/infrastructure/exceptions/kind/exception-classifier.d.ts +4 -0
  308. package/dist/esm/infrastructure/exceptions/kind/exception-classifier.js +30 -0
  309. package/dist/esm/infrastructure/exceptions/kind/exception-kind.d.ts +9 -0
  310. package/dist/esm/infrastructure/exceptions/kind/exception-kind.js +10 -0
  311. package/dist/esm/infrastructure/exceptions/unknown-event.exception.d.ts +4 -0
  312. package/dist/esm/infrastructure/exceptions/unknown-event.exception.js +15 -0
  313. package/dist/esm/infrastructure/index.d.ts +21 -0
  314. package/dist/esm/infrastructure/index.js +15 -0
  315. package/dist/esm/infrastructure/logging/console-logger.d.ts +17 -0
  316. package/dist/esm/infrastructure/logging/console-logger.js +33 -0
  317. package/dist/esm/infrastructure/logging/in-memory-logger.d.ts +15 -0
  318. package/dist/esm/infrastructure/logging/in-memory-logger.js +23 -0
  319. package/dist/esm/infrastructure/logging/log-serializer.d.ts +7 -0
  320. package/dist/esm/infrastructure/logging/log-serializer.js +55 -0
  321. package/dist/esm/infrastructure/logging/silent-logger.d.ts +7 -0
  322. package/dist/esm/infrastructure/logging/silent-logger.js +14 -0
  323. package/dist/esm/package.json +3 -0
  324. package/dist/esm/shared/exceptions/abstract.exception.d.ts +25 -0
  325. package/dist/esm/shared/exceptions/abstract.exception.js +55 -0
  326. package/dist/esm/shared/exceptions/brand/exception-brand.d.ts +6 -0
  327. package/dist/esm/shared/exceptions/brand/exception-brand.js +25 -0
  328. package/dist/esm/shared/exceptions/received/received-value.d.ts +4 -0
  329. package/dist/esm/shared/exceptions/received/received-value.js +9 -0
  330. package/dist/esm/shared/index.d.ts +8 -0
  331. package/dist/esm/shared/index.js +5 -0
  332. package/dist/esm/shared/issue-collection-error.d.ts +9 -0
  333. package/dist/esm/shared/issue-collection-error.js +7 -0
  334. package/dist/esm/shared/issue-collector.d.ts +8 -0
  335. package/dist/esm/shared/issue-collector.js +37 -0
  336. package/package.json +95 -4
package/SKILL.md ADDED
@@ -0,0 +1,106 @@
1
+ ---
2
+ name: archi-code-ddd
3
+ description: The single entry point for Domain-Driven Design with @archi-code/ddd. It routes every DDD question to the guide suite shipped in the package (integration between contexts, architecture, value objects and entities, aggregates, domain events, repositories, application services, event sourcing and CQRS, audits) and gives the rules, patterns and common mistakes for TypeScript code with @archi-code/ddd - where each class goes and what it may import, value objects, Composite, Specification, Entity, AggregateRoot, EventBase, repository roles, exceptions, UseCase, the event contract (EventListener, @ListensTo, DomainEventBus, event channels), ports, persistence owned by the repository and ExceptionClassifier. Use it whenever someone applies DDD, designs or reviews a domain model, integrates contexts, writes or changes value objects, aggregates, events, use cases, listeners, repositories or adapters, decides which layer a class belongs to, or whenever the code imports @archi-code/ddd.
4
+ ---
5
+
6
+ # archi-code-ddd
7
+
8
+ `@archi-code/ddd` is archi-code's Domain-Driven Design package for TypeScript, one entry point per
9
+ layer, each with the exceptions of its layer: `@archi-code/ddd/domain` (value objects, `Composite`,
10
+ `Specification`, `Entity`, `AggregateRoot`, `EventBase`, the repository contracts
11
+ `AggregateFinder`, `AggregateSaver`, `AggregateRemover`, and `DomainException`,
12
+ `ValidationException`…), `@archi-code/ddd/application` (`UseCase`, the event contract to listen,
13
+ `EventListener` and `@ListensTo`, and to publish, `EventBus`, the ports `Clock`, `Logger`, and
14
+ `AggregateNotFoundException`, `NotAllowedException`…) and `@archi-code/ddd/infrastructure` (the
15
+ event wiring `DomainEventBus`, `EventRegistry` and the `EventChannel` port, in-memory event
16
+ channel, clocks, loggers, `InternalErrorException`…). `@archi-code/ddd/infrastructure` also has
17
+ `ExceptionClassifier`, which gives every entry point (HTTP, gRPC, queue, CLI) the `ExceptionKind`
18
+ of an error.
19
+
20
+ ## Full API
21
+
22
+ Before using a class, function, option or type that does not appear in this skill, read
23
+ `node_modules/@archi-code/ddd/README.md`: it matches the installed version. Do not assume
24
+ signatures, options or exports. If the package is not installed: `npm install @archi-code/ddd`
25
+ (and `npm install @archi-code/validation` if validations are declared with `@Validations`).
26
+
27
+ If that path does not exist (monorepo with workspaces, pnpm…), locate the package with
28
+ `node -p "require.resolve('@archi-code/ddd/package.json')"` and read the `README.md` in that
29
+ folder.
30
+
31
+ ## The DDD guide suite
32
+
33
+ This is the **only skill to load** for Domain-Driven Design with this package. It brings a suite
34
+ of DDD guides (in Spanish, with the source of each rule: Vernon's _Implementing Domain-Driven
35
+ Design_ and _Domain-Driven Design Distilled_, and _DDD in PHP_) inside the package, in
36
+ `ddd-skills/`; never copy the suite into `.claude/skills/`: read it from the package when this
37
+ skill says so. Locate it as the README: `node_modules/@archi-code/ddd/ddd-skills/`, or the
38
+ `ddd-skills/` folder next to the `package.json` that
39
+ `node -p "require.resolve('@archi-code/ddd/package.json')"` prints (in this monorepo,
40
+ `packages/ddd/ddd-skills/`). Each guide is a folder with a `GUIA.md` (no skill frontmatter), its
41
+ `references/` and, when it has them, `assets/` (tool configuration) and `scripts/`: they are never loaded
42
+ on their own, only read when this skill routes to them. Paths inside the guides (`ddd-skills/ddd-agregados/GUIA.md`) are relative to the package
43
+ folder.
44
+
45
+ How to use it, for every design question or task:
46
+
47
+ 1. **Start at `ddd-skills/ddd-orquestador/GUIA.md`**: it says which guide covers each coding task
48
+ (integration between contexts, architecture, classes, aggregates, events, repositories, use
49
+ cases) and holds the conventions of the suite; read it for every task that is not a quick code
50
+ fix. Its `references/chuleta-reglas.md` has every essential rule with its source.
51
+ 2. **Read the `GUIA.md` of the matching guide** before answering, and the `references/` it points
52
+ to for the case at hand:
53
+
54
+ | Situation | Read `ddd-skills/…/GUIA.md` |
55
+ | ---------------------------------------------------------------------- | ------------------------------- |
56
+ | Unclear request, "where do I start", the essential rules | `ddd-orquestador` |
57
+ | How contexts and external systems relate and integrate, ACL | `ddd-context-mapping` |
58
+ | Folder structure, layers, dependencies, modules, composition root | `ddd-arquitectura` |
59
+ | Value object or entity, ids, primitives, validation, Specification | `ddd-value-objects-entidades` |
60
+ | What goes together, invariants, transactions, concurrency, factories | `ddd-agregados` |
61
+ | Events, messaging, outbox, idempotence, versions | `ddd-eventos-dominio` |
62
+ | Loading and saving aggregates, mappers, transactions, repository tests | `ddd-repositorios-persistencia` |
63
+ | Domain services, use cases, where the logic goes, authorization | `ddd-servicios-capa-aplicacion` |
64
+ | Full history, read models, CQRS, Event Sourcing | `ddd-event-sourcing-cqrs` |
65
+ | Review or migrate existing code | `ddd-auditoria-refactorizacion` |
66
+
67
+ A new project follows the orchestrator's sequence (architecture → aggregates and value objects →
68
+ events → repositories → use cases).
69
+
70
+ 3. **Design with the suite, write the code with this package.** The guides' examples are already
71
+ written with this package's API (the classes of its `src`): copy them as they are, never write
72
+ generic base classes (`ValueObject`, `Entity`, `AggregateRoot`, `DomainEvent`) of your own.
73
+ Every guide but the orchestrator opens with a "Con @archi-code/ddd" box that lists where it
74
+ diverges from the books, marked `[Fuera de los libros: convención de @archi-code/ddd]`. The
75
+ guides are the source of truth: the package departs from them only where that mark says so,
76
+ and then the package rule wins. Any other disagreement between a guide and this package
77
+ (`ddd-skills/archi-code-ddd/` or its code) is a defect of the package: follow the guide.
78
+ 4. **Audits of code built on this package** (`ddd-auditoria-refactorizacion`): apply its checklist
79
+ and also every item of `ddd-skills/archi-code-ddd/what-not-to-do.md`. Its scanner needs Python 3:
80
+ `python3 -I "$(dirname "$(node -p "require.resolve('@archi-code/ddd/package.json')")")/ddd-skills/ddd-auditoria-refactorizacion/scripts/scan_ddd_smells.py" <folder>`.
81
+ It flags a use case that saves two aggregates (`this.orders.save(…)` and `this.invoices.save(…)`
82
+ or `remove(…)`), transactions handled in the domain or the application (they belong to the
83
+ repository), domain code importing `@archi-code/ddd/application` or `/infrastructure`, and
84
+ `new Date()` in domain or application code; its findings are hints to confirm by reading the
85
+ code, and a use case that saves through a helper still needs a manual check. Without Python, apply the checklist by hand. For
86
+ the import direction, use `ddd-skills/ddd-arquitectura/assets/dependency-cruiser.cjs`.
87
+ 5. Keep the suite's conventions: say which rule comes from which book and mark what does not come
88
+ from them.
89
+
90
+ If they are installed in the project, use them together with this one:
91
+
92
+ - `archi-code-validation`: available validators, their options and `@Validations` rules.
93
+
94
+ ## Rules and patterns of this package
95
+
96
+ The rules, patterns and common mistakes of `@archi-code/ddd` live next to the suite, in
97
+ `ddd-skills/archi-code-ddd/` (located like the suite). They are part of this skill: read the file
98
+ that matches the task before writing or reviewing code, and every file when unsure.
99
+
100
+ | Read `ddd-skills/archi-code-ddd/…` | When |
101
+ | ---------------------------------- | ---------------------------------------------------------------------------------------- |
102
+ | `imports.md` | Which entry point exports each class, function and type |
103
+ | `where-each-class-goes.md` | The layer of each class, what it may import, the folder layout and the names |
104
+ | `layers.md` | The rules of value objects, aggregates, events, use cases, listeners, ports and adapters |
105
+ | `patterns.md` | Code to start from: value objects, aggregates, use cases, listeners, repositories, tests |
106
+ | `what-not-to-do.md` | The common mistakes; also the checklist of every audit of code built on this package |
@@ -0,0 +1,94 @@
1
+ # Import
2
+
3
+ Part of the `archi-code-ddd` skill: read it only when that skill routes here.
4
+
5
+ ```ts
6
+ import {
7
+ AbstractType,
8
+ AggregateRoot,
9
+ ArrayType,
10
+ BooleanType,
11
+ Composite,
12
+ CreatedAt,
13
+ DateType,
14
+ DomainException,
15
+ DomainExceptionCode,
16
+ Entity,
17
+ EnumType,
18
+ EventBase,
19
+ IdType,
20
+ InvalidEventDefinitionException,
21
+ JsonType,
22
+ NumberType,
23
+ Required,
24
+ RequiredValueException,
25
+ Specification,
26
+ StringType,
27
+ TypePrimitiveException,
28
+ UpdatedAt,
29
+ UuidType,
30
+ ValidationException,
31
+ } from '@archi-code/ddd/domain';
32
+ import type {
33
+ AggregateFinder,
34
+ AggregateRemover,
35
+ AggregateSaver,
36
+ EntityId,
37
+ EventClass,
38
+ EventMetadata,
39
+ PrimitiveTypes,
40
+ SatisfiedBy,
41
+ SerializedEvent,
42
+ ValidationIssue,
43
+ } from '@archi-code/ddd/domain';
44
+ import {
45
+ AggregateNotFoundException,
46
+ ApplicationException,
47
+ ApplicationExceptionCode,
48
+ ConcurrencyException,
49
+ EventListener,
50
+ ListensTo,
51
+ NotAllowedException,
52
+ UnexpectedErrorException,
53
+ UseCase,
54
+ ValueObjectBuilder,
55
+ } from '@archi-code/ddd/application';
56
+ import type {
57
+ Clock,
58
+ EventBus,
59
+ ListenerSubscription,
60
+ LogContext,
61
+ Logger,
62
+ LogLevel,
63
+ } from '@archi-code/ddd/application';
64
+ import {
65
+ ConsoleLogger,
66
+ DomainEventBus,
67
+ EventRegistry,
68
+ ExceptionClassifier,
69
+ ExceptionKind,
70
+ FixedClock,
71
+ InfrastructureException,
72
+ InfrastructureExceptionCode,
73
+ InMemoryEventChannel,
74
+ InMemoryLogger,
75
+ InternalErrorException,
76
+ SilentLogger,
77
+ SystemClock,
78
+ UnknownEventException,
79
+ } from '@archi-code/ddd/infrastructure';
80
+ import type {
81
+ ChannelHandler,
82
+ ChannelSubscription,
83
+ EventChannel,
84
+ Subscription,
85
+ } from '@archi-code/ddd/infrastructure';
86
+ import { Validations } from '@archi-code/validation';
87
+ ```
88
+
89
+ Each layer exports its own exceptions and its own code enum; there is no `/exceptions` subpath
90
+ and the common base class of the exceptions is internal.
91
+
92
+ ```js
93
+ const { Required, StringType } = require('@archi-code/ddd/domain');
94
+ ```
@@ -0,0 +1,314 @@
1
+ # Domain, application and infrastructure
2
+
3
+ Part of the `archi-code-ddd` skill: read it only when that skill routes here.
4
+
5
+ - Value objects are **optional by default** (`value: T | null`) `[Fuera de los libros: convención
6
+ de @archi-code/ddd]`: the books build every value object with a value and model an optional one
7
+ as a field that may be `null` (`reservation: ReservationId | null`) [IDDD ch. 5 and 6]; both
8
+ forms work here. `Required(XType)` makes them
9
+ required: the constructor demands `T` and, if it receives an empty value (`null` or `undefined`),
10
+ throws `RequiredValueException` with the class name. A blank text is a value: `StringType` keeps
11
+ it and the other types refuse it with `TypePrimitiveException`. `Required(...)` also declares
12
+ the `isRequired` validation. An id is always required (see the aggregate root below).
13
+ - A domain VO is always a named subclass (`class Email extends ...`): the name appears in the error
14
+ messages, and `equals` compares the class too (`BillingCountry('ES')` is not a
15
+ `ShippingCountry('ES')`).
16
+ - **A value object that exists is valid.** The constructor converts (or throws
17
+ `TypePrimitiveException`), checks `Required` (or throws `RequiredValueException`) and runs every
18
+ `@Validations` rule, throwing one `ValidationException` with all the broken rules
19
+ (`errors: [{ field: null, code: 'isEmail', message: '<Class>: <message>' }]`; `code` is the
20
+ validator or custom rule name, or the code of the exception). There is no `assertValid()`;
21
+ `validate()` only re-runs the rules and is always ok on a built VO.
22
+ - **Report every field, never only the first.** In `toCommand`, build the value objects of an
23
+ input with `ValueObjectBuilder.build({ field: () => new X(input.field), … })` from
24
+ `@archi-code/ddd/application` (the domain never uses it): it runs every factory and throws one
25
+ `ValidationException` whose `errors` carry the `field` and `code` of each problem (required
26
+ `DOM004`, conversion `DOM003`, a rule name, or the code of any `DomainException`, such as your
27
+ `ORD003`); `ValueObjectBuilder.buildList(list, (item) => …)` names list items by position
28
+ (`lines.1.quantity`). It returns the command typed field by field. Factories are synchronous (one
29
+ that returns a Promise does not compile and is refused at run time with
30
+ `UnexpectedErrorException`), and an error that is not a `DomainException` is a bug that wins over the
31
+ validation errors already collected.
32
+ - An `ArrayType` receives items that are already valid: it does not collect item errors and lets
33
+ the error of the first invalid item through as the item throws it.
34
+ - **Which layer validates what:** the input adapter checks the shape and format of the request (it
35
+ parses, a field is a string, an empty field or a length for a good user experience [IDDD ch. 4]),
36
+ never a business rule, and that never replaces the value object; value objects check each value (built in
37
+ `toCommand`); the aggregate checks invariants over several values; a domain service checks rules
38
+ over several aggregates; the use case checks authorization. The input of a use case arrives
39
+ unvalidated on purpose: every adapter goes through it.
40
+ - `@Validations` is imported from `@archi-code/validation`; a validator's parameters go in a single
41
+ `properties` object. Subclasses inherit validations, and one with the same name replaces the
42
+ parent's.
43
+ - Values are **immutable**: `_value` is `readonly`; to change a value, build a new VO.
44
+ `ArrayType.withItem/withoutItem` return a new instance; `UpdatedAt` is replaced with
45
+ `UpdatedAt.now()`.
46
+ - `toString()` is a method, `equals(other)` compares class and
47
+ value (dates by instant, arrays and objects by content). Template literals work on VOs;
48
+ `JSON.stringify` does not unwrap them: serialize `value` or the aggregate's `toPrimitives()`.
49
+ - Dates: `DateType` accepts `Date`, ISO dates (`'2024-01-31'`, UTC midnight) and ISO date-times
50
+ **with** a zone (`Z` or offset); a date-time without a zone throws `TypePrimitiveException`.
51
+ `UuidType`/`IdType` store lowercase. New ids: `OrderId.generate()` (an `OrderId`). Every id class
52
+ passes its own name as the brand (`class OrderId extends IdType<'OrderId'> {}`) so the compiler never
53
+ takes a `CustomerId` for an `OrderId`.
54
+ - Time: pass a `Clock` to `CreatedAt.now(clock)` / `UpdatedAt.now(clock)` and to events
55
+ (`new OrderPlaced(id, …, { clock })`) from use cases; tests use `FixedClock`. Aggregate methods
56
+ type it as `clock: { now(): Date }`: the `Clock` port matches it, and the domain never imports
57
+ `/application`.
58
+ - A custom type extends `AbstractType<T>` and implements only `protected filter(value: unknown): T`
59
+ (it receives input already known to be non-empty; it returns the value or throws
60
+ `TypePrimitiveException`). If restricting an existing type is enough, extend it and use
61
+ `@Validations`; to normalize the value (trim, lower case) override `filter` and call
62
+ `super.filter(value)` first: `IdType` does the same, and the rules run on the normalized value.
63
+ - **Concepts of several attributes are composite value objects**, not entities nor loose fields:
64
+ `class Money extends Composite({ amount: Cents, currency: Currency }) {}`. The schema names each
65
+ field's class: a value object class, another composite, or a list `[OrderLine]`. Fields are
66
+ exposed read-only with their value object type; the instance is frozen; `equals` compares class
67
+ and every field; `toPrimitives()` gives plain data (dates stay `Date`); `JSON.stringify` writes
68
+ the values; `X.fromPrimitives(data)` rebuilds it reporting every invalid field with its path
69
+ (`lines.1.quantity`). Rules over several fields (end ≥ start, one currency) are `@Validations`
70
+ `custom` rules on the composite class: `fn` receives the built composite, after its fields are
71
+ valid. Behavior returns new instances (`add(other): Money`). Prefer a composite over a child
72
+ entity: an order line with no id anybody looks it up by is a value [IDDD ch. 6]. A collection
73
+ with rules of its own (`OrderLines`: not empty, unique SKU, `total()`) is a composite with a list
74
+ field (`Composite({ items: [OrderLine] })`); `ArrayType` holds only simple value objects. A field
75
+ of a composite may hold an optional value object whose value is `null` (`new Line2(null)`); only
76
+ a missing instance is refused.
77
+ - The aggregate root passes the id to `super(id)`, exposed as `readonly id`; do not redeclare it
78
+ (no `_id` + getter). `equals` compares class and id only. The id is a required value object
79
+ (`EntityId`: `IdType` or a `Required(...)` type); an optional type does not compile as `Id`, and an
80
+ id that holds no value throws `RequiredValueException`, so two new entities are never equal by an
81
+ empty id [IDDD ch. 5]. A child entity (a part with an identity
82
+ of its own inside the aggregate) extends `Entity<Id>` (`super(id)`, `equals` by class and id)
83
+ and holds its id and value objects; it may have business methods named after the language
84
+ (`seat.relabel(label)`) with the rules of that part, never setters, and only its root calls them
85
+ (Tell, Don't Ask: `room.relabelSeat(id, label)` finds the seat and tells it) [IDDD ch. 5 and
86
+ 10]; rules over several parts stay in the root. Its identity is local: unique only inside its
87
+ aggregate, never used from outside [IDDD ch. 10] (`class SeatNumber extends Required(NumberType)`). `AggregateRoot` extends `Entity` too.
88
+ - **Derived values are methods, never getters** (`total()`, `isEditable()`), on aggregates, child
89
+ entities and composites: `PrimitiveTypes` sees every getter as a field, so a computed getter
90
+ breaks `toPrimitives()` at compile time.
91
+ - **A named business rule that selects, validates or combines is a `Specification<T>`**:
92
+ `class EligibleForExpressShipping extends Specification<Order> { isSatisfiedBy(order) {…} }`,
93
+ combined with `and`, `or` and `not`; `and`/`or` accept any `SatisfiedBy<T>` (an object with
94
+ `isSatisfiedBy`), the books' `Specification` interface [IDDD ch. 5]. It receives data already loaded (never a repository) and is
95
+ never used to protect an invariant of an aggregate: invariants stay inside the aggregate.
96
+ - **The domain knows nothing about persistence**: no mapper, repository nor storage concern in
97
+ domain code; a repository receives an aggregate and stores it, calling the aggregate's own
98
+ `toPrimitives()` / `fromPrimitives()`.
99
+ - **Aggregates and their primitives** (every aggregate follows these six rules so infrastructure can
100
+ store it; rules 1, 2, 4 and 5, and the name `fromPrimitives` of rule 3, are package conventions, `[Fuera de los libros: convención de
101
+ @archi-code/ddd]`: the books allow a primitive without behavior [IDDD ch. 6], getters only where
102
+ needed [Destilado ch. 5] and a mapper in infrastructure [IDDD ch. 6]):
103
+ 1. All its state is value objects: each persisted field is a value object, a composite, a list
104
+ of them or a child entity (`extends Entity<Id>`) whose fields are value objects. A flag is
105
+ `class Shipped extends Required(BooleanType) {}`, never `boolean`; a moment is `DateType` /
106
+ `CreatedAt`, never `Date`.
107
+ 2. Private field + public getter with the same name without `_` (or a public `readonly`). No
108
+ private state without its getter: the primitives use those names.
109
+ 3. Private constructor and two factories: a business one that validates and records events, and
110
+ `static fromPrimitives(primitives: PrimitiveTypes<Order>)` that rebuilds each value object
111
+ from its primitive and records nothing.
112
+ 4. `toPrimitives(): PrimitiveTypes<Order>` returns only plain data (`vo.value`, child primitives),
113
+ never a value object.
114
+ 5. Repositories only call `order.toPrimitives()` and `Order.fromPrimitives(row)`; they never
115
+ read the aggregate's fields. There is no mapper.
116
+ 6. One round-trip test per aggregate: `Order.fromPrimitives(order.toPrimitives()).toPrimitives()`
117
+ equals `order.toPrimitives()`.
118
+ The compiler rejects public raw state (`PrimitiveTypes` gives `never`); nothing checks private
119
+ state at run time: a private field left out of `toPrimitives()` compiles and is lost when
120
+ saving, so rule 2 and the round-trip test of rule 6 are the aggregate's responsibility. An enum value object stores its option (`PrimitiveType` is the enum type),
121
+ so `new OrderStatus(primitives.status)` needs no cast.
122
+ - Aggregates extend `AggregateRoot<Id, Event>` and call `super(id)`. The aggregate carries **no
123
+ version**: it never declares, stores nor maps one; optimistic concurrency is the repository's.
124
+ - **Every repository checks the version** (contract): it remembers the version of each aggregate
125
+ object it loaded or saved in a private `WeakMap<Order, number>` (`versions`); load with
126
+ `Order.fromPrimitives(row)` and `versions.set(order, row.version)`; on save take
127
+ `versions.get(order) ?? 0`, save a new aggregate (`0`) as version 1 and treat an existing id as a
128
+ conflict; save an existing one only where the stored version still equals the remembered one,
129
+ storing one more next to (never inside) the primitives; when nothing was written throw
130
+ `ConcurrencyException('Order', id, version)` (`ExceptionKind.Conflict`); after a write
131
+ remember `version + 1`. Keep the driver error: `ConcurrencyException(…, { cause })`.
132
+ Removing is a change too: `remove(aggregate)` receives the loaded aggregate and deletes only
133
+ where the stored version still equals the remembered one, or throws `ConcurrencyException`
134
+ (someone changed or removed it after it was loaded) [IDDD ch. 10].
135
+ After a conflict, the use case may repeat its own work when the command is safe against the new
136
+ state [IDDD ch. 10; IDDD appendix A]: a loop in `handle` where each attempt loads the aggregate
137
+ again and saves it again (a few attempts, then rethrow); otherwise the conflict reaches the user
138
+ (409). A use case run by a listener does not retry by itself: the channel's redelivery tries
139
+ again.
140
+ - `record(event)` is `protected` and keeps the event as it is (facts never change [IDDD ch. 8]: the
141
+ event declares its fields `readonly`); `pullDomainEvents()` returns the events (typed `Event[]`) in order
142
+ and empties the list. Pull them after persisting, to publish. `DomainEventBus.publish` only sends a
143
+ plain copy of each event (`{ ...event }`) to the channel.
144
+ - Events extend `EventBase`, declare `static readonly eventName` with their class name, a fact in
145
+ the past tense (`'OrderPlaced'`) [IDDD ch. 8] (a published contract is named
146
+ `<context>.<module>.<Event>`, `sales.order.OrderPlaced` [IDDD ch. 13]) and
147
+ call `super(metadata)`; the base copies the name into the event's `eventName` field. An event
148
+ is plain data with no methods. The id of the aggregate is a field the event declares like any
149
+ other (`readonly orderId: string`). Rule (not checked at run time): each event declares as
150
+ `readonly` constructor fields only the primitive data it needs (text, finite numbers, booleans,
151
+ `null`, lists and plain objects of them), taken from value objects (`id.value`,
152
+ `customer.value`, money as `{ amount, currency }`, dates as ISO text): never value objects,
153
+ `Date`s, `toPrimitives()` nor personal data nobody needs. Listeners and registries refer to
154
+ the event by its class (`@ListensTo(OrderPlaced, { consumer: 'reserve-stock-on-order-placed' })`, `register(OrderPlaced, …)`). The
155
+ base sets `eventId` (UUID v4) and `occurredOn` (ISO text in UTC, from `metadata.clock` when
156
+ given, otherwise the system time); pass `{ eventId, occurredOn }` only when rebuilding an event
157
+ a channel delivered. Inside an aggregate method, always pass the clock it received:
158
+ `new OrderPlaced(id.value, customer.value, { clock })`. The event is its own JSON:
159
+ `{ ...event }` / `JSON.stringify(event)` give `eventName`, `eventId`, `occurredOn` and the
160
+ fields, in that order.
161
+ - `PrimitiveTypes<T>` only sees **public** non-method members (it strips the leading `_`): expose
162
+ VOs with public getters or public `readonly` properties. For an aggregate it includes `id`;
163
+ child entities become their primitives; raw `string`/`number`/`boolean`/`Date`
164
+ members become `never`.
165
+ - Where to throw each exception:
166
+ - Domain (aggregates, VOs, business rules): `DomainException` or a custom subclass with its own
167
+ code; `ValidationException` (thrown by value objects and `ValueObjectBuilder.build`).
168
+ - Use cases: `AggregateNotFoundException` when a repository returns `null` (except a use case
169
+ run by a listener to register a fact: it returns, so the listener is not retried forever),
170
+ `NotAllowedException` when the requester may not run the action (authorization belongs to the
171
+ use case), `ApplicationException` for other application errors.
172
+ - Adapters (DB, network…): `InfrastructureException` / `InternalErrorException`, always with
173
+ `{ cause: error }` when wrapping another error.
174
+ - `TypePrimitiveException` and `RequiredValueException` are thrown by the VOs; throw them yourself
175
+ only inside the `filter` of a custom type.
176
+ - The package speaks no protocol: each entry point (HTTP, gRPC, queue consumer, CLI) translates
177
+ errors itself from `ExceptionClassifier.classify(error)` (`/infrastructure`), which returns the
178
+ `ExceptionKind`: `Malformed` for a conversion or required error thrown alone (a value object
179
+ built with `new` outside `ValueObjectBuilder.build`; inside it they become a `ValidationException` with
180
+ `DOM003`/`DOM004` in `errors`), `NotAllowed` for `NotAllowedException`, `NotFound` for
181
+ `AggregateNotFoundException`, `Conflict` for `ConcurrencyException`, `Invalid` for
182
+ `ValidationException` and any other `DomainException` (a broken business rule), `Rejected` for
183
+ any other `ApplicationException`, `Internal` for `UnexpectedErrorException`,
184
+ `InvalidEventDefinitionException` and anything else. The entry point maps the kind to its
185
+ protocol (HTTP: 400, 403, 404, 409, 422, 400, 500), handles your own codes with `error.code`,
186
+ returns the `errors` of a `ValidationException`, never sends the message of an `Internal`
187
+ failure and logs it once; never classify exceptions with hand-written `instanceof` chains. For logs or messages use `error.code` and the code enum of each layer
188
+ (`DomainExceptionCode`, `ApplicationExceptionCode`, `InfrastructureExceptionCode`), or
189
+ `instanceof`: the built-in exceptions are recognized across the CJS and ESM builds.
190
+ - A use case does **one thing**: one business action, one class, one `handle`. It changes one
191
+ aggregate and saves it once [Destilado ch. 5; IDDD ch. 10] (the exceptions IDDD ch. 10 accepts, such
192
+ as creating several aggregates in one batch that changes nothing semantically, are written down
193
+ as an explicit decision); a flow that needs several actions is several use cases (chained by
194
+ domain events or called one after another by whoever orchestrates them), never one use case with
195
+ flags or a `type` field in its input that switch between behaviors.
196
+ - A use case is **named after the business action**, a verb and a noun from the ubiquitous language
197
+ that a domain expert would say: `PlaceOrder`, `ShipOrder`, `CancelSubscription`,
198
+ `RegisterUser`, `ApproveRefund`. Never technical or CRUD names (`CreateOrder` when the business
199
+ says "place", `UpdateOrder`, `SaveUser`, `OrderService`, `OrderManager`, `ProcessOrder`,
200
+ `HandleData`, `OrderUseCase`).
201
+ - The repository contracts belong to the domain
202
+ (`import type { AggregateSaver } from '@archi-code/ddd/domain'`). Interface segregation: a use case depends only on the repository roles it uses —
203
+ `AggregateFinder<A>` (`findById`), `AggregateSaver<A>` (`save`), `AggregateRemover<A>`
204
+ (`remove`), combined with `&` when it needs several. There is no all-in-one `Repository` port:
205
+ an adapter implements each role it supports.
206
+ - Use cases extend `UseCase<Input, Command, Output>`, receive ports by constructor
207
+ (`AggregateSaver<Order>`, `EventBus<OrderEvent>`, `Clock`) and are called
208
+ with `execute(input)`.
209
+ They implement two steps: `protected toCommand(input)` builds the value objects with
210
+ `ValueObjectBuilder.build` and returns the command (a small interface of value objects, or one value
211
+ object built with `new`); `protected handle(command)` works only with value objects. `UseCase` has no helpers:
212
+ write every step in `handle` (load with `findById` and throw `AggregateNotFoundException` when it
213
+ is `null` — or return, in a use case a listener runs —, change the aggregate, `save`, then
214
+ `publish(aggregate.pullDomainEvents())`); it never opens a transaction. Let errors
215
+ propagate: `execute` keeps package exceptions and wraps any other error (also from `toCommand`)
216
+ in `UnexpectedErrorException` with `cause`.
217
+ - A use case never imports nor calls another use case, and **returns an id, a DTO or nothing**,
218
+ never an aggregate. Screens that read several aggregates use read queries, not repositories.
219
+ - **Authorization belongs to the use case**: the entry point takes the requester id from the token
220
+ and puts it in the input, `toCommand` builds it as a value object, and an application policy
221
+ (`SalesAccessPolicy`) throws `NotAllowedException`. A rule that is business (only the owner may
222
+ change the order) stays in the aggregate.
223
+ - **Domain services** are plain classes in `domain/` (no base class) named after the business
224
+ operation; they receive aggregates and loaded data, and may read other aggregates through an
225
+ `AggregateFinder` to validate or calculate over several of them [IDDD ch. 5 and 7]; they never
226
+ save, open transactions nor publish. A
227
+ technical one (`ExchangeRates`) is an interface in `domain/` implemented in infrastructure.
228
+ - **Repositories only get and persist** (`findById`, `save`, `remove`): no business logic, no
229
+ business queries (`pendingOlderThan`), no `nextId()`; new ids come from the value object
230
+ (`OrderId.generate()`). A `findAll()` exists only in the in-memory repository of the tests, if
231
+ they need it (`[Fuera de los libros: convención de @archi-code/ddd]`; a real repository has no
232
+ `findAll()`).
233
+ - **One repository per aggregate and technology** (user rule): it implements the roles it supports,
234
+ knows the aggregate it rebuilds, and its constructor receives only its technology (a collection,
235
+ a pool), never an aggregate class nor a mapper; aggregates only go in and out through its
236
+ methods. The aggregate converts itself (`toPrimitives()` / `static fromPrimitives()`), never a
237
+ domain service nor a mapper; the repository calls those methods directly
238
+ (`Order.fromPrimitives(row)` on load, `order.toPrimitives()` on save, with the version it keeps
239
+ in its own `WeakMap`, `ConcurrencyException('Order', …)` on a conflict) and maps the primitives
240
+ to its storage.
241
+ The package ships no repository: the in-memory one is written in the project's `test/support/`.
242
+ - **Another aggregate is referenced by its id** (`customerId: CustomerId`), never by the object.
243
+ - **A command can be refused, a fact cannot**: a method that registers something that already
244
+ happened elsewhere (`registerStockReservation`, called by a listener) is idempotent and never
245
+ throws a business error; if the fact does not fit, it records an event so another listener
246
+ compensates.
247
+ - **Money is a composite with whole minor units** (`Money({ amount: Cents, currency })`, `Cents` a
248
+ `Required(NumberType)` with `isInt`), never a decimal amount; it is exact up to
249
+ `Number.MAX_SAFE_INTEGER` cents (the books use `bigint`, `[Fuera de los libros: convención de
250
+ @archi-code/ddd]`); rounding is explicit.
251
+ - **The repository owns the transaction and everything about persistence** (`[Fuera de los
252
+ libros: convención de @archi-code/ddd]`; IDDD ch. 14 gives it to the application service): there
253
+ is no transaction port, and neither the domain nor the application opens, joins or closes a
254
+ transaction. Each `save`/`remove` is atomic: one document per aggregate is one write; an
255
+ aggregate over several tables is written in a database transaction the repository opens and
256
+ commits inside `save`. The repository also checks the version, manages connections and sessions
257
+ and wraps driver errors. When events must not be lost between `save` and `publish` [Destilado
258
+ ch. 6; IDDD ch. 8], the repository stores them in the same atomic write (an outbox) and a relay
259
+ delivers them through an `EventChannel`: use cases do not change.
260
+ - **Events carry no schema version.** Adding an optional field old readers can ignore is
261
+ compatible; a change they cannot follow is a new event with its own `eventName`
262
+ (`CustomerRenamedV2`), or the `EventRegistry` factory reads both shapes from the stored JSON
263
+ (`typeof json.name === 'string' ? … : …`).
264
+ - **The application holds only the event contract, in `application/event`**: to publish, the
265
+ port `EventBus` (`publish`, the only thing use cases see); to listen, `EventListener` and
266
+ `@ListensTo` (`ListensTo.subscriptionOf(listener)` → `{ eventName, consumer }`). What moves the
267
+ events is infrastructure, used only by the wiring (composition root), and is imported from
268
+ `@archi-code/ddd/infrastructure`: `DomainEventBus(channel, registry)` (implements `EventBus`;
269
+ `subscribe(listener)` → `Subscription { unsubscribe() }`, both async), `EventRegistry` and the
270
+ port `EventChannel` (`send(serialized)`, `receive(eventName, consumer, handler)` →
271
+ `ChannelSubscription { close() }`, with `ChannelHandler`). A messaging technology implements only
272
+ `EventChannel` (`InMemoryEventChannel` in the package; RabbitMQ, a table or Kafka in your
273
+ infrastructure); swapping it changes one line of the wiring.
274
+ - **Consumers are idempotent**: delivery is at least once, so a listener ignores an `eventId` it
275
+ already processed. Listeners always receive the event rebuilt from its JSON (equal field
276
+ by field), also in memory, so nothing changes when the channel does.
277
+ - **Other contexts never receive domain classes**: translate the serialized event to a published,
278
+ versioned contract (`sales.order.OrderPlaced`, only what consumers need, `messageId` = `eventId`)
279
+ in the adapter that talks to the broker [IDDD ch. 13]; expose a new contract version next to the
280
+ old one while consumers move.
281
+ - Event Sourcing and CQRS are optional, only for a concrete need (full history, read models very
282
+ different from the model); read queries straight to the database come first. A projection is
283
+ an `EventListener` that writes a read table and skips an `eventId` it already applied; a read query is an application
284
+ interface implemented in infrastructure that returns DTOs or ids.
285
+ - Logging goes through the `Logger` port of `/application` (`debug`, `info`, `warn`, `error`,
286
+ each `(message, context?)`): the message is a stable snake_case name (`order_shipped`) and the
287
+ data goes in the context. Use cases, listeners and adapters that need it receive it by
288
+ constructor; the domain never logs (it records events or throws). The composition root picks the
289
+ provider: `ConsoleLogger({ level })` (one JSON line per entry), an adapter over pino or winston,
290
+ `InMemoryLogger` in tests (`entries`), `SilentLogger` by default. Pass it to
291
+ `new DomainEventBus(channel, registry, logger)` (listener failures, subscriptions, what was
292
+ published) and to the entry points, which log an `Internal` failure as `error`:
293
+ each error is logged once, where it is handled, never logged and rethrown in every layer.
294
+ - Tests use the project's `InMemoryOrderRepository` (in `test/support/`) and
295
+ `new DomainEventBus(new InMemoryEventChannel(), registry)` (`channel.sent` lists
296
+ what was published; `{ delivery: 'parallel' }` runs the listeners of an event together).
297
+ - Listeners extend `EventListener<Event>`, are decorated with `@ListensTo(EventClass, { consumer })`
298
+ (one event per listener, any number of listeners per event; `consumer` is a stable name, unique
299
+ per listener, that the channel uses as its identity, such as its queue; never derived from the
300
+ class name, which a minifier changes), receive the one use case they run by
301
+ constructor and their `handle(event)` only maps the event to that use case's input.
302
+ - The bus is built and connected in the composition root:
303
+ `const bus = new DomainEventBus(channel, registry)`, then `await bus.subscribe(listener)` for
304
+ each listener; `subscribe` refuses a listener without `@ListensTo` and an event the registry
305
+ cannot rebuild. The use cases only receive `EventBus`.
306
+ - A real repository implements the roles it supports (`AggregateFinder<A>`, `AggregateSaver<A>`,
307
+ `AggregateRemover<A>`) and wraps driver errors in `InternalErrorException` with `cause`.
308
+ The in-memory repository of the tests (`InMemoryOrderRepository`, see `patterns.md`) stores copies
309
+ of the primitives with their version and follows the same concurrency contract.
310
+ - `DomainEventBus` rebuilds events with `EventRegistry`: register a factory per
311
+ event class that passes the JSON as metadata
312
+ (`register(OrderPlaced, (json) => new OrderPlaced(json.orderId as string, …, json))`); `fromJSON`
313
+ throws `InternalErrorException` when the rebuilt event lost its `eventId` or `occurredOn`, which
314
+ listeners need to skip a redelivery.