@rodrigobeber/patoai-dtos 4.8.22 → 4.8.24

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.
@@ -7,7 +7,9 @@ export declare enum AlertTypeEnum {
7
7
  SCHEDULE_CANCELED = "schedule_canceled",
8
8
  DAILY_DIGEST = "daily_digest",
9
9
  HANDOFF = "handoff",
10
- FOLLOWUP_FAILURE = "followup_failure"
10
+ FOLLOWUP_FAILURE = "followup_failure",
11
+ /** Canal degradado: qualidade caindo, template pausado, tier rebaixado. */
12
+ CHANNEL_QUALITY = "channel_quality"
11
13
  }
12
14
  /** Alertas que PODEM ser entregues por WhatsApp (os demais = só e-mail). */
13
15
  export declare const WHATSAPP_ELIGIBLE_ALERTS: readonly AlertTypeEnum[];
@@ -12,6 +12,8 @@ var AlertTypeEnum;
12
12
  AlertTypeEnum["DAILY_DIGEST"] = "daily_digest";
13
13
  AlertTypeEnum["HANDOFF"] = "handoff";
14
14
  AlertTypeEnum["FOLLOWUP_FAILURE"] = "followup_failure";
15
+ /** Canal degradado: qualidade caindo, template pausado, tier rebaixado. */
16
+ AlertTypeEnum["CHANNEL_QUALITY"] = "channel_quality";
15
17
  })(AlertTypeEnum || (exports.AlertTypeEnum = AlertTypeEnum = {}));
16
18
  /** Alertas que PODEM ser entregues por WhatsApp (os demais = só e-mail). */
