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

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 (312) hide show
  1. package/LICENSE +46 -0
  2. package/README.md +2693 -2
  3. package/SKILL.md +104 -0
  4. package/ddd-skills/archi-code-ddd/imports.md +84 -0
  5. package/ddd-skills/archi-code-ddd/layers.md +299 -0
  6. package/ddd-skills/archi-code-ddd/patterns.md +676 -0
  7. package/ddd-skills/archi-code-ddd/what-not-to-do.md +189 -0
  8. package/ddd-skills/archi-code-ddd/where-each-class-goes.md +63 -0
  9. package/ddd-skills/ddd-agregados/GUIA.md +114 -0
  10. package/ddd-skills/ddd-agregados/references/consistencia-eventual.md +159 -0
  11. package/ddd-skills/ddd-agregados/references/ejemplo-ecommerce.md +52 -0
  12. package/ddd-skills/ddd-agregados/references/fabricas.md +196 -0
  13. package/ddd-skills/ddd-agregados/references/implementacion-ts.md +711 -0
  14. package/ddd-skills/ddd-arquitectura/GUIA.md +80 -0
  15. package/ddd-skills/ddd-arquitectura/assets/dependency-cruiser.cjs +92 -0
  16. package/ddd-skills/ddd-arquitectura/references/estilos-adicionales.md +51 -0
  17. package/ddd-skills/ddd-arquitectura/references/estructura-hexagonal-ts.md +352 -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 +316 -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 +404 -0
  26. package/ddd-skills/ddd-context-mapping/references/estilos-integracion.md +155 -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 +471 -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 +131 -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 +526 -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 +296 -0
  38. package/ddd-skills/ddd-repositorios-persistencia/references/tests-repositorios.md +177 -0
  39. package/ddd-skills/ddd-repositorios-persistencia/references/transacciones-ts.md +294 -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 +324 -0
  43. package/ddd-skills/ddd-servicios-capa-aplicacion/references/servicios-dominio-ts.md +191 -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 +220 -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 +377 -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/index.d.ts +7 -0
  58. package/dist/cjs/application/index.js +9 -0
  59. package/dist/cjs/application/ports/clock.d.ts +3 -0
  60. package/dist/cjs/application/ports/clock.js +2 -0
  61. package/dist/cjs/application/ports/logger.d.ts +8 -0
  62. package/dist/cjs/application/ports/logger.js +2 -0
  63. package/dist/cjs/application/use-case/use-case.d.ts +6 -0
  64. package/dist/cjs/application/use-case/use-case.js +24 -0
  65. package/dist/cjs/domain/aggregate/aggregate-root.d.ts +14 -0
  66. package/dist/cjs/domain/aggregate/aggregate-root.js +33 -0
  67. package/dist/cjs/domain/entity/entity.d.ts +9 -0
  68. package/dist/cjs/domain/entity/entity.js +19 -0
  69. package/dist/cjs/domain/event/event-base.d.ts +29 -0
  70. package/dist/cjs/domain/event/event-base.js +51 -0
  71. package/dist/cjs/domain/index.d.ts +10 -0
  72. package/dist/cjs/domain/index.js +24 -0
  73. package/dist/cjs/domain/primitive/primitive-types.d.ts +22 -0
  74. package/dist/cjs/domain/primitive/primitive-types.js +2 -0
  75. package/dist/cjs/domain/repository/aggregate-finder.d.ts +4 -0
  76. package/dist/cjs/domain/repository/aggregate-finder.js +2 -0
  77. package/dist/cjs/domain/repository/aggregate-remover.d.ts +4 -0
  78. package/dist/cjs/domain/repository/aggregate-remover.js +2 -0
  79. package/dist/cjs/domain/repository/aggregate-saver.d.ts +4 -0
  80. package/dist/cjs/domain/repository/aggregate-saver.js +2 -0
  81. package/dist/cjs/domain/specification/specification.d.ts +9 -0
  82. package/dist/cjs/domain/specification/specification.js +44 -0
  83. package/dist/cjs/domain/type/abstract-type.d.ts +20 -0
  84. package/dist/cjs/domain/type/abstract-type.js +69 -0
  85. package/dist/cjs/domain/type/array-type.d.ts +16 -0
  86. package/dist/cjs/domain/type/array-type.js +65 -0
  87. package/dist/cjs/domain/type/boolean-type.d.ts +4 -0
  88. package/dist/cjs/domain/type/boolean-type.js +16 -0
  89. package/dist/cjs/domain/type/composite/composite-field.d.ts +19 -0
  90. package/dist/cjs/domain/type/composite/composite-field.js +63 -0
  91. package/dist/cjs/domain/type/composite/composite.d.ts +26 -0
  92. package/dist/cjs/domain/type/composite/composite.js +55 -0
  93. package/dist/cjs/domain/type/date-type.d.ts +18 -0
  94. package/dist/cjs/domain/type/date-type.js +35 -0
  95. package/dist/cjs/domain/type/enum-type.d.ts +7 -0
  96. package/dist/cjs/domain/type/enum-type.js +30 -0
  97. package/dist/cjs/domain/type/equality/value-equality.d.ts +7 -0
  98. package/dist/cjs/domain/type/equality/value-equality.js +41 -0
  99. package/dist/cjs/domain/type/id-type.d.ts +7 -0
  100. package/dist/cjs/domain/type/id-type.js +17 -0
  101. package/dist/cjs/domain/type/immutable/immutable-date.d.ts +4 -0
  102. package/dist/cjs/domain/type/immutable/immutable-date.js +37 -0
  103. package/dist/cjs/domain/type/immutable/immutable.d.ts +4 -0
  104. package/dist/cjs/domain/type/immutable/immutable.js +19 -0
  105. package/dist/cjs/domain/type/index.d.ts +17 -0
  106. package/dist/cjs/domain/type/index.js +33 -0
  107. package/dist/cjs/domain/type/json-type.d.ts +5 -0
  108. package/dist/cjs/domain/type/json-type.js +17 -0
  109. package/dist/cjs/domain/type/number-type.d.ts +4 -0
  110. package/dist/cjs/domain/type/number-type.js +16 -0
  111. package/dist/cjs/domain/type/required/required-mark.d.ts +9 -0
  112. package/dist/cjs/domain/type/required/required-mark.js +13 -0
  113. package/dist/cjs/domain/type/required/required.d.ts +7 -0
  114. package/dist/cjs/domain/type/required/required.js +21 -0
  115. package/dist/cjs/domain/type/string-type.d.ts +4 -0
  116. package/dist/cjs/domain/type/string-type.js +16 -0
  117. package/dist/cjs/domain/type/uuid-type.d.ts +7 -0
  118. package/dist/cjs/domain/type/uuid-type.js +27 -0
  119. package/dist/cjs/domain/type/value-objects/value-objects.d.ts +16 -0
  120. package/dist/cjs/domain/type/value-objects/value-objects.js +70 -0
  121. package/dist/cjs/exceptions/abstract.exception.d.ts +23 -0
  122. package/dist/cjs/exceptions/abstract.exception.js +66 -0
  123. package/dist/cjs/exceptions/application/aggregate-not-found.exception.d.ts +5 -0
  124. package/dist/cjs/exceptions/application/aggregate-not-found.exception.js +17 -0
  125. package/dist/cjs/exceptions/application/application.exception.d.ts +6 -0
  126. package/dist/cjs/exceptions/application/application.exception.js +17 -0
  127. package/dist/cjs/exceptions/application/concurrency.exception.d.ts +5 -0
  128. package/dist/cjs/exceptions/application/concurrency.exception.js +17 -0
  129. package/dist/cjs/exceptions/application/not-allowed.exception.d.ts +5 -0
  130. package/dist/cjs/exceptions/application/not-allowed.exception.js +17 -0
  131. package/dist/cjs/exceptions/brand/exception-brand.d.ts +6 -0
  132. package/dist/cjs/exceptions/brand/exception-brand.js +29 -0
  133. package/dist/cjs/exceptions/domain/domain.exception.d.ts +6 -0
  134. package/dist/cjs/exceptions/domain/domain.exception.js +17 -0
  135. package/dist/cjs/exceptions/domain/required-value.exception.d.ts +4 -0
  136. package/dist/cjs/exceptions/domain/required-value.exception.js +21 -0
  137. package/dist/cjs/exceptions/domain/type-primitive.exception.d.ts +4 -0
  138. package/dist/cjs/exceptions/domain/type-primitive.exception.js +21 -0
  139. package/dist/cjs/exceptions/domain/validation.exception.d.ts +14 -0
  140. package/dist/cjs/exceptions/domain/validation.exception.js +23 -0
  141. package/dist/cjs/exceptions/exception-code.d.ts +15 -0
  142. package/dist/cjs/exceptions/exception-code.js +19 -0
  143. package/dist/cjs/exceptions/index.d.ts +14 -0
  144. package/dist/cjs/exceptions/index.js +30 -0
  145. package/dist/cjs/exceptions/infrastructure/event-delivery.exception.d.ts +5 -0
  146. package/dist/cjs/exceptions/infrastructure/event-delivery.exception.js +20 -0
  147. package/dist/cjs/exceptions/infrastructure/infrastructure.exception.d.ts +6 -0
  148. package/dist/cjs/exceptions/infrastructure/infrastructure.exception.js +17 -0
  149. package/dist/cjs/exceptions/infrastructure/internal-error.exception.d.ts +5 -0
  150. package/dist/cjs/exceptions/infrastructure/internal-error.exception.js +17 -0
  151. package/dist/cjs/exceptions/infrastructure/unknown-event.exception.d.ts +4 -0
  152. package/dist/cjs/exceptions/infrastructure/unknown-event.exception.js +19 -0
  153. package/dist/cjs/exceptions/received/received-value.d.ts +4 -0
  154. package/dist/cjs/exceptions/received/received-value.js +13 -0
  155. package/dist/cjs/infrastructure/clock/fixed-clock.d.ts +8 -0
  156. package/dist/cjs/infrastructure/clock/fixed-clock.js +19 -0
  157. package/dist/cjs/infrastructure/clock/system-clock.d.ts +4 -0
  158. package/dist/cjs/infrastructure/clock/system-clock.js +9 -0
  159. package/dist/cjs/infrastructure/event/domain-event-bus.d.ts +16 -0
  160. package/dist/cjs/infrastructure/event/domain-event-bus.js +60 -0
  161. package/dist/cjs/infrastructure/event/event-channel.d.ts +9 -0
  162. package/dist/cjs/infrastructure/event/event-channel.js +2 -0
  163. package/dist/cjs/infrastructure/event/event-registry.d.ts +9 -0
  164. package/dist/cjs/infrastructure/event/event-registry.js +43 -0
  165. package/dist/cjs/infrastructure/event/in-memory/emitter.d.ts +11 -0
  166. package/dist/cjs/infrastructure/event/in-memory/emitter.js +54 -0
  167. package/dist/cjs/infrastructure/event/in-memory/in-memory-event-channel.d.ts +16 -0
  168. package/dist/cjs/infrastructure/event/in-memory/in-memory-event-channel.js +51 -0
  169. package/dist/cjs/infrastructure/http/http-error-mapper.d.ts +23 -0
  170. package/dist/cjs/infrastructure/http/http-error-mapper.js +63 -0
  171. package/dist/cjs/infrastructure/index.d.ts +16 -0
  172. package/dist/cjs/infrastructure/index.js +21 -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/esm/application/event/event-bus.d.ts +4 -0
  182. package/dist/esm/application/event/event-bus.js +1 -0
  183. package/dist/esm/application/event/event-listener.d.ts +4 -0
  184. package/dist/esm/application/event/event-listener.js +2 -0
  185. package/dist/esm/application/event/listens-to.d.ts +15 -0
  186. package/dist/esm/application/event/listens-to.js +25 -0
  187. package/dist/esm/application/index.d.ts +7 -0
  188. package/dist/esm/application/index.js +3 -0
  189. package/dist/esm/application/ports/clock.d.ts +3 -0
  190. package/dist/esm/application/ports/clock.js +1 -0
  191. package/dist/esm/application/ports/logger.d.ts +8 -0
  192. package/dist/esm/application/ports/logger.js +1 -0
  193. package/dist/esm/application/use-case/use-case.d.ts +6 -0
  194. package/dist/esm/application/use-case/use-case.js +20 -0
  195. package/dist/esm/domain/aggregate/aggregate-root.d.ts +14 -0
  196. package/dist/esm/domain/aggregate/aggregate-root.js +29 -0
  197. package/dist/esm/domain/entity/entity.d.ts +9 -0
  198. package/dist/esm/domain/entity/entity.js +15 -0
  199. package/dist/esm/domain/event/event-base.d.ts +29 -0
  200. package/dist/esm/domain/event/event-base.js +47 -0
  201. package/dist/esm/domain/index.d.ts +10 -0
  202. package/dist/esm/domain/index.js +6 -0
  203. package/dist/esm/domain/primitive/primitive-types.d.ts +22 -0
  204. package/dist/esm/domain/primitive/primitive-types.js +1 -0
  205. package/dist/esm/domain/repository/aggregate-finder.d.ts +4 -0
  206. package/dist/esm/domain/repository/aggregate-finder.js +1 -0
  207. package/dist/esm/domain/repository/aggregate-remover.d.ts +4 -0
  208. package/dist/esm/domain/repository/aggregate-remover.js +1 -0
  209. package/dist/esm/domain/repository/aggregate-saver.d.ts +4 -0
  210. package/dist/esm/domain/repository/aggregate-saver.js +1 -0
  211. package/dist/esm/domain/specification/specification.d.ts +9 -0
  212. package/dist/esm/domain/specification/specification.js +40 -0
  213. package/dist/esm/domain/type/abstract-type.d.ts +20 -0
  214. package/dist/esm/domain/type/abstract-type.js +65 -0
  215. package/dist/esm/domain/type/array-type.d.ts +16 -0
  216. package/dist/esm/domain/type/array-type.js +61 -0
  217. package/dist/esm/domain/type/boolean-type.d.ts +4 -0
  218. package/dist/esm/domain/type/boolean-type.js +12 -0
  219. package/dist/esm/domain/type/composite/composite-field.d.ts +19 -0
  220. package/dist/esm/domain/type/composite/composite-field.js +59 -0
  221. package/dist/esm/domain/type/composite/composite.d.ts +26 -0
  222. package/dist/esm/domain/type/composite/composite.js +52 -0
  223. package/dist/esm/domain/type/date-type.d.ts +18 -0
  224. package/dist/esm/domain/type/date-type.js +29 -0
  225. package/dist/esm/domain/type/enum-type.d.ts +7 -0
  226. package/dist/esm/domain/type/enum-type.js +26 -0
  227. package/dist/esm/domain/type/equality/value-equality.d.ts +7 -0
  228. package/dist/esm/domain/type/equality/value-equality.js +37 -0
  229. package/dist/esm/domain/type/id-type.d.ts +7 -0
  230. package/dist/esm/domain/type/id-type.js +13 -0
  231. package/dist/esm/domain/type/immutable/immutable-date.d.ts +4 -0
  232. package/dist/esm/domain/type/immutable/immutable-date.js +33 -0
  233. package/dist/esm/domain/type/immutable/immutable.d.ts +4 -0
  234. package/dist/esm/domain/type/immutable/immutable.js +15 -0
  235. package/dist/esm/domain/type/index.d.ts +17 -0
  236. package/dist/esm/domain/type/index.js +14 -0
  237. package/dist/esm/domain/type/json-type.d.ts +5 -0
  238. package/dist/esm/domain/type/json-type.js +13 -0
  239. package/dist/esm/domain/type/number-type.d.ts +4 -0
  240. package/dist/esm/domain/type/number-type.js +12 -0
  241. package/dist/esm/domain/type/required/required-mark.d.ts +9 -0
  242. package/dist/esm/domain/type/required/required-mark.js +9 -0
  243. package/dist/esm/domain/type/required/required.d.ts +7 -0
  244. package/dist/esm/domain/type/required/required.js +18 -0
  245. package/dist/esm/domain/type/string-type.d.ts +4 -0
  246. package/dist/esm/domain/type/string-type.js +12 -0
  247. package/dist/esm/domain/type/uuid-type.d.ts +7 -0
  248. package/dist/esm/domain/type/uuid-type.js +23 -0
  249. package/dist/esm/domain/type/value-objects/value-objects.d.ts +16 -0
  250. package/dist/esm/domain/type/value-objects/value-objects.js +66 -0
  251. package/dist/esm/exceptions/abstract.exception.d.ts +23 -0
  252. package/dist/esm/exceptions/abstract.exception.js +62 -0
  253. package/dist/esm/exceptions/application/aggregate-not-found.exception.d.ts +5 -0
  254. package/dist/esm/exceptions/application/aggregate-not-found.exception.js +13 -0
  255. package/dist/esm/exceptions/application/application.exception.d.ts +6 -0
  256. package/dist/esm/exceptions/application/application.exception.js +13 -0
  257. package/dist/esm/exceptions/application/concurrency.exception.d.ts +5 -0
  258. package/dist/esm/exceptions/application/concurrency.exception.js +13 -0
  259. package/dist/esm/exceptions/application/not-allowed.exception.d.ts +5 -0
  260. package/dist/esm/exceptions/application/not-allowed.exception.js +13 -0
  261. package/dist/esm/exceptions/brand/exception-brand.d.ts +6 -0
  262. package/dist/esm/exceptions/brand/exception-brand.js +25 -0
  263. package/dist/esm/exceptions/domain/domain.exception.d.ts +6 -0
  264. package/dist/esm/exceptions/domain/domain.exception.js +13 -0
  265. package/dist/esm/exceptions/domain/required-value.exception.d.ts +4 -0
  266. package/dist/esm/exceptions/domain/required-value.exception.js +17 -0
  267. package/dist/esm/exceptions/domain/type-primitive.exception.d.ts +4 -0
  268. package/dist/esm/exceptions/domain/type-primitive.exception.js +17 -0
  269. package/dist/esm/exceptions/domain/validation.exception.d.ts +14 -0
  270. package/dist/esm/exceptions/domain/validation.exception.js +19 -0
  271. package/dist/esm/exceptions/exception-code.d.ts +15 -0
  272. package/dist/esm/exceptions/exception-code.js +16 -0
  273. package/dist/esm/exceptions/index.d.ts +14 -0
  274. package/dist/esm/exceptions/index.js +14 -0
  275. package/dist/esm/exceptions/infrastructure/event-delivery.exception.d.ts +5 -0
  276. package/dist/esm/exceptions/infrastructure/event-delivery.exception.js +16 -0
  277. package/dist/esm/exceptions/infrastructure/infrastructure.exception.d.ts +6 -0
  278. package/dist/esm/exceptions/infrastructure/infrastructure.exception.js +13 -0
  279. package/dist/esm/exceptions/infrastructure/internal-error.exception.d.ts +5 -0
  280. package/dist/esm/exceptions/infrastructure/internal-error.exception.js +13 -0
  281. package/dist/esm/exceptions/infrastructure/unknown-event.exception.d.ts +4 -0
  282. package/dist/esm/exceptions/infrastructure/unknown-event.exception.js +15 -0
  283. package/dist/esm/exceptions/received/received-value.d.ts +4 -0
  284. package/dist/esm/exceptions/received/received-value.js +9 -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 +47 -0
  299. package/dist/esm/infrastructure/http/http-error-mapper.d.ts +23 -0
  300. package/dist/esm/infrastructure/http/http-error-mapper.js +59 -0
  301. package/dist/esm/infrastructure/index.d.ts +16 -0
  302. package/dist/esm/infrastructure/index.js +9 -0
  303. package/dist/esm/infrastructure/logging/console-logger.d.ts +17 -0
  304. package/dist/esm/infrastructure/logging/console-logger.js +33 -0
  305. package/dist/esm/infrastructure/logging/in-memory-logger.d.ts +15 -0
  306. package/dist/esm/infrastructure/logging/in-memory-logger.js +23 -0
  307. package/dist/esm/infrastructure/logging/log-serializer.d.ts +7 -0
  308. package/dist/esm/infrastructure/logging/log-serializer.js +55 -0
  309. package/dist/esm/infrastructure/logging/silent-logger.d.ts +7 -0
  310. package/dist/esm/infrastructure/logging/silent-logger.js +14 -0
  311. package/dist/esm/package.json +3 -0
  312. package/package.json +106 -4
