Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
84 lines
3.1 KiB
TypeScript
84 lines
3.1 KiB
TypeScript
import type { Db } from '@barev/db';
|
|
import type { OrderStatus } from '@barev/core';
|
|
|
|
/** Доменные события. Воркер превращает их в уведомления на языке получателя. */
|
|
export type DomainEvent =
|
|
| { type: 'order.created'; orderId: string }
|
|
| { type: 'order.status'; orderId: string; from: OrderStatus; to: OrderStatus }
|
|
/** событие без смены статуса, например «Я на месте» */
|
|
| { type: 'order.event'; orderId: string; code: string }
|
|
| { type: 'order.rescheduled'; orderId: string }
|
|
| { type: 'order.unassigned'; orderId: string; providerId: string }
|
|
| { type: 'offer.created'; offerId: string }
|
|
| { type: 'offer.declined'; offerId: string }
|
|
| { type: 'offer.expired'; offerId: string }
|
|
| { type: 'company.order'; orderId: string; companyId: string }
|
|
| { type: 'order.reminder'; orderId: string; hours: 24 | 1 }
|
|
| { type: 'gift.activated'; clientId: string; endsAt: string }
|
|
/** оператор сменил статус шага переезда — клиенту сообщение в бота */
|
|
| { type: 'lead.step'; stepId: string }
|
|
/** оператор ответил в чате консьержа — ответ уходит в чат с ботом */
|
|
| { type: 'concierge.reply'; messageId: string }
|
|
/** оператор включил подписку по заявке из приложения */
|
|
| { type: 'subscription.activated'; subscriptionId: string }
|
|
/** уведомления операторам в рабочий бот */
|
|
| { type: 'concierge.message'; messageId: string }
|
|
| { type: 'lead.submitted'; leadId: string }
|
|
| { type: 'clientRequest.created'; requestId: string }
|
|
| { type: 'webRequest.created'; requestId: string };
|
|
|
|
export interface Notifier {
|
|
emit(event: DomainEvent): Promise<void> | void;
|
|
}
|
|
|
|
export interface Ctx {
|
|
db: Db;
|
|
notify: Notifier;
|
|
now: () => Date;
|
|
}
|
|
|
|
export const silentNotifier: Notifier = { emit: () => {} };
|
|
|
|
/** Ошибка бизнес-логики. code переводится на фронте как errors.<code>. */
|
|
export class DomainError extends Error {
|
|
constructor(
|
|
public code: DomainErrorCode,
|
|
public details?: Record<string, unknown>,
|
|
) {
|
|
super(code);
|
|
this.name = 'DomainError';
|
|
}
|
|
}
|
|
|
|
export type DomainErrorCode =
|
|
| 'NOT_FOUND'
|
|
| 'FORBIDDEN'
|
|
| 'CONSENT_REQUIRED'
|
|
| 'SERVICE_UNAVAILABLE'
|
|
| 'INVALID_PARAMS'
|
|
| 'SLOT_UNAVAILABLE'
|
|
| 'ADDRESS_REQUIRED'
|
|
| 'TRANSITION_NOT_ALLOWED'
|
|
| 'CHECKLIST_INCOMPLETE'
|
|
| 'PHOTO_REQUIRED'
|
|
| 'ESTIMATE_NOT_ACCEPTED'
|
|
| 'CANCEL_VIA_OPERATOR'
|
|
| 'RESCHEDULE_VIA_OPERATOR'
|
|
| 'AGENCY_CODE_INVALID'
|
|
| 'AGENCY_ALREADY_SET'
|
|
| 'OFFER_NOT_ACTIVE'
|
|
| 'PROVIDER_BUSY'
|
|
| 'ALREADY_ASSIGNED'
|
|
| 'INVITE_INVALID'
|
|
| 'NOT_PAID_STATE'
|
|
| 'PHONE_INVALID'
|
|
| 'CONTACT_INVALID'
|
|
| 'NAME_REQUIRED'
|
|
| 'PROVIDER_NOT_LINKED'
|
|
| 'CARD_EXPIRED'
|
|
| 'OFFER_NOT_AVAILABLE'
|
|
| 'OFFER_LIMIT_REACHED';
|
|
|
|
/** Имя очереди BullMQ, через которую API и боты передают события воркеру */
|
|
export const EVENTS_QUEUE = 'barev-events';
|