17
19
  exports.WHATSAPP_ELIGIBLE_ALERTS = [
@@ -30,7 +32,8 @@ exports.WHATSAPP_ELIGIBLE_ALERTS = [
30
32
  exports.DEFAULT_ENABLED_ALERTS = [
31
33
  AlertTypeEnum.WHATSAPP_HEALTH,
32
34
  AlertTypeEnum.SUBSCRIPTION,
33
- AlertTypeEnum.LOW_CREDITS
35
+ AlertTypeEnum.LOW_CREDITS,
36
+ AlertTypeEnum.CHANNEL_QUALITY
34
37
  ];
35
38
  /** Alertas que só existem/avaliam quando a crew tem agenda ativa. */
36
39
  exports.AGENDA_REQUIRED_ALERTS = [
@@ -14,4 +14,3 @@ export * from './support-insight-access.dto';
14
14
  export * from './support-agent-balance.dto';
15
15
  export * from './support-lab-session.dto';
16
16
  export * from './support-lab-onboarding.dto';
17
- export * from './lab-action-catalog';
@@ -30,4 +30,3 @@ __exportStar(require("./support-insight-access.dto"), exports);
30
30
  __exportStar(require("./support-agent-balance.dto"), exports);
31
31
  __exportStar(require("./support-lab-session.dto"), exports);
32
32
  __exportStar(require("./support-lab-onboarding.dto"), exports);
33
- __exportStar(require("./lab-action-catalog"), exports);
@@ -46,11 +46,19 @@ export interface LabAction {
46
46
  */
47
47
  impactHint?: string;
48
48
  }
49
- /** Uma linha "Antes -> Depois" já formatada em pt-BR (render 'field' e 'item'). */
49
+ /**
50
+ * Uma linha "Antes -> Depois" (render 'field' e 'item').
51
+ *
52
+ * `before`/`after` vêm FORMATADOS em pt-BR pelo support; o frontend só exibe. Quem compara para detectar
53
+ * "mudou desde a proposta" é o `beforeRaw` contra o valor cru lido da API — se os dois lados formatassem
54
+ * por conta própria, "18 segundos" × "18s" viraria um falso aviso de alteração.
55
+ */
50
56
  export interface LabProposalChangeDto {
57
+ param: string;
51
58
  label: string;
52
59
  before: string;
53
60
  after: string;
61
+ beforeRaw?: unknown;
54
62
  }
55
63
  export declare const LAB_ACTIONS: LabAction[];
56
64
  export declare function findLabAction(id: string): LabAction | undefined;
@@ -75,3 +75,173 @@ exports.LAB_ACTIONS = [
75
75
  function findLabAction(id) {
76
76
  return exports.LAB_ACTIONS.find(a => a.id === id);
77
77
  }
78
+ // ── Onda 2: os campos de Comportamento e Avançado ──────────────────────────────────────────────
79
+ // São os únicos que a Oráculo já enxerga SEM gastar uma ida de ferramenta (as duas seções estão em
80
+ // CHAT_CONFIG_SECTIONS, o núcleo que vai no prompt cacheado). Todos reeditáveis na tela.
81
+ //
82
+ // ⚠️ Os `min`/`max` aqui são a ÚNICA barreira: `PUT /agent-settings` e `PUT /advanced-settings` só checam
83
+ // permissão, não faixa. Sem eles, "espera 500 segundos" seria aceito pelo backend e o agente passaria 8
84
+ // minutos calado. Os valores espelham os inputs da tela (ResponseTimesManagement / AgentAdvancedSettings).
85
+ const COMPORTAMENTO = 'Configurações → Agente → Comportamento';
86
+ const AVANCADO = 'Configurações → Agente → Avançado';
87
+ const REEDITAVEL = (tela) => `${tela}: dá para mudar o valor de novo quando quiser.`;
88
+ /** Rótulos da tela (ResponseTimesManagement). Espelhados em `crew-config-labels.ts`, com teste travando. */
89
+ const TYPING_SPEED = [
90
+ { value: 9, label: 'Muito rápido' },
91
+ { value: 8, label: 'Robô' },
92
+ { value: 7, label: 'Humano Rápido' },
93
+ { value: 6, label: 'Humano Normal' },
94
+ { value: 5, label: 'Humano Lento' },
95
+ { value: 4, label: 'Lento' },
96
+ ];
97
+ /** Só as 3 opções que a tela OFERECE (`VISION_OPTIONS`). `both`/`text-ocr` são valores legados que ainda
98
+ * existem no banco: aparecem no "antes" de uma crew antiga, mas não podem ser propostos. */
99
+ const VISION = [
100
+ { value: 'no', label: 'Não' },
101
+ { value: 'text', label: 'Extrai significado' },
102
+ { value: 'file', label: 'Análise direta' },
103
+ ];
104
+ function toggle(id, name, title, path, summary, description) {
105
+ return {
106
+ id, op: 'update', render: 'field', title, path, summary,
107
+ reversible: 'tela', undoHint: REEDITAVEL(path),
108
+ params: [{ name, kind: 'boolean', required: true, label: title, description }],
109
+ };
110
+ }
111
+ exports.LAB_ACTIONS.push({
112
+ id: 'behavior.typingSpeed',
113
+ op: 'update', render: 'field',
114
+ title: 'Velocidade de digitação',
115
+ path: COMPORTAMENTO,
116
+ summary: 'Mudar a velocidade com que o agente "digita" a resposta.',
117
+ reversible: 'tela', undoHint: REEDITAVEL(COMPORTAMENTO),
118
+ params: [{
119
+ name: 'typingSpeed', kind: 'enum', required: true, options: TYPING_SPEED,
120
+ label: 'Velocidade de digitação',
121
+ description: 'Quanto MAIOR o número, mais rápido o agente responde (9 = quase instantâneo, 4 = bem devagar).',
122
+ }],
123
+ }, {
124
+ id: 'behavior.debounce',
125
+ op: 'update', render: 'field',
126
+ title: 'Tempo de espera antes de responder',
127
+ path: COMPORTAMENTO,
128
+ summary: 'Ajustar quantos segundos o agente espera, depois da mensagem do lead, antes de responder.',
129
+ reversible: 'tela', undoHint: REEDITAVEL(COMPORTAMENTO),
130
+ params: [{
131
+ name: 'debounce', kind: 'number', required: true, min: 8, max: 120, unit: 'segundos',
132
+ label: 'Tempo de espera antes de responder',
133
+ description: 'Segundos de espera. Serve para o lead terminar de escrever antes de o agente responder.',
134
+ }],
135
+ }, toggle('behavior.pretend', 'pretend', 'Negar que é IA', COMPORTAMENTO, 'Ligar/desligar o agente negar que é uma inteligência artificial quando perguntam.', 'Ligado = o agente nega ser IA quando o lead pergunta.'), {
136
+ id: 'advanced.window',
137
+ op: 'update', render: 'field',
138
+ title: 'Janela de mensagens para a IA',
139
+ path: AVANCADO,
140
+ summary: 'Ajustar quantas mensagens anteriores o agente enxerga ao responder.',
141
+ reversible: 'tela', undoHint: REEDITAVEL(AVANCADO),
142
+ params: [{
143
+ name: 'window', kind: 'number', required: true, min: 5, max: 80, unit: 'mensagens',
144
+ label: 'Janela de mensagens para a IA',
145
+ description: 'Quantas mensagens do histórico o agente lê. Mais mensagens = mais contexto e mais custo por resposta.',
146
+ }],
147
+ }, toggle('advanced.userInfo', 'userInfo', 'Confirmar nome do lead/cliente', AVANCADO, 'Ligar/desligar o agente confirmar o nome do lead no início da conversa.', 'Ligado = o agente confirma o nome antes de seguir.'), toggle('advanced.document', 'document', 'Capacidade de ler documentos', AVANCADO, 'Ligar/desligar a leitura de documentos (PDF etc.) enviados pelo lead.', 'Ligado = o agente lê documentos que o lead enviar.'), {
148
+ id: 'advanced.vision',
149
+ op: 'update', render: 'field',
150
+ title: 'Suporte a imagens',
151
+ path: AVANCADO,
152
+ summary: 'Mudar como o agente trata imagens enviadas pelo lead.',
153
+ reversible: 'tela', undoHint: REEDITAVEL(AVANCADO),
154
+ params: [{
155
+ name: 'vision', kind: 'enum', required: true, options: VISION,
156
+ label: 'Suporte a imagens',
157
+ description: 'Não = ignora imagens; Extrai significado = outra IA descreve a imagem; Análise direta = o próprio agente olha a imagem.',
158
+ }],
159
+ });
160
+ // ── Onda 3: Atendimento Humano, Reengajamento e Lembretes ──────────────────────────────────────
161
+ // Três áreas que a Oráculo NÃO enxerga sem abrir a seção por ferramenta (nenhuma está em
162
+ // CHAT_CONFIG_SECTIONS), mas que respondem ao que o dono mais pergunta: "por que insistiu 3 vezes?",
163
+ // "não manda mensagem de madrugada", "desliga a transferência para humano".
164
+ //
165
+ // ⚠️ NOME DO PARÂMETRO = a chave que o frontend LÊ (WebChatCrewDto / WebChatHandoffDto), não a chave do
166
+ // corpo do endpoint. O "mudou desde a proposta" compara `currentValues[param]` com `beforeRaw`, então um
167
+ // nome que não existe na leitura marcaria TODA proposta como desatualizada. Quem traduz para o corpo é o
168
+ // applier do frontend (ex.: `followUpDayStartTime` -> `dayStartTime`).
169
+ //
170
+ // ⚠️ HORÁRIO: o banco guarda UTC, a tela e o dono falam Brasília. O modelo propõe em Brasília; a
171
+ // conversão acontece UMA vez, na materialização. Errar isto desloca todo envio em 3h — e os dois lados
172
+ // continuam parecendo certos na tela.
173
+ const ATENDIMENTO_DIST = 'Configurações → Atendimento Humano → Distribuição';
174
+ const ATENDIMENTO_MSG = 'Configurações → Atendimento Humano → Mensagem ao Transferir';
175
+ const USUARIOS = 'Configurações → Usuários → Opções Gerais';
176
+ const REENGAJAMENTO = 'Configurações → Reengajamento → Opções Gerais';
177
+ const LEMBRETES = 'Configurações → Agenda → Lembretes e confirmações';
178
+ /** DISTRIBUTION_LABELS (DistributionCard). */
179
+ const DISTRIBUTION = [
180
+ { value: 'no', label: 'Nunca atribuir' },
181
+ { value: 'keep', label: 'Não atribuir, mas manter responsável' },
182
+ { value: 'rotation', label: 'Sempre em rodízio' },
183
+ { value: 'rotation-keep', label: 'Rodízio com responsável fixo' },
184
+ ];
185
+ /** FOLLOW_UP_MODE_LABELS (ReengajamentoOpcoesGeraisPage). */
186
+ const FOLLOW_UP_MODE = [
187
+ { value: 'off', label: 'Nunca fazer follow-up' },
188
+ { value: 'normal', label: 'Sim, sem repetir' },
189
+ { value: 'full', label: 'Sim, reiniciar após o lead responder' },
190
+ ];
191
+ /** REMINDER_MODE_LABELS (ReminderOptionsCard). */
192
+ const REMINDER_MODE = [
193
+ { value: 'on', label: 'Ligado' },
194
+ { value: 'off', label: 'Desligado' },
195
+ ];
196
+ // Janela comercial de envio: começo e fim mudam JUNTOS, numa única chamada de endpoint — a invariante
197
+ // "uma ação = uma chamada" continua valendo, é a ação que tem dois campos.
198
+ function timeWindow(id, prefix, title, path, summary, oQue) {
199
+ const hora = (suffix) => ({
200
+ name: `${prefix}Day${suffix}Time`,
201
+ kind: 'time', required: true,
202
+ label: `${suffix === 'Start' ? 'Enviar a partir de' : 'Enviar até'} (horário de Brasília)`,
203
+ description: `${suffix === 'Start' ? 'Hora em que o agente pode COMEÇAR' : 'Hora em que o agente PARA'} de ${oQue}, no horário de Brasília, formato HH:MM.`,
204
+ });
205
+ return {
206
+ id, op: 'update', render: 'field', title, path, summary,
207
+ reversible: 'tela', undoHint: REEDITAVEL(path),
208
+ params: [hora('Start'), hora('End')],
209
+ };
210
+ }
211
+ exports.LAB_ACTIONS.push(Object.assign(Object.assign({}, toggle('handoff.escalate', 'escalate', 'Habilitar escalonamentos', USUARIOS, 'Ligar/desligar a IA poder transferir a conversa para um atendente humano.', 'Ligado = a IA transfere para atendente humano conforme as regras de Atendimento Humano. Desligado = ela nunca transfere.')), { impactHint: 'Desligar tira do menu toda a área de Atendimento Humano.' }), toggle('handoff.message', 'active', 'Mensagem ao transferir', ATENDIMENTO_MSG, 'Ligar/desligar o aviso ao lead quando a conversa passa para um atendente humano.', 'Ligado = o lead recebe uma mensagem avisando que vai falar com uma pessoa. Desligado = a transferência é silenciosa.'), {
212
+ id: 'handoff.distribution',
213
+ op: 'update', render: 'field',
214
+ title: 'Distribuição de conversas',
215
+ path: ATENDIMENTO_DIST,
216
+ summary: 'Mudar como as conversas transferidas são atribuídas aos atendentes.',
217
+ reversible: 'tela', undoHint: REEDITAVEL(ATENDIMENTO_DIST),
218
+ params: [{
219
+ name: 'dist', kind: 'enum', required: true, options: DISTRIBUTION,
220
+ label: 'Distribuição de conversas',
221
+ description: 'Rodízio reparte as conversas entre os atendentes; "manter responsável" faz o lead voltar sempre para quem já o atendeu.',
222
+ }],
223
+ }, {
224
+ id: 'followUp.mode',
225
+ op: 'update', render: 'field',
226
+ title: 'Modo de reengajamento',
227
+ path: REENGAJAMENTO,
228
+ summary: 'Ligar/desligar o reengajamento (follow-up) ou mudar se ele reinicia quando o lead responde.',
229
+ reversible: 'tela', undoHint: REEDITAVEL(REENGAJAMENTO),
230
+ params: [{
231
+ name: 'followUp', kind: 'enum', required: true, options: FOLLOW_UP_MODE,
232
+ label: 'Modo de reengajamento',
233
+ description: 'Reengajamento é o agente voltar a falar com quem parou de responder. "Reiniciar" faz o ciclo começar de novo cada vez que o lead responde.',
234
+ }],
235
+ }, toggle('followUp.semantics', 'followUpSemantics', 'Enviar follow-ups semanticamente', REENGAJAMENTO, 'Ligar/desligar o agente escrever o follow-up na hora em vez de mandar o texto fixo.', 'Ligado = a IA escreve o follow-up a partir da conversa. Desligado = envia o texto configurado, igual para todos.'), timeWindow('followUp.window', 'followUp', 'Horário de envio do reengajamento', REENGAJAMENTO, 'Ajustar a faixa de horário em que o agente pode enviar follow-up (ex.: não mandar de madrugada).', 'mandar follow-up'), {
236
+ id: 'reminder.mode',
237
+ op: 'update', render: 'field',
238
+ title: 'Lembretes de agendamento',
239
+ path: LEMBRETES,
240
+ summary: 'Ligar/desligar os lembretes de reunião agendada.',
241
+ reversible: 'tela', undoHint: REEDITAVEL(LEMBRETES),
242
+ params: [{
243
+ name: 'reminderMode', kind: 'enum', required: true, options: REMINDER_MODE,
244
+ label: 'Lembretes de agendamento',
245
+ description: 'Chave mestra dos lembretes: desligada, nenhuma regra de lembrete dispara.',
246
+ }],
247
+ }, timeWindow('reminder.window', 'reminder', 'Horário de envio dos lembretes', LEMBRETES, 'Ajustar a faixa de horário em que os lembretes de reunião podem ser enviados.', 'mandar lembrete'));
@@ -1,7 +1,6 @@
1
1
  import { SupportMessageDto } from "./support-message.dto";
2
2
  import { SupportAgentBalanceDto } from "./support-agent-balance.dto";
3
3
  import { SupportLabPendingAnalysisDto } from "./support-lab-analyze.dto";
4
- import { LabActionRender, LabActionReversible, LabProposalChangeDto } from "./lab-action-catalog";
5
4
  export interface SupportLabFocusDto {
6
5
  idStage?: number;
7
6
  runType?: string;
@@ -19,30 +18,14 @@ export interface SupportLabAskDto {
19
18
  }
20
19
  export interface SupportLabProposalDto {
21
20
  id: string;
22
- actionId: string;
23
- render: LabActionRender;
24
- title: string;
25
- path: string;
26
- params: Record<string, unknown>;
27
- rationale: string;
28
- reversible: LabActionReversible;
29
- undoHint: string;
30
- /**
31
- * O que quebra junto se aplicar (mídia usada em roteiro, template usado em lembrete...). Calculado na
32
- * materialização, não estático: é o que o cartão do item NÃO mostra. Lista não-vazia => confirmação
33
- * digitada no diálogo.
34
- */
35
- impact?: string[];
36
- kind?: 'markdown' | 'spin-yaml';
37
- baseText?: string;
38
- proposedText?: string;
39
- changes?: LabProposalChangeDto[];
40
- /** @deprecated compat 1 deploy (frontend antigo lê estes); use `actionId` + `params`. */
41
- target?: 'context' | 'prompt';
42
- /** @deprecated compat 1 deploy; use `params.field`. */
21
+ target: 'context' | 'prompt';
43
22
  field?: 'about' | 'role' | 'audience' | 'behavior';
44
- /** @deprecated compat 1 deploy; use `params.idPrompt`. */
45
23
  idPrompt?: number;
24
+ kind: 'markdown' | 'spin-yaml';
25
+ title: string;
26
+ baseText: string;
27
+ proposedText: string;
28
+ rationale: string;
46
29
  }
47
30
  export interface SupportLabAnswerDto {
48
31
  content: string;
@@ -16,3 +16,5 @@ export * from './send-buttons.dto';
16
16
  export * from './message-status.dto';
17
17
  export * from './telegram.dto';
18
18
  export * from './whatsapp-error-code.enum';
19
+ export * from './rpc-error.dto';
20
+ export * from './waba-event.dto';
package/dist/uh/index.js CHANGED
@@ -32,3 +32,5 @@ __exportStar(require("./send-buttons.dto"), exports);
32
32
  __exportStar(require("./message-status.dto"), exports);
33
33
  __exportStar(require("./telegram.dto"), exports);
34
34
  __exportStar(require("./whatsapp-error-code.enum"), exports);
35
+ __exportStar(require("./rpc-error.dto"), exports);
36
+ __exportStar(require("./waba-event.dto"), exports);
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Erro de envio devolvido pelo patoai-uh via RabbitMQ.
3
+ *
4
+ * `RpcException(string)` já chega ao chamador como `{ status: 'error', message }` — este DTO é
5
+ * superset exato disso, então trocar a string pelo objeto não muda nada para quem só lê `message`.
6
+ * O que ele acrescenta é o `errorCode`: sem ele o consumidor não distingue um 131049 (limite do
7
+ * destinatário, basta pular o lead) de um 131048 (spam rate limit, tem que parar o canal).
8
+ */
9
+ export interface UhRpcErrorDto {
10
+ status: 'error';
11
+ message: string;
12
+ errorCode?: number;
13
+ errorSubcode?: number;
14
+ }
15
+ /**
16
+ * Normaliza o erro recebido do uh. Aceita tanto o payload novo quanto a string antiga, porque
17
+ * durante o rolling deploy os dois formatos circulam.
18
+ */
19
+ export declare function toUhError(err: any): {
20
+ message: string;
21
+ errorCode: number | null;
22
+ };
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toUhError = toUhError;
4
+ /**
5
+ * Normaliza o erro recebido do uh. Aceita tanto o payload novo quanto a string antiga, porque
6
+ * durante o rolling deploy os dois formatos circulam.
7
+ */
8
+ function toUhError(err) {
9
+ var _a, _b, _c, _d;
10
+ const payload = (_b = (_a = err === null || err === void 0 ? void 0 : err.error) !== null && _a !== void 0 ? _a : err === null || err === void 0 ? void 0 : err.response) !== null && _b !== void 0 ? _b : err;
11
+ const message = (_d = (_c = payload === null || payload === void 0 ? void 0 : payload.message) !== null && _c !== void 0 ? _c : err === null || err === void 0 ? void 0 : err.message) !== null && _d !== void 0 ? _d : 'Erro desconhecido';
12
+ const errorCode = typeof (payload === null || payload === void 0 ? void 0 : payload.errorCode) === 'number' ? payload.errorCode : null;
13
+ return { message, errorCode };
14
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Eventos de conta/qualidade que a Meta entrega por webhook na WABA — o aviso que antecede a
3
+ * punição (warning → restrição temporária → account lock → desativação).
4
+ *
5
+ * A Meta só entrega esses campos "to those subscribed": além de assinar via
6
+ * `POST /{waba_id}/subscribed_apps`, os mesmos campos precisam estar marcados no App Dashboard.
7
+ */
8
+ export declare enum WabaWebhookFieldEnum {
9
+ MESSAGES = "messages",
10
+ ACCOUNT_UPDATE = "account_update",
11
+ ACCOUNT_ALERTS = "account_alerts",
12
+ PHONE_NUMBER_QUALITY_UPDATE = "phone_number_quality_update",
13
+ PHONE_NUMBER_NAME_UPDATE = "phone_number_name_update",
14
+ ACCOUNT_REVIEW_UPDATE = "account_review_update",
15
+ MESSAGE_TEMPLATE_STATUS_UPDATE = "message_template_status_update",
16
+ MESSAGE_TEMPLATE_QUALITY_UPDATE = "message_template_quality_update",
17
+ TEMPLATE_CATEGORY_UPDATE = "template_category_update",
18
+ BUSINESS_CAPABILITY_UPDATE = "business_capability_update",
19
+ USER_PREFERENCES = "user_preferences"
20
+ }
21
+ /** Fonte única da lista assinada na Meta. Consumida pelo subscribe (crew) e pelo parser (uh). */
22
+ export declare const WABA_SUBSCRIBED_FIELDS: readonly WabaWebhookFieldEnum[];
23
+ export declare enum WabaEventSeverityEnum {
24
+ CRITICAL = "critical",
25
+ WARNING = "warning",
26
+ INFO = "info"
27
+ }
28
+ /**
29
+ * Evento normalizado pelo uh e consumido pelo crew.
30
+ *
31
+ * Viaja cru (`wabaId`/`phoneNumberId`, não `idChannel`) porque o uh não tem tabela de canal —
32
+ * a resolução canal→crew é do crew.
33
+ */
34
+ export interface WabaEventDto {
35
+ wabaId: string;
36
+ phoneNumberId?: string;
37
+ displayPhoneNumber?: string;
38
+ field: WabaWebhookFieldEnum | string;
39
+ event?: string;
40
+ severity: WabaEventSeverityEnum;
41
+ reason?: string;
42
+ /** GREEN | YELLOW | RED */
43
+ quality?: string;
44
+ /** TIER_250 | TIER_1K | TIER_10K | TIER_100K | TIER_UNLIMITED */
45
+ currentLimit?: string;
46
+ banState?: string;
47
+ /** `restriction_info[].expiration` — quando a restrição temporária expira. */
48
+ restrictedUntil?: Date;
49
+ templateName?: string;
50
+ description?: string;
51
+ at: Date;
52
+ /** `change.value` inteiro: campo novo da Meta não pode se perder por falta de mapeamento. */
53
+ raw: unknown;
54
+ }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WabaEventSeverityEnum = exports.WABA_SUBSCRIBED_FIELDS = exports.WabaWebhookFieldEnum = void 0;
4
+ /**
5
+ * Eventos de conta/qualidade que a Meta entrega por webhook na WABA — o aviso que antecede a
6
+ * punição (warning → restrição temporária → account lock → desativação).
7
+ *
8
+ * A Meta só entrega esses campos "to those subscribed": além de assinar via
9
+ * `POST /{waba_id}/subscribed_apps`, os mesmos campos precisam estar marcados no App Dashboard.
10
+ */
11
+ var WabaWebhookFieldEnum;
12
+ (function (WabaWebhookFieldEnum) {
13
+ WabaWebhookFieldEnum["MESSAGES"] = "messages";
14
+ WabaWebhookFieldEnum["ACCOUNT_UPDATE"] = "account_update";
15
+ WabaWebhookFieldEnum["ACCOUNT_ALERTS"] = "account_alerts";
16
+ WabaWebhookFieldEnum["PHONE_NUMBER_QUALITY_UPDATE"] = "phone_number_quality_update";
17
+ WabaWebhookFieldEnum["PHONE_NUMBER_NAME_UPDATE"] = "phone_number_name_update";
18
+ WabaWebhookFieldEnum["ACCOUNT_REVIEW_UPDATE"] = "account_review_update";
19
+ WabaWebhookFieldEnum["MESSAGE_TEMPLATE_STATUS_UPDATE"] = "message_template_status_update";
20
+ WabaWebhookFieldEnum["MESSAGE_TEMPLATE_QUALITY_UPDATE"] = "message_template_quality_update";
21
+ WabaWebhookFieldEnum["TEMPLATE_CATEGORY_UPDATE"] = "template_category_update";
22
+ WabaWebhookFieldEnum["BUSINESS_CAPABILITY_UPDATE"] = "business_capability_update";
23
+ WabaWebhookFieldEnum["USER_PREFERENCES"] = "user_preferences";
24
+ })(WabaWebhookFieldEnum || (exports.WabaWebhookFieldEnum = WabaWebhookFieldEnum = {}));
25
+ /** Fonte única da lista assinada na Meta. Consumida pelo subscribe (crew) e pelo parser (uh). */
26
+ exports.WABA_SUBSCRIBED_FIELDS = [
27
+ WabaWebhookFieldEnum.MESSAGES,
28
+ WabaWebhookFieldEnum.ACCOUNT_UPDATE,
29
+ WabaWebhookFieldEnum.ACCOUNT_ALERTS,
30
+ WabaWebhookFieldEnum.PHONE_NUMBER_QUALITY_UPDATE,
31
+ WabaWebhookFieldEnum.PHONE_NUMBER_NAME_UPDATE,
32
+ WabaWebhookFieldEnum.ACCOUNT_REVIEW_UPDATE,
33
+ WabaWebhookFieldEnum.MESSAGE_TEMPLATE_STATUS_UPDATE,
34
+ WabaWebhookFieldEnum.MESSAGE_TEMPLATE_QUALITY_UPDATE,
35
+ WabaWebhookFieldEnum.TEMPLATE_CATEGORY_UPDATE,
36
+ WabaWebhookFieldEnum.BUSINESS_CAPABILITY_UPDATE,
37
+ WabaWebhookFieldEnum.USER_PREFERENCES
38
+ ];
39
+ var WabaEventSeverityEnum;
40
+ (function (WabaEventSeverityEnum) {
41
+ WabaEventSeverityEnum["CRITICAL"] = "critical";
42
+ WabaEventSeverityEnum["WARNING"] = "warning";
43
+ WabaEventSeverityEnum["INFO"] = "info";
44
+ })(WabaEventSeverityEnum || (exports.WabaEventSeverityEnum = WabaEventSeverityEnum = {}));
@@ -17,7 +17,17 @@ export declare enum WhatsAppErrorCodeEnum {
17
17
  /** This message was not delivered to maintain healthy ecosystem engagement. */
18
18
  HEALTHY_ECOSYSTEM = 131049,
19
19
  /** Recipient opted out of marketing messages */
20
- MARKETING_OPT_OUT = 131050
20
+ MARKETING_OPT_OUT = 131050,
21
+ /**
22
+ * Business portfolio pacing: o portfolio esta sob revisao e a Meta derrubou o lote.
23
+ *
24
+ * A referencia de erros da Meta ainda descreve 135000 como "unknown error with your request
25
+ * parameters" — a doc de portfolio pacing e que revela o significado real (o codigo era 132015
26
+ * ate ~mai/2026 e foi trocado sem entrada no changelog). Tratar como erro de parametro leva ao
27
+ * conselho errado ("revise a sintaxe do template") e a retentativa, que a Meta pune desde
28
+ * abr/2026. Recorrente em template que ja funcionava = conta marcada: PARAR o funil.
29
+ */
30
+ PORTFOLIO_PACING = 135000
21
31
  }
22
32
  /**
23
33
  * Rejeições em que NÃO adianta reenviar para o mesmo número.
@@ -23,6 +23,16 @@ var WhatsAppErrorCodeEnum;
23
23
  WhatsAppErrorCodeEnum[WhatsAppErrorCodeEnum["HEALTHY_ECOSYSTEM"] = 131049] = "HEALTHY_ECOSYSTEM";
24
24
  /** Recipient opted out of marketing messages */
25
25
  WhatsAppErrorCodeEnum[WhatsAppErrorCodeEnum["MARKETING_OPT_OUT"] = 131050] = "MARKETING_OPT_OUT";
26
+ /**
27
+ * Business portfolio pacing: o portfolio esta sob revisao e a Meta derrubou o lote.
28
+ *
29
+ * A referencia de erros da Meta ainda descreve 135000 como "unknown error with your request
30
+ * parameters" — a doc de portfolio pacing e que revela o significado real (o codigo era 132015
31
+ * ate ~mai/2026 e foi trocado sem entrada no changelog). Tratar como erro de parametro leva ao
32
+ * conselho errado ("revise a sintaxe do template") e a retentativa, que a Meta pune desde
33
+ * abr/2026. Recorrente em template que ja funcionava = conta marcada: PARAR o funil.
34
+ */
35
+ WhatsAppErrorCodeEnum[WhatsAppErrorCodeEnum["PORTFOLIO_PACING"] = 135000] = "PORTFOLIO_PACING";
26
36
  })(WhatsAppErrorCodeEnum || (exports.WhatsAppErrorCodeEnum = WhatsAppErrorCodeEnum = {}));
27
37
  /**
28
38
  * Rejeições em que NÃO adianta reenviar para o mesmo número.
@@ -15,3 +15,17 @@ export interface WebChatChannelDto {
15
15
  bmLegacy?: boolean;
16
16
  dev?: boolean;
17
17
  }
18
+ /** Um aviso de enforcement/qualidade da Meta (alert.channel_event), para a timeline do canal. */
19
+ export interface WebChatChannelEventDto {
20
+ id: string;
21
+ field: string;
22
+ event?: string;
23
+ severity: string;
24
+ reason?: string;
25
+ quality?: string;
26
+ tier?: string;
27
+ templateName?: string;
28
+ description?: string;
29
+ restrictedUntil?: string;
30
+ eventAt: string;
31
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rodrigobeber/patoai-dtos",
3
- "version": "4.8.22",
3
+ "version": "4.8.24",
4
4
  "description": "Data Transfer Objects for PatoAI",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",