55 lines
1.5 KiB
TypeScript
55 lines
1.5 KiB
TypeScript
import { ArgumentNotProvidedException } from '../../exceptions';
|
|
import { Guard } from '../../guard';
|
|
import { v4 } from 'uuid';
|
|
import { RequestContextService } from '@libs/application/context/AppRequestContext';
|
|
|
|
type DomainEventMetadata = {
|
|
/** Timestamp when this domain event occurred */
|
|
readonly timestamp: number;
|
|
|
|
/** ID for correlation purposes (for Integration Events,logs correlation, etc).
|
|
*/
|
|
readonly correlationId: string;
|
|
|
|
/**
|
|
* Causation id used to reconstruct execution order if needed
|
|
*/
|
|
readonly causationId?: string;
|
|
|
|
/**
|
|
* User ID for debugging and logging purposes
|
|
*/
|
|
readonly userId?: string;
|
|
};
|
|
|
|
export type DomainEventProps<T> = Omit<T, 'id' | 'metadata'> & {
|
|
aggregateId: string;
|
|
metadata?: DomainEventMetadata;
|
|
};
|
|
|
|
export abstract class DomainEvent {
|
|
public readonly id: string;
|
|
|
|
/** Aggregate ID where domain event occurred */
|
|
public readonly aggregateId: string;
|
|
|
|
public readonly metadata: DomainEventMetadata;
|
|
|
|
constructor(props: DomainEventProps<unknown>) {
|
|
if (Guard.isEmpty(props)) {
|
|
throw new ArgumentNotProvidedException(
|
|
'DomainEvent props should not be empty',
|
|
);
|
|
}
|
|
this.id = v4();
|
|
this.aggregateId = props.aggregateId;
|
|
this.metadata = {
|
|
correlationId:
|
|
props?.metadata?.correlationId || RequestContextService.getRequestId(),
|
|
causationId: props?.metadata?.causationId,
|
|
timestamp: props?.metadata?.timestamp || Date.now(),
|
|
userId: props?.metadata?.userId,
|
|
};
|
|
}
|
|
}
|