@@ -0,0 +1,471 @@
1
+ # Event Sourcing en TypeScript
2
+
3
+ `@archi-code/ddd` no trae event store, repositorios con Event Sourcing ni snapshots: todo lo de esta referencia es código del proyecto escrito sobre las clases del paquete (`AggregateRoot`, `EventBase`, `EventRegistry`, `UseCase`, `EventBus`, `ConcurrencyException`). Úsalo solo en los agregados que la tabla de decisión de `ddd-skills/ddd-event-sourcing-cqrs/GUIA.md` justifique.
4
+
5
+ ## Eventos del stream
6
+
7
+ Cada evento es una subclase de `EventBase` con `static readonly eventName`, el id del agregado en `super(...)` y una carga de primitivos tomados de los value objects (el dinero como `{ amount, currency }`), nunca value objects: el evento se serializa tal cual con `toJSON()` [IDDD cap. 8].
8
+
9
+ ```ts
10
+ import { EventBase } from '@archi-code/ddd/domain';
11
+ import type { EventMetadata } from '@archi-code/ddd/domain';
12
+
13
+ export class PaymentRequested extends EventBase {
14
+ static readonly eventName = 'PaymentRequested';
15
+
16
+ constructor(
17
+ paymentId: string,
18
+ readonly orderId: string,
19
+ readonly amount: { amount: number; currency: string },
20
+ metadata?: EventMetadata,
21
+ ) {
22
+ super(paymentId, metadata);
23
+ }
24
+ }
25
+
26
+ export class PaymentAuthorized extends EventBase {
27
+ static readonly eventName = 'PaymentAuthorized';
28
+
29
+ constructor(
30
+ paymentId: string,
31
+ readonly authorizationCode: string,
32
+ readonly expiresAt: string,
33
+ metadata?: EventMetadata,
34
+ ) {
35
+ super(paymentId, metadata);
36
+ }
37
+ }
38
+
39
+ export class PaymentRejected extends EventBase {
40
+ static readonly eventName = 'PaymentRejected';
41
+
42
+ constructor(
43
+ paymentId: string,
44
+ readonly reason: string,
45
+ metadata?: EventMetadata,
46
+ ) {
47
+ super(paymentId, metadata);
48
+ }
49
+ }
50
+
51
+ export class PaymentCaptured extends EventBase {
52
+ static readonly eventName = 'PaymentCaptured';
53
+ }
54
+
55
+ export type PaymentEvent = PaymentRequested | PaymentAuthorized | PaymentRejected | PaymentCaptured;
56
+ ```
57
+
58
+ `EventBase` pone `eventId`, `aggregateId` y un `occurredOn` inmutable (del `clock` que recibe el método del agregado), y `toJSON()` escribe `eventName`, `eventVersion`, `eventId`, `aggregateId`, `occurredOn` en ISO y la carga: esa es la fila del stream.
59
+
60
+ ## Agregado con decidir y aplicar
61
+
62
+ `[Fuera de los libros como código; estructura basada en IDDD apéndice A]`
63
+
64
+ ```ts
65
+ import {
66
+ AggregateRoot,
67
+ Composite,
68
+ DateType,
69
+ EnumType,
70
+ IdType,
71
+ NumberType,
72
+ Required,
73
+ StringType,
74
+ } from '@archi-code/ddd/domain';
75
+ import { DomainException } from '@archi-code/ddd/exceptions';
76
+ import { Validations } from '@archi-code/validation';
77
+
78
+ export class PaymentId extends IdType<'PaymentId'> {}
79
+ export class OrderId extends IdType<'OrderId'> {}
80
+ export class AuthorizationCode extends Required(StringType) {}
81
+ export class RejectionReason extends Required(StringType) {}
82
+ export class ExpiresAt extends Required(DateType) {}
83
+
84
+ @Validations([{ validator: 'isInt' }])
85
+ export class Cents extends Required(NumberType) {}
86
+ @Validations([{ validator: 'isISO4217' }])
87
+ export class Currency extends Required(StringType) {}
88
+ export class Money extends Composite({ amount: Cents, currency: Currency }) {}
89
+
90
+ export enum Status {
91
+ Requested = 'requested',
92
+ Authorized = 'authorized',
93
+ Rejected = 'rejected',
94
+ Captured = 'captured',
95
+ }
96
+
97
+ class StatusType extends EnumType<Status> {
98
+ protected getEnum(): typeof Status {
99
+ return Status;
100
+ }
101
+ }
102
+
103
+ export class PaymentStatus extends Required(StatusType) {
104
+ is(status: Status): boolean {
105
+ return this.value === status;
106
+ }
107
+ }
108
+
109
+ export class PaymentNotAuthorized extends DomainException {
110
+ constructor(paymentId: string) {
111
+ super(`Payment ${paymentId} is not authorized`, ['PAY002']);
112
+ }
113
+ }
114
+
115
+ export class AuthorizationExpired extends DomainException {
116
+ constructor(paymentId: string) {
117
+ super(`The authorization of payment ${paymentId} has expired`, ['PAY003']);
118
+ }
119
+ }
120
+
121
+ export class PaymentAlreadyDecided extends DomainException {
122
+ constructor(paymentId: string) {
123
+ super(`Payment ${paymentId} was already authorized or rejected`, ['PAY004']);
124
+ }
125
+ }
126
+
127
+ export class Payment extends AggregateRoot<PaymentId, PaymentEvent> {
128
+ private status = new PaymentStatus(Status.Requested);
129
+ private amount: Money | null = null;
130
+ private expiresAt: ExpiresAt | null = null;
131
+ private replayed = 0;
132
+
133
+ private constructor(id: PaymentId) {
134
+ super(id);
135
+ }
136
+
137
+ static request(id: PaymentId, orderId: OrderId, amount: Money, clock: { now(): Date }): Payment {
138
+ const payment = new Payment(id);
139
+ payment.emit(
140
+ new PaymentRequested(
141
+ id.value,
142
+ orderId.value,
143
+ { amount: amount.amount.value, currency: amount.currency.value },
144
+ { clock },
145
+ ),
146
+ );
147
+ return payment;
148
+ }
149
+
150
+ static fromHistory(id: PaymentId, history: readonly PaymentEvent[]): Payment {
151
+ const payment = new Payment(id);
152
+ history.forEach((event) => payment.apply(event));
153
+ payment.replayed = history.length;
154
+ return payment;
155
+ }
156
+
157
+ streamVersion(): number {
158
+ return this.replayed;
159
+ }
160
+
161
+ authorize(code: AuthorizationCode, expiresAt: ExpiresAt, clock: { now(): Date }): void {
162
+ if (!this.status.is(Status.Requested)) {
163
+ throw new PaymentAlreadyDecided(this.id.value);
164
+ }
165
+ this.emit(
166
+ new PaymentAuthorized(this.id.value, code.value, expiresAt.value.toISOString(), { clock }),
167
+ );
168
+ }
169
+
170
+ reject(reason: RejectionReason, clock: { now(): Date }): void {
171
+ if (!this.status.is(Status.Requested)) {
172
+ throw new PaymentAlreadyDecided(this.id.value);
173
+ }
174
+ this.emit(new PaymentRejected(this.id.value, reason.value, { clock }));
175
+ }
176
+
177
+ capture(clock: { now(): Date }): void {
178
+ if (!this.status.is(Status.Authorized) || this.expiresAt === null) {
179
+ throw new PaymentNotAuthorized(this.id.value);
180
+ }
181
+ if (this.expiresAt.value < clock.now()) {
182
+ throw new AuthorizationExpired(this.id.value);
183
+ }
184
+ this.emit(new PaymentCaptured(this.id.value, { clock }));
185
+ }
186
+
187
+ private emit(event: PaymentEvent): void {
188
+ this.apply(event);
189
+ this.record(event);
190
+ }
191
+
192
+ private apply(event: PaymentEvent): void {
193
+ if (event instanceof PaymentRequested) {
194
+ this.amount = Money.fromPrimitives(event.amount);
195
+ } else if (event instanceof PaymentAuthorized) {
196
+ this.status = new PaymentStatus(Status.Authorized);
197
+ this.expiresAt = new ExpiresAt(new Date(event.expiresAt));
198
+ } else if (event instanceof PaymentRejected) {
199
+ this.status = new PaymentStatus(Status.Rejected);
200
+ } else {
201
+ this.status = new PaymentStatus(Status.Captured);
202
+ }
203
+ }
204
+ }
205
+ ```
206
+
207
+ Reglas:
208
+ * `apply` no valida ni lanza: los eventos son hechos ya ocurridos [Destilado cap. 6].
209
+ * Las reglas viven en los métodos de comando (`authorize`, `capture`), antes de emitir, y lanzan subclases de `DomainException` con su código.
210
+ * El estado solo cambia vía eventos: `emit` aplica y después llama a `record` (protegido en `AggregateRoot`, congela el evento), así que `pullDomainEvents()` devuelve exactamente los cambios pendientes, en orden.
211
+ * `fromHistory` aplica sin `record`: reconstituir no genera eventos nuevos.
212
+ * El reloj se recibe como `{ now(): Date }` y se pasa a cada evento (`{ clock }`), para que reconstruir no dependa de la hora actual; en pruebas, `FixedClock`.
213
+ * IDDD propone separar estado y comportamiento en dos clases que solo colaboran a través de `apply` [IDDD apéndice A]; aquí el estado son campos privados de value objects que solo `apply` escribe. Si el agregado crece, extrae ese estado a una clase propia con su `apply`.
214
+ * `[Fuera de los libros: convención de @archi-code/ddd]` La `version` de `AggregateRoot` cuenta guardados, no eventos (crece 1 por `save`), así que este agregado lleva su propia versión de stream (`streamVersion()`, los eventos que se aplicaron al cargar) y no se guarda como instantánea: no necesita `toPrimitives()`/`fromPrimitives()` ni getters para sus campos, porque lo que se persiste son los eventos.
215
+
216
+ ## Event store
217
+
218
+ Un stream por agregado, identificado por la identidad de la raíz; almacenamiento solo de anexión con cualquier tecnología que ofrezca consistencia fuerte [IDDD apéndice A; Destilado cap. 6].
219
+
220
+ ```sql
221
+ CREATE TABLE event_streams (
222
+ stream_id TEXT NOT NULL,
223
+ version INT NOT NULL,
224
+ body JSONB NOT NULL,
225
+ global_seq BIGSERIAL UNIQUE,
226
+ PRIMARY KEY (stream_id, version)
227
+ );
228
+ ```
229
+
230
+ La clave primaria `(stream_id, version)` impide dos escrituras con la misma versión; `global_seq` da el orden global que necesitan la publicación y la reconstrucción de proyecciones. `body` es el `toJSON()` del evento.
231
+
232
+ El dominio declara el contrato del stream (solo tipos, como los contratos de repositorio del paquete) `[Fuera de los libros: convención de @archi-code/ddd]`: no es `AggregateFinder`/`AggregateSaver`, porque guardar necesita los cambios que el caso de uso ya sacó con `pullDomainEvents()` para publicarlos.
233
+
234
+ ```ts
235
+ export interface PaymentStream {
236
+ load(id: PaymentId): Promise<Payment | null>;
237
+ append(payment: Payment, changes: readonly PaymentEvent[]): Promise<void>;
238
+ }
239
+ ```
240
+
241
+ La infraestructura lo implementa: reconstruye cada fila con `EventRegistry.fromJSON` (que conserva `eventId` y `occurredOn` y congela el evento), anexa todos los eventos de un `append` en una sola transacción que abre y cierra con su propia conexión, y traduce la violación de la clave primaria a `ConcurrencyException`. Como cualquier repositorio del paquete, el stream es responsable de todo lo de persistencia: la escritura atómica del stream con su versión esperada, la conexión y los errores del driver `[Fuera de los libros: convención de @archi-code/ddd]`.
242
+
243
+ ```ts
244
+ import type { SerializedEvent } from '@archi-code/ddd/domain';
245
+ import { EventRegistry } from '@archi-code/ddd/infrastructure';
246
+ import { ConcurrencyException, InternalErrorException } from '@archi-code/ddd/exceptions';
247
+
248
+ export const paymentEvents = new EventRegistry<PaymentEvent>()
249
+ .register(
250
+ PaymentRequested,
251
+ (json) =>
252
+ new PaymentRequested(
253
+ json.aggregateId,
254
+ json.orderId as string,
255
+ json.amount as { amount: number; currency: string },
256
+ json,
257
+ ),
258
+ )
259
+ .register(
260
+ PaymentAuthorized,
261
+ (json) =>
262
+ new PaymentAuthorized(
263
+ json.aggregateId,
264
+ json.authorizationCode as string,
265
+ json.expiresAt as string,
266
+ json,
267
+ ),
268
+ )
269
+ .register(
270
+ PaymentRejected,
271
+ (json) => new PaymentRejected(json.aggregateId, json.reason as string, json),
272
+ )
273
+ .register(PaymentCaptured, (json) => new PaymentCaptured(json.aggregateId, json));
274
+
275
+ interface SqlClient {
276
+ query<Row>(text: string, values: readonly unknown[]): Promise<{ rows: Row[] }>;
277
+ }
278
+
279
+ interface PoolClient extends SqlClient {
280
+ release(): void;
281
+ }
282
+
283
+ interface Pool extends SqlClient {
284
+ connect(): Promise<PoolClient>;
285
+ }
286
+
287
+ export class PgPaymentStream implements PaymentStream {
288
+ constructor(
289
+ private readonly pool: Pool,
290
+ private readonly registry: EventRegistry<PaymentEvent>,
291
+ ) {}
292
+
293
+ async load(id: PaymentId): Promise<Payment | null> {
294
+ const { rows } = await this.pool.query<{ body: SerializedEvent }>(
295
+ 'SELECT body FROM event_streams WHERE stream_id = $1 ORDER BY version',
296
+ [id.value],
297
+ );
298
+ if (rows.length === 0) {
299
+ return null;
300
+ }
301
+ return Payment.fromHistory(
302
+ id,
303
+ rows.map((row) => this.registry.fromJSON(row.body)),
304
+ );
305
+ }
306
+
307
+ async append(payment: Payment, changes: readonly PaymentEvent[]): Promise<void> {
308
+ const expected = payment.streamVersion();
309
+ const client = await this.pool.connect();
310
+ try {
311
+ await client.query('BEGIN', []);
312
+ for (const [index, event] of changes.entries()) {
313
+ await client.query(
314
+ 'INSERT INTO event_streams (stream_id, version, body) VALUES ($1, $2, $3)',
315
+ [payment.id.value, expected + index + 1, JSON.stringify(event.toJSON())],
316
+ );
317
+ }
318
+ await client.query('COMMIT', []);
319
+ } catch (error) {
320
+ await client.query('ROLLBACK', []);
321
+ if ((error as { code?: string }).code === '23505') {
322
+ throw new ConcurrencyException('Payment', payment.id.value, expected, { cause: error });
323
+ }
324
+ throw new InternalErrorException('appending payment events', { cause: error });
325
+ } finally {
326
+ client.release();
327
+ }
328
+ }
329
+ }
330
+ ```
331
+
332
+ `Pool` y `SqlClient` son la parte de `pg` que usa el adaptador, declarada de forma estructural. La transacción empieza y termina dentro de `append`: o entran todos los eventos del cambio o ninguno, y la aplicación no ve ninguna transacción. `'23505'` es el código de violación de unicidad de PostgreSQL; con otro motor, comprueba el suyo.
333
+
334
+ ## Caso de uso y reintento
335
+
336
+ El caso de uso carga, decide, anexa y publica; no abre transacciones ni recibe un puerto para ello. Ante un conflicto puede reintentar recargando y reejecutando el comando contra el estado nuevo, como propone IDDD [IDDD apéndice A]; si el comando ya no es válido, el error de negocio sale normalmente. `[Fuera de los libros: convención de @archi-code/ddd]` El stream solo carga y anexa; el bucle de reintento va en el `handle` del caso de uso, cada intento vuelve a cargar y vuelve a anexar, unos pocos intentos y después relanza la `ConcurrencyException` (HTTP 409 con `HttpErrorMapper`). Reintenta solo comandos seguros de repetir; un caso de uso que lanza un listener no lleva este bucle: el reintento lo hace la reentrega del canal.
337
+
338
+ ```ts
339
+ import { UseCase } from '@archi-code/ddd/application';
340
+ import type { Clock, EventBus } from '@archi-code/ddd/application';
341
+ import { AggregateNotFoundException, ConcurrencyException } from '@archi-code/ddd/exceptions';
342
+
343
+ export class CapturePayment extends UseCase<{ paymentId: string }, PaymentId, void> {
344
+ constructor(
345
+ private readonly payments: PaymentStream,
346
+ private readonly events: EventBus<PaymentEvent>,
347
+ private readonly clock: Clock,
348
+ ) {
349
+ super();
350
+ }
351
+
352
+ protected toCommand(input: { paymentId: string }): PaymentId {
353
+ return new PaymentId(input.paymentId);
354
+ }
355
+
356
+ protected async handle(paymentId: PaymentId): Promise<void> {
357
+ for (let attempt = 1; ; attempt += 1) {
358
+ try {
359
+ const payment = await this.payments.load(paymentId);
360
+ if (payment === null) {
361
+ throw new AggregateNotFoundException('Payment', paymentId.value);
362
+ }
363
+ payment.capture(this.clock);
364
+ const changes = payment.pullDomainEvents();
365
+ await this.payments.append(payment, changes);
366
+ await this.events.publish(changes);
367
+ return;
368
+ } catch (error) {
369
+ if (!(error instanceof ConcurrencyException) || attempt === 3) {
370
+ throw error;
371
+ }
372
+ }
373
+ }
374
+ }
375
+ }
376
+ ```
377
+
378
+ Publicar: IDDD publica con un proceso en segundo plano que lee lo anexado [IDDD apéndice A]. Con el paquete, el caso de uso solo ve el puerto `EventBus`; el `DomainEventBus` de la composición envía a un `EventChannel`. Si `publish` falla después de `append`, los eventos ya están en el stream pero no se entregan. Para no perder ninguno, el propio `event_streams` hace de bandeja, porque `append` ya los guardó en su escritura atómica: un reenviador lee por `global_seq` y entrega los `SerializedEvent` a los manejadores que registró `receive`, y el canal que recibe el bus del caso de uso no escribe nada en su `send` (los eventos ya están guardados) y delega `receive` en el canal del reenviador. Es persistencia y entrega, así que vive en la infraestructura; los casos de uso no cambian `[Fuera de los libros: convención de @archi-code/ddd]`.
379
+
380
+ ## Pruebas en memoria
381
+
382
+ Una implementación en memoria del stream sirve como doble de pruebas y como referencia del contrato; anexa todos los cambios de una vez o ninguno, como `PgPaymentStream`:
383
+
384
+ ```ts
385
+ import { DomainEventBus, FixedClock, InMemoryEventChannel } from '@archi-code/ddd/infrastructure';
386
+
387
+ export class InMemoryPaymentStream implements PaymentStream {
388
+ private readonly streams = new Map<string, readonly SerializedEvent[]>();
389
+
390
+ constructor(private readonly registry: EventRegistry<PaymentEvent>) {}
391
+
392
+ async load(id: PaymentId): Promise<Payment | null> {
393
+ const stream = this.streams.get(id.value);
394
+ if (stream === undefined) {
395
+ return null;
396
+ }
397
+ return Payment.fromHistory(
398
+ id,
399
+ stream.map((json) => this.registry.fromJSON(json)),
400
+ );
401
+ }
402
+
403
+ async append(payment: Payment, changes: readonly PaymentEvent[]): Promise<void> {
404
+ const stream = this.streams.get(payment.id.value) ?? [];
405
+ if (stream.length !== payment.streamVersion()) {
406
+ throw new ConcurrencyException('Payment', payment.id.value, payment.streamVersion());
407
+ }
408
+ this.streams.set(payment.id.value, [...stream, ...changes.map((event) => event.toJSON())]);
409
+ }
410
+ }
411
+
412
+ const clock = new FixedClock('2026-10-19T09:30:00Z');
413
+ const payments = new InMemoryPaymentStream(paymentEvents);
414
+ const channel = new InMemoryEventChannel();
415
+ const bus = new DomainEventBus<PaymentEvent>(channel, paymentEvents);
416
+
417
+ const paymentId = PaymentId.generate();
418
+ const payment = Payment.request(
419
+ paymentId,
420
+ OrderId.generate(),
421
+ Money.fromPrimitives({ amount: 4990, currency: 'EUR' }),
422
+ clock,
423
+ );
424
+ payment.authorize(
425
+ new AuthorizationCode('AUTH-7731'),
426
+ new ExpiresAt(new Date('2026-10-26T09:30:00Z')),
427
+ clock,
428
+ );
429
+ await payments.append(payment, payment.pullDomainEvents());
430
+
431
+ await new CapturePayment(payments, bus, clock).execute({
432
+ paymentId: paymentId.value,
433
+ });
434
+ channel.sent.map((event) => event.eventName); // ['PaymentCaptured']
435
+ (await payments.load(paymentId))?.streamVersion(); // 3
436
+ ```
437
+
438
+ Ejecuta las mismas pruebas de contrato (carga lo anexado, rechaza una versión esperada antigua con `ConcurrencyException`) contra `InMemoryPaymentStream` y `PgPaymentStream`, como el contrato de repositorio de `ddd-skills/ddd-repositorios-persistencia/GUIA.md`.
439
+
440
+ ## Snapshots
441
+
442
+ Para streams largos, guarda periódicamente el estado serializado con su versión y carga desde ahí más los eventos posteriores [IDDD apéndice A; Destilado cap. 6]. Los snapshots son una optimización desechable: si cambia la forma del estado, se borran y se regeneran. El paquete no los trae: son una tabla más de tu infraestructura (`stream_id`, `version`, `state`) y una fábrica del agregado que parte del estado y aplica solo los eventos con versión mayor, dejando `streamVersion()` en la versión del último evento aplicado.
443
+
444
+ ## Versionado de eventos
445
+
446
+ `[Fuera de los libros]` Los eventos del stream no se reescriben. Para cambiar su forma, convierte las versiones antiguas al leer ("upcasting") en el deserializador, o añade un tipo de evento nuevo. El apéndice de IDDD trata los serializadores (por ejemplo Protocol Buffers) como apoyo para esta evolución [IDDD apéndice A].
447
+
448
+ Con el paquete, el evento declara `static readonly eventVersion` (1 si no se declara; `toJSON()` lo escribe) y la fábrica del `EventRegistry` recibe el `eventVersion` con el que se guardó cada fila, así que el upcasting va ahí. Por ejemplo, si una primera versión de `PaymentRequested` guardaba `amountCents` en euros:
449
+
450
+ ```ts
451
+ export class PaymentRequested extends EventBase {
452
+ static readonly eventName = 'PaymentRequested';
453
+ static readonly eventVersion = 2;
454
+ // constructor as above
455
+ }
456
+
457
+ new EventRegistry<PaymentEvent>().register(
458
+ PaymentRequested,
459
+ (json) =>
460
+ new PaymentRequested(
461
+ json.aggregateId,
462
+ json.orderId as string,
463
+ json.eventVersion === 1
464
+ ? { amount: json.amountCents as number, currency: 'EUR' }
465
+ : (json.amount as { amount: number; currency: string }),
466
+ json,
467
+ ),
468
+ );
469
+ ```
470
+
471
+ Pasa siempre `json` como último argumento: el evento reconstruido conserva su `eventId` y su `occurredOn`, y `fromJSON` lanza `InternalErrorException` si la fábrica los pierde.