xpeditis2.0/apps/backend/src/domain/entities/webhook.entity.ts
David-Henri ARNAUD c5c15eb1f9 feature phase 3
2025-10-13 17:54:32 +02:00

196 lines
3.8 KiB
TypeScript

/**
* Webhook Entity
*
* Represents a webhook subscription for external integrations
*/
export enum WebhookEvent {
BOOKING_CREATED = 'booking.created',
BOOKING_UPDATED = 'booking.updated',
BOOKING_CANCELLED = 'booking.cancelled',
BOOKING_CONFIRMED = 'booking.confirmed',
RATE_QUOTE_CREATED = 'rate_quote.created',
DOCUMENT_UPLOADED = 'document.uploaded',
ORGANIZATION_UPDATED = 'organization.updated',
USER_CREATED = 'user.created',
}
export enum WebhookStatus {
ACTIVE = 'active',
INACTIVE = 'inactive',
FAILED = 'failed',
}
interface WebhookProps {
id: string;
organizationId: string;
url: string;
events: WebhookEvent[];
secret: string;
status: WebhookStatus;
description?: string;
headers?: Record<string, string>;
retryCount: number;
lastTriggeredAt?: Date;
failureCount: number;
createdAt: Date;
updatedAt: Date;
}
export class Webhook {
private constructor(private readonly props: WebhookProps) {}
static create(
props: Omit<WebhookProps, 'id' | 'status' | 'retryCount' | 'failureCount' | 'createdAt' | 'updatedAt'> & { id: string },
): Webhook {
return new Webhook({
...props,
status: WebhookStatus.ACTIVE,
retryCount: 0,
failureCount: 0,
createdAt: new Date(),
updatedAt: new Date(),
});
}
static fromPersistence(props: WebhookProps): Webhook {
return new Webhook(props);
}
get id(): string {
return this.props.id;
}
get organizationId(): string {
return this.props.organizationId;
}
get url(): string {
return this.props.url;
}
get events(): WebhookEvent[] {
return this.props.events;
}
get secret(): string {
return this.props.secret;
}
get status(): WebhookStatus {
return this.props.status;
}
get description(): string | undefined {
return this.props.description;
}
get headers(): Record<string, string> | undefined {
return this.props.headers;
}
get retryCount(): number {
return this.props.retryCount;
}
get lastTriggeredAt(): Date | undefined {
return this.props.lastTriggeredAt;
}
get failureCount(): number {
return this.props.failureCount;
}
get createdAt(): Date {
return this.props.createdAt;
}
get updatedAt(): Date {
return this.props.updatedAt;
}
/**
* Check if webhook is active
*/
isActive(): boolean {
return this.props.status === WebhookStatus.ACTIVE;
}
/**
* Check if webhook subscribes to an event
*/
subscribesToEvent(event: WebhookEvent): boolean {
return this.props.events.includes(event);
}
/**
* Activate webhook
*/
activate(): Webhook {
return new Webhook({
...this.props,
status: WebhookStatus.ACTIVE,
updatedAt: new Date(),
});
}
/**
* Deactivate webhook
*/
deactivate(): Webhook {
return new Webhook({
...this.props,
status: WebhookStatus.INACTIVE,
updatedAt: new Date(),
});
}
/**
* Mark webhook as failed
*/
markAsFailed(): Webhook {
return new Webhook({
...this.props,
status: WebhookStatus.FAILED,
failureCount: this.props.failureCount + 1,
updatedAt: new Date(),
});
}
/**
* Record successful trigger
*/
recordTrigger(): Webhook {
return new Webhook({
...this.props,
lastTriggeredAt: new Date(),
retryCount: this.props.retryCount + 1,
failureCount: 0, // Reset failure count on success
updatedAt: new Date(),
});
}
/**
* Update webhook
*/
update(updates: {
url?: string;
events?: WebhookEvent[];
description?: string;
headers?: Record<string, string>;
}): Webhook {
return new Webhook({
...this.props,
...updates,
updatedAt: new Date(),
});
}
/**
* Convert to plain object
*/
toObject(): WebhookProps {
return { ...this.props };
}
}