@archi-code/ddd 3.0.0-alpha.1 → 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.
- package/README.md +478 -376
- package/SKILL.md +10 -8
- package/ddd-skills/archi-code-ddd/imports.md +28 -18
- package/ddd-skills/archi-code-ddd/layers.md +68 -53
- package/ddd-skills/archi-code-ddd/patterns.md +50 -43
- package/ddd-skills/archi-code-ddd/what-not-to-do.md +25 -18
- package/ddd-skills/archi-code-ddd/where-each-class-goes.md +11 -10
- package/ddd-skills/ddd-agregados/GUIA.md +2 -2
- package/ddd-skills/ddd-agregados/references/consistencia-eventual.md +5 -6
- package/ddd-skills/ddd-agregados/references/fabricas.md +5 -8
- package/ddd-skills/ddd-agregados/references/implementacion-ts.md +22 -27
- package/ddd-skills/ddd-arquitectura/GUIA.md +4 -4
- package/ddd-skills/ddd-arquitectura/assets/dependency-cruiser.cjs +13 -6
- package/ddd-skills/ddd-arquitectura/references/estilos-adicionales.md +2 -2
- package/ddd-skills/ddd-arquitectura/references/estructura-hexagonal-ts.md +70 -16
- package/ddd-skills/ddd-auditoria-refactorizacion/GUIA.md +1 -1
- package/ddd-skills/ddd-auditoria-refactorizacion/references/ejemplo-auditoria.md +9 -11
- package/ddd-skills/ddd-auditoria-refactorizacion/references/lista-comprobacion.md +4 -4
- package/ddd-skills/ddd-auditoria-refactorizacion/references/plan-migracion.md +2 -2
- package/ddd-skills/ddd-context-mapping/GUIA.md +5 -5
- package/ddd-skills/ddd-context-mapping/references/anticorrupcion-ts.md +33 -18
- package/ddd-skills/ddd-context-mapping/references/estilos-integracion.md +4 -7
- package/ddd-skills/ddd-event-sourcing-cqrs/GUIA.md +2 -2
- package/ddd-skills/ddd-event-sourcing-cqrs/references/event-sourcing-ts.md +32 -27
- package/ddd-skills/ddd-event-sourcing-cqrs/references/proyecciones-cqrs-ts.md +7 -7
- package/ddd-skills/ddd-eventos-dominio/GUIA.md +3 -3
- package/ddd-skills/ddd-eventos-dominio/references/diseno-eventos.md +15 -16
- package/ddd-skills/ddd-eventos-dominio/references/ejemplo-ecommerce.md +11 -11
- package/ddd-skills/ddd-eventos-dominio/references/publicacion-ts.md +34 -31
- package/ddd-skills/ddd-repositorios-persistencia/GUIA.md +7 -7
- package/ddd-skills/ddd-repositorios-persistencia/references/implementacion-ts.md +50 -32
- package/ddd-skills/ddd-repositorios-persistencia/references/tests-repositorios.md +31 -17
- package/ddd-skills/ddd-repositorios-persistencia/references/transacciones-ts.md +21 -14
- package/ddd-skills/ddd-servicios-capa-aplicacion/GUIA.md +2 -2
- package/ddd-skills/ddd-servicios-capa-aplicacion/references/capa-aplicacion-ts.md +19 -19
- package/ddd-skills/ddd-servicios-capa-aplicacion/references/ejemplo-ecommerce.md +12 -15
- package/ddd-skills/ddd-servicios-capa-aplicacion/references/servicios-dominio-ts.md +5 -6
- package/ddd-skills/ddd-value-objects-entidades/GUIA.md +3 -3
- package/ddd-skills/ddd-value-objects-entidades/references/entidades-ts.md +7 -9
- package/ddd-skills/ddd-value-objects-entidades/references/persistencia-valores.md +5 -5
- package/ddd-skills/ddd-value-objects-entidades/references/validacion.md +9 -9
- package/ddd-skills/ddd-value-objects-entidades/references/value-objects-ts.md +2 -3
- package/dist/cjs/application/event/listens-to.js +4 -4
- package/dist/cjs/{exceptions/application → application/exceptions}/aggregate-not-found.exception.d.ts +1 -1
- package/dist/cjs/{exceptions/application → application/exceptions}/aggregate-not-found.exception.js +4 -4
- package/dist/cjs/application/exceptions/application-exception-code.d.ts +7 -0
- package/dist/cjs/application/exceptions/application-exception-code.js +11 -0
- package/dist/cjs/application/exceptions/application.exception.d.ts +6 -0
- package/dist/cjs/application/exceptions/application.exception.js +16 -0
- package/dist/cjs/{exceptions/application → application/exceptions}/concurrency.exception.d.ts +1 -1
- package/dist/cjs/{exceptions/application → application/exceptions}/concurrency.exception.js +4 -4
- package/dist/cjs/{exceptions/application → application/exceptions}/not-allowed.exception.d.ts +1 -1
- package/dist/cjs/{exceptions/application → application/exceptions}/not-allowed.exception.js +4 -4
- package/dist/cjs/application/exceptions/unexpected-error.exception.d.ts +5 -0
- package/dist/cjs/application/exceptions/unexpected-error.exception.js +17 -0
- package/dist/cjs/application/index.d.ts +7 -0
- package/dist/cjs/application/index.js +15 -1
- package/dist/cjs/application/use-case/use-case.js +3 -2
- package/dist/{esm/domain/type/value-objects/value-objects.d.ts → cjs/application/value-object-builder/value-object-builder.d.ts} +3 -3
- package/dist/cjs/application/value-object-builder/value-object-builder.js +51 -0
- package/dist/cjs/domain/aggregate/aggregate-root.d.ts +0 -5
- package/dist/cjs/domain/aggregate/aggregate-root.js +4 -20
- package/dist/cjs/domain/entity/entity.js +2 -2
- package/dist/cjs/domain/event/event-base.d.ts +3 -9
- package/dist/cjs/domain/event/event-base.js +8 -38
- package/dist/cjs/domain/exceptions/domain-exception-code.d.ts +7 -0
- package/dist/cjs/domain/exceptions/domain-exception-code.js +11 -0
- package/dist/cjs/domain/exceptions/domain.exception.d.ts +6 -0
- package/dist/cjs/domain/exceptions/domain.exception.js +16 -0
- package/dist/cjs/domain/exceptions/invalid-event-definition.exception.d.ts +4 -0
- package/dist/cjs/domain/exceptions/invalid-event-definition.exception.js +19 -0
- package/dist/cjs/{exceptions/domain → domain/exceptions}/required-value.exception.js +5 -6
- package/dist/cjs/{exceptions/domain → domain/exceptions}/type-primitive.exception.js +5 -6
- package/dist/cjs/{exceptions/domain → domain/exceptions}/validation.exception.js +5 -5
- package/dist/cjs/domain/index.d.ts +8 -1
- package/dist/cjs/domain/index.js +14 -2
- package/dist/cjs/domain/primitive/primitive-types.d.ts +1 -3
- package/dist/cjs/domain/type/abstract-type.d.ts +6 -8
- package/dist/cjs/domain/type/abstract-type.js +15 -23
- package/dist/cjs/domain/type/array-type.d.ts +2 -1
- package/dist/cjs/domain/type/array-type.js +17 -18
- package/dist/cjs/domain/type/boolean-type.js +2 -2
- package/dist/cjs/domain/type/composite/composite-brand.d.ts +4 -0
- package/dist/cjs/domain/type/composite/composite-brand.js +15 -0
- package/dist/cjs/domain/type/composite/composite-field.d.ts +7 -8
- package/dist/cjs/domain/type/composite/composite-field.js +70 -47
- package/dist/cjs/domain/type/composite/composite-issues.d.ts +6 -0
- package/dist/cjs/domain/type/composite/composite-issues.js +35 -0
- package/dist/cjs/domain/type/composite/composite.js +15 -19
- package/dist/cjs/domain/type/date-type.d.ts +3 -2
- package/dist/cjs/domain/type/date-type.js +42 -7
- package/dist/cjs/domain/type/enum-type.js +2 -2
- package/dist/cjs/domain/type/id-type.d.ts +1 -1
- package/dist/cjs/domain/type/id-type.js +4 -4
- package/dist/cjs/domain/type/index.d.ts +2 -4
- package/dist/cjs/domain/type/index.js +3 -7
- package/dist/cjs/domain/type/json-type.d.ts +4 -0
- package/dist/cjs/domain/type/json-type.js +33 -4
- package/dist/cjs/domain/type/number-type.js +2 -2
- package/dist/cjs/domain/type/required/required-mark.d.ts +0 -1
- package/dist/cjs/domain/type/string-type.js +2 -2
- package/dist/cjs/domain/type/uuid-type.js +2 -2
- package/dist/cjs/infrastructure/event/domain-event-bus.js +9 -9
- package/dist/cjs/infrastructure/event/event-registry.js +9 -9
- package/dist/cjs/infrastructure/event/in-memory/emitter.js +2 -2
- package/dist/cjs/infrastructure/event/in-memory/in-memory-event-channel.d.ts +1 -1
- package/dist/cjs/infrastructure/event/in-memory/in-memory-event-channel.js +6 -7
- package/dist/cjs/{exceptions/infrastructure → infrastructure/exceptions}/event-delivery.exception.js +4 -4
- package/dist/cjs/infrastructure/exceptions/infrastructure-exception-code.d.ts +6 -0
- package/dist/cjs/infrastructure/exceptions/infrastructure-exception-code.js +10 -0
- package/dist/cjs/infrastructure/exceptions/infrastructure.exception.d.ts +6 -0
- package/dist/cjs/infrastructure/exceptions/infrastructure.exception.js +16 -0
- package/dist/cjs/{exceptions/infrastructure → infrastructure/exceptions}/internal-error.exception.d.ts +1 -1
- package/dist/cjs/{exceptions/infrastructure → infrastructure/exceptions}/internal-error.exception.js +4 -4
- package/dist/cjs/infrastructure/exceptions/kind/exception-classifier.d.ts +4 -0
- package/dist/cjs/infrastructure/exceptions/kind/exception-classifier.js +34 -0
- package/dist/cjs/infrastructure/exceptions/kind/exception-kind.d.ts +9 -0
- package/dist/cjs/infrastructure/exceptions/kind/exception-kind.js +13 -0
- package/dist/cjs/{exceptions/infrastructure → infrastructure/exceptions}/unknown-event.exception.js +4 -4
- package/dist/cjs/infrastructure/index.d.ts +7 -2
- package/dist/cjs/infrastructure/index.js +15 -3
- package/dist/cjs/infrastructure/logging/console-logger.js +2 -2
- package/dist/{esm → cjs/shared}/exceptions/abstract.exception.d.ts +6 -4
- package/dist/cjs/{exceptions → shared/exceptions}/abstract.exception.js +9 -16
- package/dist/cjs/shared/index.d.ts +8 -0
- package/dist/cjs/shared/index.js +13 -0
- package/dist/cjs/shared/issue-collection-error.d.ts +9 -0
- package/dist/cjs/shared/issue-collection-error.js +11 -0
- package/dist/cjs/shared/issue-collector.d.ts +8 -0
- package/dist/cjs/shared/issue-collector.js +41 -0
- package/dist/esm/application/event/listens-to.js +1 -1
- package/dist/esm/{exceptions/application → application/exceptions}/aggregate-not-found.exception.d.ts +1 -1
- package/dist/esm/application/exceptions/aggregate-not-found.exception.js +13 -0
- package/dist/esm/application/exceptions/application-exception-code.d.ts +7 -0
- package/dist/esm/application/exceptions/application-exception-code.js +8 -0
- package/dist/esm/application/exceptions/application.exception.d.ts +6 -0
- package/dist/esm/application/exceptions/application.exception.js +12 -0
- package/dist/esm/{exceptions/application → application/exceptions}/concurrency.exception.d.ts +1 -1
- package/dist/esm/{exceptions/application → application/exceptions}/concurrency.exception.js +4 -4
- package/dist/esm/{exceptions/application → application/exceptions}/not-allowed.exception.d.ts +1 -1
- package/dist/esm/application/exceptions/not-allowed.exception.js +13 -0
- package/dist/esm/application/exceptions/unexpected-error.exception.d.ts +5 -0
- package/dist/esm/application/exceptions/unexpected-error.exception.js +13 -0
- package/dist/esm/application/index.d.ts +7 -0
- package/dist/esm/application/index.js +7 -0
- package/dist/esm/application/use-case/use-case.js +3 -2
- package/dist/{cjs/domain/type/value-objects/value-objects.d.ts → esm/application/value-object-builder/value-object-builder.d.ts} +3 -3
- package/dist/esm/application/value-object-builder/value-object-builder.js +47 -0
- package/dist/esm/domain/aggregate/aggregate-root.d.ts +0 -5
- package/dist/esm/domain/aggregate/aggregate-root.js +4 -20
- package/dist/esm/domain/entity/entity.js +1 -1
- package/dist/esm/domain/event/event-base.d.ts +3 -9
- package/dist/esm/domain/event/event-base.js +8 -38
- package/dist/esm/domain/exceptions/domain-exception-code.d.ts +7 -0
- package/dist/esm/domain/exceptions/domain-exception-code.js +8 -0
- package/dist/esm/domain/exceptions/domain.exception.d.ts +6 -0
- package/dist/esm/domain/exceptions/domain.exception.js +12 -0
- package/dist/esm/domain/exceptions/invalid-event-definition.exception.d.ts +4 -0
- package/dist/esm/domain/exceptions/invalid-event-definition.exception.js +15 -0
- package/dist/esm/{exceptions/domain → domain/exceptions}/required-value.exception.js +4 -5
- package/dist/esm/{exceptions/domain → domain/exceptions}/type-primitive.exception.js +4 -5
- package/dist/esm/{exceptions/domain → domain/exceptions}/validation.exception.js +5 -5
- package/dist/esm/domain/index.d.ts +7 -0
- package/dist/esm/domain/index.js +6 -0
- package/dist/esm/domain/primitive/primitive-types.d.ts +1 -3
- package/dist/esm/domain/type/abstract-type.d.ts +6 -8
- package/dist/esm/domain/type/abstract-type.js +14 -22
- package/dist/esm/domain/type/array-type.d.ts +2 -1
- package/dist/esm/domain/type/array-type.js +16 -17
- package/dist/esm/domain/type/boolean-type.js +1 -1
- package/dist/esm/domain/type/composite/composite-brand.d.ts +4 -0
- package/dist/esm/domain/type/composite/composite-brand.js +11 -0
- package/dist/esm/domain/type/composite/composite-field.d.ts +7 -8
- package/dist/esm/domain/type/composite/composite-field.js +69 -46
- package/dist/esm/domain/type/composite/composite-issues.d.ts +6 -0
- package/dist/esm/domain/type/composite/composite-issues.js +31 -0
- package/dist/esm/domain/type/composite/composite.js +13 -17
- package/dist/esm/domain/type/date-type.d.ts +3 -2
- package/dist/esm/domain/type/date-type.js +39 -4
- package/dist/esm/domain/type/enum-type.js +1 -1
- package/dist/esm/domain/type/id-type.d.ts +1 -1
- package/dist/esm/domain/type/id-type.js +2 -2
- package/dist/esm/domain/type/index.d.ts +2 -4
- package/dist/esm/domain/type/index.js +1 -3
- package/dist/esm/domain/type/json-type.d.ts +4 -0
- package/dist/esm/domain/type/json-type.js +32 -3
- package/dist/esm/domain/type/number-type.js +1 -1
- package/dist/esm/domain/type/required/required-mark.d.ts +0 -1
- package/dist/esm/domain/type/string-type.js +1 -1
- package/dist/esm/domain/type/uuid-type.js +1 -1
- package/dist/esm/infrastructure/event/domain-event-bus.js +5 -5
- package/dist/esm/infrastructure/event/event-registry.js +4 -4
- package/dist/esm/infrastructure/event/in-memory/emitter.js +1 -1
- package/dist/esm/infrastructure/event/in-memory/in-memory-event-channel.d.ts +1 -1
- package/dist/esm/infrastructure/event/in-memory/in-memory-event-channel.js +5 -6
- package/dist/esm/{exceptions/infrastructure → infrastructure/exceptions}/event-delivery.exception.js +4 -4
- package/dist/esm/infrastructure/exceptions/infrastructure-exception-code.d.ts +6 -0
- package/dist/esm/infrastructure/exceptions/infrastructure-exception-code.js +7 -0
- package/dist/esm/infrastructure/exceptions/infrastructure.exception.d.ts +6 -0
- package/dist/esm/infrastructure/exceptions/infrastructure.exception.js +12 -0
- package/dist/esm/{exceptions/infrastructure → infrastructure/exceptions}/internal-error.exception.d.ts +1 -1
- package/dist/esm/infrastructure/exceptions/internal-error.exception.js +13 -0
- package/dist/esm/infrastructure/exceptions/kind/exception-classifier.d.ts +4 -0
- package/dist/esm/infrastructure/exceptions/kind/exception-classifier.js +30 -0
- package/dist/esm/infrastructure/exceptions/kind/exception-kind.d.ts +9 -0
- package/dist/esm/infrastructure/exceptions/kind/exception-kind.js +10 -0
- package/dist/esm/{exceptions/infrastructure → infrastructure/exceptions}/unknown-event.exception.js +4 -4
- package/dist/esm/infrastructure/index.d.ts +7 -2
- package/dist/esm/infrastructure/index.js +7 -1
- package/dist/esm/infrastructure/logging/console-logger.js +1 -1
- package/dist/{cjs → esm/shared}/exceptions/abstract.exception.d.ts +6 -4
- package/dist/esm/{exceptions → shared/exceptions}/abstract.exception.js +9 -16
- package/dist/esm/shared/index.d.ts +8 -0
- package/dist/esm/shared/index.js +5 -0
- package/dist/esm/shared/issue-collection-error.d.ts +9 -0
- package/dist/esm/shared/issue-collection-error.js +7 -0
- package/dist/esm/shared/issue-collector.d.ts +8 -0
- package/dist/esm/shared/issue-collector.js +37 -0
- package/package.json +7 -18
- package/dist/cjs/domain/type/equality/value-equality.d.ts +0 -7
- package/dist/cjs/domain/type/equality/value-equality.js +0 -41
- package/dist/cjs/domain/type/immutable/immutable-date.d.ts +0 -4
- package/dist/cjs/domain/type/immutable/immutable-date.js +0 -37
- package/dist/cjs/domain/type/immutable/immutable.d.ts +0 -4
- package/dist/cjs/domain/type/immutable/immutable.js +0 -19
- package/dist/cjs/domain/type/value-objects/value-objects.js +0 -70
- package/dist/cjs/exceptions/application/application.exception.d.ts +0 -6
- package/dist/cjs/exceptions/application/application.exception.js +0 -17
- package/dist/cjs/exceptions/domain/domain.exception.d.ts +0 -6
- package/dist/cjs/exceptions/domain/domain.exception.js +0 -17
- package/dist/cjs/exceptions/exception-code.d.ts +0 -15
- package/dist/cjs/exceptions/exception-code.js +0 -19
- package/dist/cjs/exceptions/index.d.ts +0 -14
- package/dist/cjs/exceptions/index.js +0 -30
- package/dist/cjs/exceptions/infrastructure/infrastructure.exception.d.ts +0 -6
- package/dist/cjs/exceptions/infrastructure/infrastructure.exception.js +0 -17
- package/dist/cjs/infrastructure/http/http-error-mapper.d.ts +0 -23
- package/dist/cjs/infrastructure/http/http-error-mapper.js +0 -63
- package/dist/esm/domain/type/equality/value-equality.d.ts +0 -7
- package/dist/esm/domain/type/equality/value-equality.js +0 -37
- package/dist/esm/domain/type/immutable/immutable-date.d.ts +0 -4
- package/dist/esm/domain/type/immutable/immutable-date.js +0 -33
- package/dist/esm/domain/type/immutable/immutable.d.ts +0 -4
- package/dist/esm/domain/type/immutable/immutable.js +0 -15
- package/dist/esm/domain/type/value-objects/value-objects.js +0 -66
- package/dist/esm/exceptions/application/aggregate-not-found.exception.js +0 -13
- package/dist/esm/exceptions/application/application.exception.d.ts +0 -6
- package/dist/esm/exceptions/application/application.exception.js +0 -13
- package/dist/esm/exceptions/application/not-allowed.exception.js +0 -13
- package/dist/esm/exceptions/domain/domain.exception.d.ts +0 -6
- package/dist/esm/exceptions/domain/domain.exception.js +0 -13
- package/dist/esm/exceptions/exception-code.d.ts +0 -15
- package/dist/esm/exceptions/exception-code.js +0 -16
- package/dist/esm/exceptions/index.d.ts +0 -14
- package/dist/esm/exceptions/index.js +0 -14
- package/dist/esm/exceptions/infrastructure/infrastructure.exception.d.ts +0 -6
- package/dist/esm/exceptions/infrastructure/infrastructure.exception.js +0 -13
- package/dist/esm/exceptions/infrastructure/internal-error.exception.js +0 -13
- package/dist/esm/infrastructure/http/http-error-mapper.d.ts +0 -23
- package/dist/esm/infrastructure/http/http-error-mapper.js +0 -59
- /package/dist/cjs/{exceptions/domain → domain/exceptions}/required-value.exception.d.ts +0 -0
- /package/dist/cjs/{exceptions/domain → domain/exceptions}/type-primitive.exception.d.ts +0 -0
- /package/dist/cjs/{exceptions/domain → domain/exceptions}/validation.exception.d.ts +0 -0
- /package/dist/cjs/domain/type/required/{required.d.ts → required-type.d.ts} +0 -0
- /package/dist/cjs/domain/type/required/{required.js → required-type.js} +0 -0
- /package/dist/cjs/{exceptions/infrastructure → infrastructure/exceptions}/event-delivery.exception.d.ts +0 -0
- /package/dist/cjs/{exceptions/infrastructure → infrastructure/exceptions}/unknown-event.exception.d.ts +0 -0
- /package/dist/cjs/{exceptions → shared/exceptions}/brand/exception-brand.d.ts +0 -0
- /package/dist/cjs/{exceptions → shared/exceptions}/brand/exception-brand.js +0 -0
- /package/dist/cjs/{exceptions → shared/exceptions}/received/received-value.d.ts +0 -0
- /package/dist/cjs/{exceptions → shared/exceptions}/received/received-value.js +0 -0
- /package/dist/esm/{exceptions/domain → domain/exceptions}/required-value.exception.d.ts +0 -0
- /package/dist/esm/{exceptions/domain → domain/exceptions}/type-primitive.exception.d.ts +0 -0
- /package/dist/esm/{exceptions/domain → domain/exceptions}/validation.exception.d.ts +0 -0
- /package/dist/esm/domain/type/required/{required.d.ts → required-type.d.ts} +0 -0
- /package/dist/esm/domain/type/required/{required.js → required-type.js} +0 -0
- /package/dist/esm/{exceptions/infrastructure → infrastructure/exceptions}/event-delivery.exception.d.ts +0 -0
- /package/dist/esm/{exceptions/infrastructure → infrastructure/exceptions}/unknown-event.exception.d.ts +0 -0
- /package/dist/esm/{exceptions → shared/exceptions}/brand/exception-brand.d.ts +0 -0
- /package/dist/esm/{exceptions → shared/exceptions}/brand/exception-brand.js +0 -0
- /package/dist/esm/{exceptions → shared/exceptions}/received/received-value.d.ts +0 -0
- /package/dist/esm/{exceptions → shared/exceptions}/received/received-value.js +0 -0
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
## Eventos del stream
|
|
6
6
|
|
|
7
|
-
Cada evento es una subclase de `EventBase` con `static readonly eventName
|
|
7
|
+
Cada evento es una subclase de `EventBase` con `static readonly eventName` y, como campos `readonly` del constructor, el id del agregado y los datos primitivos que necesita, tomados de los value objects (el dinero como `{ amount, currency }`), nunca value objects: el evento no tiene métodos y se serializa tal cual (`{ ...event }`) [IDDD cap. 8].
|
|
8
8
|
|
|
9
9
|
```ts
|
|
10
10
|
import { EventBase } from '@archi-code/ddd/domain';
|
|
@@ -14,12 +14,12 @@ export class PaymentRequested extends EventBase {
|
|
|
14
14
|
static readonly eventName = 'PaymentRequested';
|
|
15
15
|
|
|
16
16
|
constructor(
|
|
17
|
-
paymentId: string,
|
|
17
|
+
readonly paymentId: string,
|
|
18
18
|
readonly orderId: string,
|
|
19
19
|
readonly amount: { amount: number; currency: string },
|
|
20
20
|
metadata?: EventMetadata,
|
|
21
21
|
) {
|
|
22
|
-
super(
|
|
22
|
+
super(metadata);
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -27,12 +27,12 @@ export class PaymentAuthorized extends EventBase {
|
|
|
27
27
|
static readonly eventName = 'PaymentAuthorized';
|
|
28
28
|
|
|
29
29
|
constructor(
|
|
30
|
-
paymentId: string,
|
|
30
|
+
readonly paymentId: string,
|
|
31
31
|
readonly authorizationCode: string,
|
|
32
32
|
readonly expiresAt: string,
|
|
33
33
|
metadata?: EventMetadata,
|
|
34
34
|
) {
|
|
35
|
-
super(
|
|
35
|
+
super(metadata);
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -40,22 +40,29 @@ export class PaymentRejected extends EventBase {
|
|
|
40
40
|
static readonly eventName = 'PaymentRejected';
|
|
41
41
|
|
|
42
42
|
constructor(
|
|
43
|
-
paymentId: string,
|
|
43
|
+
readonly paymentId: string,
|
|
44
44
|
readonly reason: string,
|
|
45
45
|
metadata?: EventMetadata,
|
|
46
46
|
) {
|
|
47
|
-
super(
|
|
47
|
+
super(metadata);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
export class PaymentCaptured extends EventBase {
|
|
52
52
|
static readonly eventName = 'PaymentCaptured';
|
|
53
|
+
|
|
54
|
+
constructor(
|
|
55
|
+
readonly paymentId: string,
|
|
56
|
+
metadata?: EventMetadata,
|
|
57
|
+
) {
|
|
58
|
+
super(metadata);
|
|
59
|
+
}
|
|
53
60
|
}
|
|
54
61
|
|
|
55
62
|
export type PaymentEvent = PaymentRequested | PaymentAuthorized | PaymentRejected | PaymentCaptured;
|
|
56
63
|
```
|
|
57
64
|
|
|
58
|
-
`EventBase` pone `
|
|
65
|
+
`EventBase` pone `eventName`, `eventId` y `occurredOn` (texto ISO en UTC, del `clock` que recibe el método del agregado); la identidad del pago es un campo más del evento (`paymentId`), declarado por cada clase. `{ ...event }` da `eventName`, `eventId`, `occurredOn` y los campos, todos datos primitivos (regla del paquete, no comprobada en ejecución): esa es la fila del stream.
|
|
59
66
|
|
|
60
67
|
## Agregado con decidir y aplicar
|
|
61
68
|
|
|
@@ -72,7 +79,7 @@ import {
|
|
|
72
79
|
Required,
|
|
73
80
|
StringType,
|
|
74
81
|
} from '@archi-code/ddd/domain';
|
|
75
|
-
import { DomainException } from '@archi-code/ddd/
|
|
82
|
+
import { DomainException } from '@archi-code/ddd/domain';
|
|
76
83
|
import { Validations } from '@archi-code/validation';
|
|
77
84
|
|
|
78
85
|
export class PaymentId extends IdType<'PaymentId'> {}
|
|
@@ -211,7 +218,7 @@ Reglas:
|
|
|
211
218
|
* `fromHistory` aplica sin `record`: reconstituir no genera eventos nuevos.
|
|
212
219
|
* 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
220
|
* 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]`
|
|
221
|
+
* `[Fuera de los libros: convención de @archi-code/ddd]` `AggregateRoot` no tiene versión, y la que recuerda un repositorio de instantáneas en su `WeakMap` 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
222
|
|
|
216
223
|
## Event store
|
|
217
224
|
|
|
@@ -227,7 +234,7 @@ CREATE TABLE event_streams (
|
|
|
227
234
|
);
|
|
228
235
|
```
|
|
229
236
|
|
|
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
|
|
237
|
+
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 la copia plana del evento (`{ ...event }`).
|
|
231
238
|
|
|
232
239
|
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
240
|
|
|
@@ -242,15 +249,15 @@ La infraestructura lo implementa: reconstruye cada fila con `EventRegistry.fromJ
|
|
|
242
249
|
|
|
243
250
|
```ts
|
|
244
251
|
import type { SerializedEvent } from '@archi-code/ddd/domain';
|
|
245
|
-
import { EventRegistry } from '@archi-code/ddd/infrastructure';
|
|
246
|
-
import { ConcurrencyException
|
|
252
|
+
import { EventRegistry, InternalErrorException } from '@archi-code/ddd/infrastructure';
|
|
253
|
+
import { ConcurrencyException } from '@archi-code/ddd/application';
|
|
247
254
|
|
|
248
255
|
export const paymentEvents = new EventRegistry<PaymentEvent>()
|
|
249
256
|
.register(
|
|
250
257
|
PaymentRequested,
|
|
251
258
|
(json) =>
|
|
252
259
|
new PaymentRequested(
|
|
253
|
-
json.
|
|
260
|
+
json.paymentId as string,
|
|
254
261
|
json.orderId as string,
|
|
255
262
|
json.amount as { amount: number; currency: string },
|
|
256
263
|
json,
|
|
@@ -260,7 +267,7 @@ export const paymentEvents = new EventRegistry<PaymentEvent>()
|
|
|
260
267
|
PaymentAuthorized,
|
|
261
268
|
(json) =>
|
|
262
269
|
new PaymentAuthorized(
|
|
263
|
-
json.
|
|
270
|
+
json.paymentId as string,
|
|
264
271
|
json.authorizationCode as string,
|
|
265
272
|
json.expiresAt as string,
|
|
266
273
|
json,
|
|
@@ -268,9 +275,9 @@ export const paymentEvents = new EventRegistry<PaymentEvent>()
|
|
|
268
275
|
)
|
|
269
276
|
.register(
|
|
270
277
|
PaymentRejected,
|
|
271
|
-
(json) => new PaymentRejected(json.
|
|
278
|
+
(json) => new PaymentRejected(json.paymentId as string, json.reason as string, json),
|
|
272
279
|
)
|
|
273
|
-
.register(PaymentCaptured, (json) => new PaymentCaptured(json.
|
|
280
|
+
.register(PaymentCaptured, (json) => new PaymentCaptured(json.paymentId as string, json));
|
|
274
281
|
|
|
275
282
|
interface SqlClient {
|
|
276
283
|
query<Row>(text: string, values: readonly unknown[]): Promise<{ rows: Row[] }>;
|
|
@@ -312,7 +319,7 @@ export class PgPaymentStream implements PaymentStream {
|
|
|
312
319
|
for (const [index, event] of changes.entries()) {
|
|
313
320
|
await client.query(
|
|
314
321
|
'INSERT INTO event_streams (stream_id, version, body) VALUES ($1, $2, $3)',
|
|
315
|
-
[payment.id.value, expected + index + 1, JSON.stringify(event
|
|
322
|
+
[payment.id.value, expected + index + 1, JSON.stringify(event)],
|
|
316
323
|
);
|
|
317
324
|
}
|
|
318
325
|
await client.query('COMMIT', []);
|
|
@@ -333,12 +340,11 @@ export class PgPaymentStream implements PaymentStream {
|
|
|
333
340
|
|
|
334
341
|
## Caso de uso y reintento
|
|
335
342
|
|
|
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` (
|
|
343
|
+
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` (`ExceptionKind.Conflict`, 409 en HTTP). 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
344
|
|
|
338
345
|
```ts
|
|
339
|
-
import { UseCase } from '@archi-code/ddd/application';
|
|
346
|
+
import { AggregateNotFoundException, ConcurrencyException, UseCase } from '@archi-code/ddd/application';
|
|
340
347
|
import type { Clock, EventBus } from '@archi-code/ddd/application';
|
|
341
|
-
import { AggregateNotFoundException, ConcurrencyException } from '@archi-code/ddd/exceptions';
|
|
342
348
|
|
|
343
349
|
export class CapturePayment extends UseCase<{ paymentId: string }, PaymentId, void> {
|
|
344
350
|
constructor(
|
|
@@ -405,7 +411,7 @@ export class InMemoryPaymentStream implements PaymentStream {
|
|
|
405
411
|
if (stream.length !== payment.streamVersion()) {
|
|
406
412
|
throw new ConcurrencyException('Payment', payment.id.value, payment.streamVersion());
|
|
407
413
|
}
|
|
408
|
-
this.streams.set(payment.id.value, [...stream, ...changes.map((event) => event
|
|
414
|
+
this.streams.set(payment.id.value, [...stream, ...changes.map((event) => ({ ...event }))]);
|
|
409
415
|
}
|
|
410
416
|
}
|
|
411
417
|
|
|
@@ -445,12 +451,11 @@ Para streams largos, guarda periódicamente el estado serializado con su versió
|
|
|
445
451
|
|
|
446
452
|
`[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
453
|
|
|
448
|
-
Con el paquete,
|
|
454
|
+
Con el paquete, los eventos no llevan número de versión: la fábrica del `EventRegistry` recibe cada fila tal como se guardó, así que el upcasting va ahí y reconoce la forma antigua por sus campos; un cambio que no se pueda leer así se publica como un evento nuevo con otro `eventName` (`PaymentRequestedV2`). Por ejemplo, si una primera forma de `PaymentRequested` guardaba `amountCents` en euros:
|
|
449
455
|
|
|
450
456
|
```ts
|
|
451
457
|
export class PaymentRequested extends EventBase {
|
|
452
458
|
static readonly eventName = 'PaymentRequested';
|
|
453
|
-
static readonly eventVersion = 2;
|
|
454
459
|
// constructor as above
|
|
455
460
|
}
|
|
456
461
|
|
|
@@ -458,10 +463,10 @@ new EventRegistry<PaymentEvent>().register(
|
|
|
458
463
|
PaymentRequested,
|
|
459
464
|
(json) =>
|
|
460
465
|
new PaymentRequested(
|
|
461
|
-
json.
|
|
466
|
+
json.paymentId as string,
|
|
462
467
|
json.orderId as string,
|
|
463
|
-
json.
|
|
464
|
-
? { amount: json.amountCents
|
|
468
|
+
typeof json.amountCents === 'number'
|
|
469
|
+
? { amount: json.amountCents, currency: 'EUR' }
|
|
465
470
|
: (json.amount as { amount: number; currency: string }),
|
|
466
471
|
json,
|
|
467
472
|
),
|
|
@@ -64,7 +64,7 @@ La implementación registra el `eventId` en `projection_inbox` y aplica el cambi
|
|
|
64
64
|
|
|
65
65
|
```ts
|
|
66
66
|
import type { EventBase } from '@archi-code/ddd/domain';
|
|
67
|
-
import { InfrastructureException } from '@archi-code/ddd/
|
|
67
|
+
import { InfrastructureException } from '@archi-code/ddd/infrastructure';
|
|
68
68
|
|
|
69
69
|
interface Sql {
|
|
70
70
|
query<Row>(text: string, values: readonly unknown[]): Promise<{ rows: Row[]; rowCount: number }>;
|
|
@@ -87,7 +87,7 @@ export class PgOrderSummaryProjection implements OrderSummaryProjection {
|
|
|
87
87
|
(order_id, customer, line_count, units, total_cents, currency, updated_at)
|
|
88
88
|
VALUES ($1, $2, $3, $4, $5, $6, $7) ON CONFLICT (order_id) DO NOTHING`,
|
|
89
89
|
[
|
|
90
|
-
event.
|
|
90
|
+
event.orderId,
|
|
91
91
|
event.customerId,
|
|
92
92
|
event.lines.length,
|
|
93
93
|
event.lines.reduce((units, line) => units + line.quantity, 0),
|
|
@@ -107,7 +107,7 @@ export class PgOrderSummaryProjection implements OrderSummaryProjection {
|
|
|
107
107
|
updated_at = GREATEST(updated_at, $4)
|
|
108
108
|
WHERE order_id = $1`,
|
|
109
109
|
[
|
|
110
|
-
event.
|
|
110
|
+
event.orderId,
|
|
111
111
|
event.quantity,
|
|
112
112
|
event.quantity * event.unitPrice.amount,
|
|
113
113
|
event.occurredOn,
|
|
@@ -115,7 +115,7 @@ export class PgOrderSummaryProjection implements OrderSummaryProjection {
|
|
|
115
115
|
);
|
|
116
116
|
if (rowCount === 0) {
|
|
117
117
|
throw new InfrastructureException(
|
|
118
|
-
`${this.table}: order ${event.
|
|
118
|
+
`${this.table}: order ${event.orderId} is not projected yet`,
|
|
119
119
|
);
|
|
120
120
|
}
|
|
121
121
|
});
|
|
@@ -149,7 +149,7 @@ export const orderEvents = new EventRegistry<OrderEvent>()
|
|
|
149
149
|
OrderPlaced,
|
|
150
150
|
(json) =>
|
|
151
151
|
new OrderPlaced(
|
|
152
|
-
json.
|
|
152
|
+
json.orderId as string,
|
|
153
153
|
json.customerId as string,
|
|
154
154
|
json.lines as OrderLineData[],
|
|
155
155
|
json.total as MoneyData,
|
|
@@ -160,7 +160,7 @@ export const orderEvents = new EventRegistry<OrderEvent>()
|
|
|
160
160
|
OrderLineAdded,
|
|
161
161
|
(json) =>
|
|
162
162
|
new OrderLineAdded(
|
|
163
|
-
json.
|
|
163
|
+
json.orderId as string,
|
|
164
164
|
json.sku as string,
|
|
165
165
|
json.quantity as number,
|
|
166
166
|
json.unitPrice as MoneyData,
|
|
@@ -220,7 +220,7 @@ export async function rebuild(
|
|
|
220
220
|
Una consulta de lectura es una interfaz de la aplicación que devuelve DTOs, implementada en infraestructura directamente sobre la base de datos:
|
|
221
221
|
|
|
222
222
|
```ts
|
|
223
|
-
import { InternalErrorException } from '@archi-code/ddd/
|
|
223
|
+
import { InternalErrorException } from '@archi-code/ddd/infrastructure';
|
|
224
224
|
|
|
225
225
|
export interface OrderSummary {
|
|
226
226
|
readonly id: string;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
[Fuera de los libros: convención de @archi-code/ddd]
|
|
10
10
|
|
|
11
|
-
* Los eventos extienden `EventBase`, declaran `static readonly eventName` con el nombre de su clase en pasado (`'OrderPlaced'`)
|
|
11
|
+
* Los eventos extienden `EventBase`, declaran `static readonly eventName` con el nombre de su clase en pasado (`'OrderPlaced'`); llaman a `super(metadata)` (con `{ clock }` dentro del agregado) y la base copia el nombre en el campo `eventName` y pone `eventId` (UUID v4) y `occurredOn` (texto ISO en UTC). Un evento es un objeto de datos primitivos sin métodos: `{ ...event }` y `JSON.stringify(event)` dan `{ eventName, eventId, occurredOn, ...campos }`. La identidad del agregado es un campo más que declara cada evento (`readonly orderId: string`). Regla, no comprobada en ejecución: cada evento declara como campos `readonly` del constructor solo los datos primitivos que necesita (texto, números finitos, booleanos, `null`, listas y objetos planos de ellos), sacados de los value objects (`.value`, el dinero como `{ amount, currency }`, las fechas en ISO), nunca value objects, `Date` ni `toPrimitives()` del agregado. Los eventos no llevan número de versión: un cambio incompatible de sus datos es un evento nuevo con otro `eventName`, o una fábrica del `EventRegistry` que lee las dos formas `[Fuera de los libros: convención de @archi-code/ddd]`.
|
|
12
12
|
* El agregado registra con `record()` (que congela el evento) y el caso de uso publica con `await this.events.publish(order.pullDomainEvents())` justo después de `await this.orders.save(order)`. La aplicación nunca abre, une ni cierra transacciones y no hay puerto para ello: cada `save` es una escritura atómica que garantiza el repositorio. Si `publish` falla después de `save`, el evento se puede perder; cuando un evento no puede perderse, el adaptador del repositorio escribe el agregado y sus eventos pendientes en la misma escritura atómica (un outbox en el mismo documento o en la misma transacción de base de datos de `save`) y un reenviador los entrega después por un `EventChannel`. Es persistencia, así que va en el repositorio, y el caso de uso no cambia. Fuera de ese caso, el repositorio no toca los eventos.
|
|
13
13
|
* La aplicación solo tiene el contrato de eventos, en `@archi-code/ddd/application`: para publicar, el puerto `EventBus` (lo único que ve el caso de uso); para escuchar, `EventListener` + `@ListensTo` (`ListensTo.subscriptionOf(listener)` da `{ eventName, consumer }`). Lo que mueve los eventos es infraestructura y lo usa solo el composition root, desde `@archi-code/ddd/infrastructure`: `DomainEventBus(channel, registry)` implementa `EventBus` sobre un `EventChannel` (con `ChannelHandler` y `ChannelSubscription`), que es lo único que implementa cada tecnología (`InMemoryEventChannel` en el paquete; un outbox o un broker en tu infraestructura). Los listeners reciben siempre el evento reconstruido desde su JSON por `EventRegistry`, cuya fábrica pasa el JSON como metadatos para conservar `eventId` y `occurredOn`.
|
|
14
14
|
* Un listener extiende `EventListener<Event>`, escucha un único evento con `@ListensTo(EventClass, { consumer })` (un nombre de consumidor estable y explícito, su identidad en el canal), se llama `<Acción>On<Evento>` y solo traduce el evento a la entrada de un caso de uso.
|
|
@@ -63,7 +63,7 @@ export class PrepareShipmentOnOrderLineAdded extends EventListener<OrderLineAdde
|
|
|
63
63
|
async handle(event: OrderLineAdded): Promise<void> {
|
|
64
64
|
await this.prepareShipment.execute({
|
|
65
65
|
eventId: event.eventId,
|
|
66
|
-
orderId: event.
|
|
66
|
+
orderId: event.orderId,
|
|
67
67
|
sku: event.sku,
|
|
68
68
|
quantity: event.quantity,
|
|
69
69
|
});
|
|
@@ -82,7 +82,7 @@ export class PrepareShipmentOnOrderLineAdded extends EventListener<OrderLineAdde
|
|
|
82
82
|
| Puede cambiar | Con el modelo | Solo con versión nueva y compatibilidad |
|
|
83
83
|
| Contenido | Lo que el modelo necesita | Lo que el contrato promete; sin datos personales innecesarios |
|
|
84
84
|
|
|
85
|
-
No publiques
|
|
85
|
+
No publiques los eventos de dominio tal cual (`{ ...event }`) hacia fuera. Traduce el evento serializado (`SerializedEvent`) al contrato publicado en el adaptador que habla con el broker, con `messageId` = `eventId` [IDDD cap. 13]; el paquete no trae esa traducción (ver "Lenguaje publicado en el adaptador del broker" en `ddd-skills/ddd-eventos-dominio/references/publicacion-ts.md`).
|
|
86
86
|
|
|
87
87
|
## Señales de alarma
|
|
88
88
|
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
Pregunta guía: ¿qué estimuló la publicación del evento? Normalmente un comando, y el evento debería llevar las propiedades que llevaba ese comando [Destilado cap. 6]. IDDD añade [IDDD cap. 8]:
|
|
22
22
|
|
|
23
23
|
* Marca de tiempo de cuándo ocurrió (`occurredOn`, que pone `EventBase`).
|
|
24
|
-
* Lo necesario para "volver a disparar" el evento: identidad del agregado (
|
|
24
|
+
* Lo necesario para "volver a disparar" el evento: identidad del agregado (un campo del payload que declara el evento, como `orderId`; `EventBase` no la pone) y de los agregados implicados.
|
|
25
25
|
* Parámetros del comando si se demuestran útiles.
|
|
26
26
|
* Valores del estado resultante que ayuden a los suscriptores.
|
|
27
27
|
* En entornos multi-tenant, siempre el `tenantId`, aunque no viniera en el comando.
|
|
@@ -51,11 +51,11 @@ export class OrderConfirmed extends EventBase {
|
|
|
51
51
|
static readonly eventName = 'OrderConfirmed';
|
|
52
52
|
|
|
53
53
|
constructor(
|
|
54
|
-
orderId: string,
|
|
54
|
+
readonly orderId: string,
|
|
55
55
|
readonly total: MoneyData,
|
|
56
56
|
metadata?: EventMetadata,
|
|
57
57
|
) {
|
|
58
|
-
super(
|
|
58
|
+
super(metadata);
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
```
|
|
@@ -71,13 +71,13 @@ private tryToConfirm(clock: { now(): Date }): void {
|
|
|
71
71
|
}
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
-
`EventBase` pone `eventId` (UUID v4) y `occurredOn` (del `clock
|
|
74
|
+
`EventBase` pone `eventName`, `eventId` (UUID v4) y `occurredOn` (texto ISO en UTC, del `clock` o de la hora del sistema), y `record()` congela el evento: inmutable y con constructor completo [IDDD cap. 8]. No generes tú el id ni la fecha de un evento nuevo; pasa `{ eventId, occurredOn }` (o el JSON entero) solo al reconstruir uno que entregó un canal. El evento ya es la forma que viaja:
|
|
75
75
|
|
|
76
76
|
```ts
|
|
77
77
|
const [confirmed] = order.pullDomainEvents();
|
|
78
|
-
confirmed
|
|
79
|
-
// { eventName: 'OrderConfirmed',
|
|
80
|
-
//
|
|
78
|
+
({ ...confirmed });
|
|
79
|
+
// { eventName: 'OrderConfirmed', eventId: '…', occurredOn: '2026-03-01T09:30:00.000Z',
|
|
80
|
+
// orderId: '9b2f6c1e-…', total: { amount: 7000, currency: 'EUR' } }
|
|
81
81
|
```
|
|
82
82
|
|
|
83
83
|
## Identidad del evento
|
|
@@ -93,7 +93,7 @@ A veces un evento no resulta de un comando sobre un agregado sino que un usuario
|
|
|
93
93
|
|
|
94
94
|
* Los eventos publicados llevan versión. Diseñados con cuidado, muchos consumidores pueden leer cualquier versión como si fuera la 1 [IDDD cap. 13].
|
|
95
95
|
* Cambios compatibles `[Fuera de los libros]`: añadir campos opcionales. Incompatibles: renombrar, quitar o cambiar el significado → nueva versión o nuevo evento, publicando ambas durante la transición.
|
|
96
|
-
* Con el paquete,
|
|
96
|
+
* Con el paquete, los eventos no llevan número de versión `[Fuera de los libros: convención de @archi-code/ddd]`. Un cambio incompatible de la forma interna se publica como un evento nuevo con otro `eventName` (`OrderCancelledV2`), o la fábrica del `EventRegistry`, que recibe cada evento guardado tal como se escribió, reconoce la forma antigua por sus campos:
|
|
97
97
|
|
|
98
98
|
```ts
|
|
99
99
|
import { EventBase } from '@archi-code/ddd/domain';
|
|
@@ -102,30 +102,29 @@ import { EventRegistry } from '@archi-code/ddd/infrastructure';
|
|
|
102
102
|
|
|
103
103
|
export class OrderCancelled extends EventBase {
|
|
104
104
|
static readonly eventName = 'OrderCancelled';
|
|
105
|
-
static readonly eventVersion = 2;
|
|
106
105
|
|
|
107
106
|
constructor(
|
|
108
|
-
orderId: string,
|
|
107
|
+
readonly orderId: string,
|
|
109
108
|
readonly reason: string,
|
|
110
109
|
readonly refund: MoneyData,
|
|
111
110
|
metadata?: EventMetadata,
|
|
112
111
|
) {
|
|
113
|
-
super(
|
|
112
|
+
super(metadata);
|
|
114
113
|
}
|
|
115
114
|
}
|
|
116
115
|
|
|
117
116
|
export const cancellations = new EventRegistry<OrderCancelled>().register(
|
|
118
117
|
OrderCancelled,
|
|
119
118
|
(json) =>
|
|
120
|
-
json.
|
|
119
|
+
typeof json.refundCents === 'number'
|
|
121
120
|
? new OrderCancelled(
|
|
122
|
-
json.
|
|
121
|
+
json.orderId as string,
|
|
123
122
|
json.reason as string,
|
|
124
|
-
{ amount: json.refundCents
|
|
123
|
+
{ amount: json.refundCents, currency: 'EUR' },
|
|
125
124
|
json,
|
|
126
125
|
)
|
|
127
|
-
: new OrderCancelled(json.
|
|
126
|
+
: new OrderCancelled(json.orderId as string, json.reason as string, json.refund as MoneyData, json),
|
|
128
127
|
);
|
|
129
128
|
```
|
|
130
129
|
|
|
131
|
-
La versión del contrato publicado a otros contextos es otra cosa: la decide el adaptador del broker, que puede seguir emitiendo la v1 del contrato aunque
|
|
130
|
+
La versión del contrato publicado a otros contextos es otra cosa: la decide el adaptador del broker, que puede seguir emitiendo la v1 del contrato aunque cambie la forma del evento interno (ver `ddd-skills/ddd-eventos-dominio/references/publicacion-ts.md`).
|
|
@@ -44,13 +44,13 @@ export class OrderPlaced extends EventBase {
|
|
|
44
44
|
static readonly eventName = 'OrderPlaced';
|
|
45
45
|
|
|
46
46
|
constructor(
|
|
47
|
-
orderId: string,
|
|
47
|
+
readonly orderId: string,
|
|
48
48
|
readonly customerId: string,
|
|
49
49
|
readonly lines: readonly OrderLineData[],
|
|
50
50
|
readonly total: MoneyData,
|
|
51
51
|
metadata?: EventMetadata,
|
|
52
52
|
) {
|
|
53
|
-
super(
|
|
53
|
+
super(metadata);
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -58,14 +58,14 @@ export class OrderLineAdded extends EventBase {
|
|
|
58
58
|
static readonly eventName = 'OrderLineAdded';
|
|
59
59
|
|
|
60
60
|
constructor(
|
|
61
|
-
orderId: string,
|
|
61
|
+
readonly orderId: string,
|
|
62
62
|
readonly sku: string,
|
|
63
63
|
readonly quantity: number,
|
|
64
64
|
readonly unitPrice: MoneyData,
|
|
65
65
|
readonly total: MoneyData,
|
|
66
66
|
metadata?: EventMetadata,
|
|
67
67
|
) {
|
|
68
|
-
super(
|
|
68
|
+
super(metadata);
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
|
|
@@ -73,11 +73,11 @@ export class OrderConfirmed extends EventBase {
|
|
|
73
73
|
static readonly eventName = 'OrderConfirmed';
|
|
74
74
|
|
|
75
75
|
constructor(
|
|
76
|
-
orderId: string,
|
|
76
|
+
readonly orderId: string,
|
|
77
77
|
readonly total: MoneyData,
|
|
78
78
|
metadata?: EventMetadata,
|
|
79
79
|
) {
|
|
80
|
-
super(
|
|
80
|
+
super(metadata);
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
|
|
@@ -154,7 +154,7 @@ export const orderEvents = new EventRegistry<OrderEvent>()
|
|
|
154
154
|
OrderPlaced,
|
|
155
155
|
(json) =>
|
|
156
156
|
new OrderPlaced(
|
|
157
|
-
json.
|
|
157
|
+
json.orderId as string,
|
|
158
158
|
json.customerId as string,
|
|
159
159
|
json.lines as OrderLineData[],
|
|
160
160
|
json.total as MoneyData,
|
|
@@ -165,7 +165,7 @@ export const orderEvents = new EventRegistry<OrderEvent>()
|
|
|
165
165
|
OrderLineAdded,
|
|
166
166
|
(json) =>
|
|
167
167
|
new OrderLineAdded(
|
|
168
|
-
json.
|
|
168
|
+
json.orderId as string,
|
|
169
169
|
json.sku as string,
|
|
170
170
|
json.quantity as number,
|
|
171
171
|
json.unitPrice as MoneyData,
|
|
@@ -175,13 +175,13 @@ export const orderEvents = new EventRegistry<OrderEvent>()
|
|
|
175
175
|
)
|
|
176
176
|
.register(
|
|
177
177
|
OrderConfirmed,
|
|
178
|
-
(json) => new OrderConfirmed(json.
|
|
178
|
+
(json) => new OrderConfirmed(json.orderId as string, json.total as MoneyData, json),
|
|
179
179
|
)
|
|
180
180
|
.register(
|
|
181
181
|
OrderCancelled,
|
|
182
182
|
(json) =>
|
|
183
183
|
new OrderCancelled(
|
|
184
|
-
json.
|
|
184
|
+
json.orderId as string,
|
|
185
185
|
json.reason as string,
|
|
186
186
|
json.reservationId as string | null,
|
|
187
187
|
json.paymentId as string | null,
|
|
@@ -192,7 +192,7 @@ export const orderEvents = new EventRegistry<OrderEvent>()
|
|
|
192
192
|
PaymentAuthorizationInsufficient,
|
|
193
193
|
(json) =>
|
|
194
194
|
new PaymentAuthorizationInsufficient(
|
|
195
|
-
json.
|
|
195
|
+
json.orderId as string,
|
|
196
196
|
json.paymentId as string,
|
|
197
197
|
json.authorized as MoneyData,
|
|
198
198
|
json.required as MoneyData,
|