evo360-types 1.3.713 → 1.3.717
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/dist/apps/evo-chat/forward/zod-schemas.d.ts +576 -0
- package/dist/apps/evo-chat/forward/zod-schemas.js +154 -0
- package/dist/apps/evo-chat/forward/zod-schemas.ts +175 -0
- package/dist/apps/evo-chat/thread-message/zod-schemas.d.ts +204 -0
- package/dist/apps/evo-chat/thread-message/zod-schemas.js +3 -0
- package/dist/apps/evo-chat/thread-message/zod-schemas.ts +3 -0
- package/dist/apps/evo-finops/zod-schemas.d.ts +2 -2
- package/dist/apps/evo-med/appointment/zod-schemas.d.ts +8 -8
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.ts +1 -0
- package/dist/types/evo-campaigns/index.d.ts +41 -0
- package/dist/types/evo-campaigns/index.ts +43 -0
- package/dist/types/evo-chat/forward/index.d.ts +168 -0
- package/dist/types/evo-chat/forward/index.js +75 -0
- package/dist/types/evo-chat/forward/index.ts +256 -0
- package/dist/types/evo-chat/index.d.ts +3 -0
- package/dist/types/evo-chat/index.js +3 -0
- package/dist/types/evo-chat/index.ts +3 -0
- package/dist/types/evo-chat/thread-message/index.d.ts +4 -0
- package/dist/types/evo-chat/thread-message/index.ts +6 -0
- package/package.json +1 -1
|
@@ -278,12 +278,12 @@ export declare const zAppointmentRescheduleSchema: z.ZodObject<{
|
|
|
278
278
|
userRef?: any;
|
|
279
279
|
external_id?: string | null | undefined;
|
|
280
280
|
user_name?: string | undefined;
|
|
281
|
+
reason?: string | undefined;
|
|
281
282
|
appointmentSource?: {
|
|
282
283
|
code: string;
|
|
283
284
|
name: string;
|
|
284
285
|
external_id?: string | null | undefined;
|
|
285
286
|
} | undefined;
|
|
286
|
-
reason?: string | undefined;
|
|
287
287
|
oldStartDate?: Date | undefined;
|
|
288
288
|
oldEndDate?: Date | undefined;
|
|
289
289
|
newStartDate?: Date | undefined;
|
|
@@ -293,12 +293,12 @@ export declare const zAppointmentRescheduleSchema: z.ZodObject<{
|
|
|
293
293
|
userRef?: any;
|
|
294
294
|
external_id?: string | null | undefined;
|
|
295
295
|
user_name?: string | undefined;
|
|
296
|
+
reason?: string | undefined;
|
|
296
297
|
appointmentSource?: {
|
|
297
298
|
code: string;
|
|
298
299
|
name: string;
|
|
299
300
|
external_id?: string | null | undefined;
|
|
300
301
|
} | undefined;
|
|
301
|
-
reason?: string | undefined;
|
|
302
302
|
oldStartDate?: unknown;
|
|
303
303
|
oldEndDate?: unknown;
|
|
304
304
|
newStartDate?: unknown;
|
|
@@ -650,12 +650,12 @@ export declare const zAppointmentSchema: z.ZodObject<{
|
|
|
650
650
|
userRef?: any;
|
|
651
651
|
external_id?: string | null | undefined;
|
|
652
652
|
user_name?: string | undefined;
|
|
653
|
+
reason?: string | undefined;
|
|
653
654
|
appointmentSource?: {
|
|
654
655
|
code: string;
|
|
655
656
|
name: string;
|
|
656
657
|
external_id?: string | null | undefined;
|
|
657
658
|
} | undefined;
|
|
658
|
-
reason?: string | undefined;
|
|
659
659
|
oldStartDate?: Date | undefined;
|
|
660
660
|
oldEndDate?: Date | undefined;
|
|
661
661
|
newStartDate?: Date | undefined;
|
|
@@ -665,12 +665,12 @@ export declare const zAppointmentSchema: z.ZodObject<{
|
|
|
665
665
|
userRef?: any;
|
|
666
666
|
external_id?: string | null | undefined;
|
|
667
667
|
user_name?: string | undefined;
|
|
668
|
+
reason?: string | undefined;
|
|
668
669
|
appointmentSource?: {
|
|
669
670
|
code: string;
|
|
670
671
|
name: string;
|
|
671
672
|
external_id?: string | null | undefined;
|
|
672
673
|
} | undefined;
|
|
673
|
-
reason?: string | undefined;
|
|
674
674
|
oldStartDate?: unknown;
|
|
675
675
|
oldEndDate?: unknown;
|
|
676
676
|
newStartDate?: unknown;
|
|
@@ -1017,12 +1017,12 @@ export declare const zAppointmentSchema: z.ZodObject<{
|
|
|
1017
1017
|
userRef?: any;
|
|
1018
1018
|
external_id?: string | null | undefined;
|
|
1019
1019
|
user_name?: string | undefined;
|
|
1020
|
+
reason?: string | undefined;
|
|
1020
1021
|
appointmentSource?: {
|
|
1021
1022
|
code: string;
|
|
1022
1023
|
name: string;
|
|
1023
1024
|
external_id?: string | null | undefined;
|
|
1024
1025
|
} | undefined;
|
|
1025
|
-
reason?: string | undefined;
|
|
1026
1026
|
oldStartDate?: Date | undefined;
|
|
1027
1027
|
oldEndDate?: Date | undefined;
|
|
1028
1028
|
newStartDate?: Date | undefined;
|
|
@@ -1032,12 +1032,12 @@ export declare const zAppointmentSchema: z.ZodObject<{
|
|
|
1032
1032
|
userRef?: any;
|
|
1033
1033
|
external_id?: string | null | undefined;
|
|
1034
1034
|
user_name?: string | undefined;
|
|
1035
|
+
reason?: string | undefined;
|
|
1035
1036
|
appointmentSource?: {
|
|
1036
1037
|
code: string;
|
|
1037
1038
|
name: string;
|
|
1038
1039
|
external_id?: string | null | undefined;
|
|
1039
1040
|
} | undefined;
|
|
1040
|
-
reason?: string | undefined;
|
|
1041
1041
|
oldStartDate?: unknown;
|
|
1042
1042
|
oldEndDate?: unknown;
|
|
1043
1043
|
newStartDate?: unknown;
|
|
@@ -1384,12 +1384,12 @@ export declare const zAppointmentSchema: z.ZodObject<{
|
|
|
1384
1384
|
userRef?: any;
|
|
1385
1385
|
external_id?: string | null | undefined;
|
|
1386
1386
|
user_name?: string | undefined;
|
|
1387
|
+
reason?: string | undefined;
|
|
1387
1388
|
appointmentSource?: {
|
|
1388
1389
|
code: string;
|
|
1389
1390
|
name: string;
|
|
1390
1391
|
external_id?: string | null | undefined;
|
|
1391
1392
|
} | undefined;
|
|
1392
|
-
reason?: string | undefined;
|
|
1393
1393
|
oldStartDate?: Date | undefined;
|
|
1394
1394
|
oldEndDate?: Date | undefined;
|
|
1395
1395
|
newStartDate?: Date | undefined;
|
|
@@ -1399,12 +1399,12 @@ export declare const zAppointmentSchema: z.ZodObject<{
|
|
|
1399
1399
|
userRef?: any;
|
|
1400
1400
|
external_id?: string | null | undefined;
|
|
1401
1401
|
user_name?: string | undefined;
|
|
1402
|
+
reason?: string | undefined;
|
|
1402
1403
|
appointmentSource?: {
|
|
1403
1404
|
code: string;
|
|
1404
1405
|
name: string;
|
|
1405
1406
|
external_id?: string | null | undefined;
|
|
1406
1407
|
} | undefined;
|
|
1407
|
-
reason?: string | undefined;
|
|
1408
1408
|
oldStartDate?: unknown;
|
|
1409
1409
|
oldEndDate?: unknown;
|
|
1410
1410
|
newStartDate?: unknown;
|
package/dist/index.d.ts
CHANGED
|
@@ -58,6 +58,7 @@ export * from "./apps/evo-chat/waba-template/zod-schemas";
|
|
|
58
58
|
export * from "./apps/evo-chat/waba-setup/zod-schemas";
|
|
59
59
|
export * from "./apps/evo-chat/ig-setup/zod-schemas";
|
|
60
60
|
export * from "./apps/evo-chat/quick-reply/zod-schemas";
|
|
61
|
+
export * from "./apps/evo-chat/forward/zod-schemas";
|
|
61
62
|
export * from "./apps/evo-hub-ia/channel/zod-schemas";
|
|
62
63
|
export * from "./apps/evo-hub-ia/v1/zod-schemas";
|
|
63
64
|
export * from "./apps/evo-hub-ia/v1/adapter-tool-registry";
|
package/dist/index.js
CHANGED
|
@@ -76,6 +76,7 @@ __exportStar(require("./apps/evo-chat/waba-template/zod-schemas"), exports);
|
|
|
76
76
|
__exportStar(require("./apps/evo-chat/waba-setup/zod-schemas"), exports);
|
|
77
77
|
__exportStar(require("./apps/evo-chat/ig-setup/zod-schemas"), exports);
|
|
78
78
|
__exportStar(require("./apps/evo-chat/quick-reply/zod-schemas"), exports);
|
|
79
|
+
__exportStar(require("./apps/evo-chat/forward/zod-schemas"), exports);
|
|
79
80
|
__exportStar(require("./apps/evo-hub-ia/channel/zod-schemas"), exports);
|
|
80
81
|
__exportStar(require("./apps/evo-hub-ia/v1/zod-schemas"), exports);
|
|
81
82
|
__exportStar(require("./apps/evo-hub-ia/v1/adapter-tool-registry"), exports);
|
package/dist/index.ts
CHANGED
|
@@ -61,6 +61,7 @@ export * from "./apps/evo-chat/waba-template/zod-schemas";
|
|
|
61
61
|
export * from "./apps/evo-chat/waba-setup/zod-schemas";
|
|
62
62
|
export * from "./apps/evo-chat/ig-setup/zod-schemas";
|
|
63
63
|
export * from "./apps/evo-chat/quick-reply/zod-schemas";
|
|
64
|
+
export * from "./apps/evo-chat/forward/zod-schemas";
|
|
64
65
|
export * from "./apps/evo-hub-ia/channel/zod-schemas";
|
|
65
66
|
export * from "./apps/evo-hub-ia/v1/zod-schemas";
|
|
66
67
|
export * from "./apps/evo-hub-ia/v1/adapter-tool-registry";
|
|
@@ -227,7 +227,18 @@ export interface ICampaignChannelCounters {
|
|
|
227
227
|
failed?: number;
|
|
228
228
|
clicked?: number;
|
|
229
229
|
replied?: number;
|
|
230
|
+
/**
|
|
231
|
+
* Ticket outcome of sends whose policy asked to close the ticket (F6). Recorded by
|
|
232
|
+
* the hub-omni at the moment it decides. `kept_open` is the RULE (patient already had
|
|
233
|
+
* an open ticket — the campaign never ends a live attendance); `close_failed` is a
|
|
234
|
+
* defect (close attempted, did not happen).
|
|
235
|
+
*/
|
|
236
|
+
ticket_closed?: number;
|
|
237
|
+
ticket_kept_open?: number;
|
|
238
|
+
ticket_close_failed?: number;
|
|
230
239
|
}
|
|
240
|
+
/** What happened to the ticket of a campaign send that asked to close it (F6). */
|
|
241
|
+
export type CampaignTicketOutcome = "closed" | "kept_open" | "close_failed";
|
|
231
242
|
export interface ICampaignCounters {
|
|
232
243
|
raw?: number;
|
|
233
244
|
unique?: number;
|
|
@@ -330,6 +341,26 @@ export interface ICampaign extends IFireDoc {
|
|
|
330
341
|
finished_at?: Date | null;
|
|
331
342
|
cancel_reason?: string | null;
|
|
332
343
|
error_reason?: string | null;
|
|
344
|
+
/**
|
|
345
|
+
* Why the campaign is paused, when the SYSTEM paused it (F6 circuit breaker).
|
|
346
|
+
* `null`/absent on an operator pause and cleared on resume — its presence is what
|
|
347
|
+
* tells the screen "the platform stopped this, here is the cause".
|
|
348
|
+
*/
|
|
349
|
+
pause_reason?: ICampaignPauseReason | null;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* System pause (F6). A provider error that fails EVERY recipient the same way
|
|
353
|
+
* (account payment, account restricted, template paused/disabled, broken media)
|
|
354
|
+
* stops the dispatch instead of burning the rest of the list.
|
|
355
|
+
*/
|
|
356
|
+
export interface ICampaignPauseReason {
|
|
357
|
+
kind: "provider_systemic_error";
|
|
358
|
+
channel: CampaignChannel;
|
|
359
|
+
error_code: string;
|
|
360
|
+
error_message?: string | null;
|
|
361
|
+
/** Recipient whose failure tripped the breaker — the operator can open it. */
|
|
362
|
+
recipient_id?: string | null;
|
|
363
|
+
at: Date;
|
|
333
364
|
}
|
|
334
365
|
export type CampaignBucketSourceType = "leads" | "patients" | "appointments" | "csv";
|
|
335
366
|
export interface ICampaignBucketCsvFile {
|
|
@@ -417,6 +448,16 @@ export interface ICampaignRecipientChannelState {
|
|
|
417
448
|
failed_at?: Date | null;
|
|
418
449
|
/** Provider error text that accompanies `failed_at`. */
|
|
419
450
|
error?: string | null;
|
|
451
|
+
/**
|
|
452
|
+
* Provider error CODE that accompanies `failed_at` (F6). Kept apart from `error`
|
|
453
|
+
* because the code is what the operator-facing breakdown groups by and what the
|
|
454
|
+
* circuit breaker decides on; parsing it back out of the text would be guessing.
|
|
455
|
+
* String, not number: providers other than Meta do not promise numeric codes.
|
|
456
|
+
*/
|
|
457
|
+
error_code?: string | null;
|
|
458
|
+
/** Ticket outcome when the policy asked to close it (F6) — see ICampaignChannelCounters. */
|
|
459
|
+
ticket_outcome?: CampaignTicketOutcome | null;
|
|
460
|
+
ticket_id?: string | null;
|
|
420
461
|
}
|
|
421
462
|
/**
|
|
422
463
|
* Why a recipient was kept out. Closed union: every value here HAS a writer in
|
|
@@ -304,8 +304,20 @@ export interface ICampaignChannelCounters {
|
|
|
304
304
|
failed?: number;
|
|
305
305
|
clicked?: number;
|
|
306
306
|
replied?: number;
|
|
307
|
+
/**
|
|
308
|
+
* Ticket outcome of sends whose policy asked to close the ticket (F6). Recorded by
|
|
309
|
+
* the hub-omni at the moment it decides. `kept_open` is the RULE (patient already had
|
|
310
|
+
* an open ticket — the campaign never ends a live attendance); `close_failed` is a
|
|
311
|
+
* defect (close attempted, did not happen).
|
|
312
|
+
*/
|
|
313
|
+
ticket_closed?: number;
|
|
314
|
+
ticket_kept_open?: number;
|
|
315
|
+
ticket_close_failed?: number;
|
|
307
316
|
}
|
|
308
317
|
|
|
318
|
+
/** What happened to the ticket of a campaign send that asked to close it (F6). */
|
|
319
|
+
export type CampaignTicketOutcome = "closed" | "kept_open" | "close_failed";
|
|
320
|
+
|
|
309
321
|
export interface ICampaignCounters {
|
|
310
322
|
raw?: number;
|
|
311
323
|
unique?: number;
|
|
@@ -422,6 +434,27 @@ export interface ICampaign extends IFireDoc {
|
|
|
422
434
|
finished_at?: Date | null;
|
|
423
435
|
cancel_reason?: string | null;
|
|
424
436
|
error_reason?: string | null;
|
|
437
|
+
/**
|
|
438
|
+
* Why the campaign is paused, when the SYSTEM paused it (F6 circuit breaker).
|
|
439
|
+
* `null`/absent on an operator pause and cleared on resume — its presence is what
|
|
440
|
+
* tells the screen "the platform stopped this, here is the cause".
|
|
441
|
+
*/
|
|
442
|
+
pause_reason?: ICampaignPauseReason | null;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* System pause (F6). A provider error that fails EVERY recipient the same way
|
|
447
|
+
* (account payment, account restricted, template paused/disabled, broken media)
|
|
448
|
+
* stops the dispatch instead of burning the rest of the list.
|
|
449
|
+
*/
|
|
450
|
+
export interface ICampaignPauseReason {
|
|
451
|
+
kind: "provider_systemic_error";
|
|
452
|
+
channel: CampaignChannel;
|
|
453
|
+
error_code: string;
|
|
454
|
+
error_message?: string | null;
|
|
455
|
+
/** Recipient whose failure tripped the breaker — the operator can open it. */
|
|
456
|
+
recipient_id?: string | null;
|
|
457
|
+
at: Date;
|
|
425
458
|
}
|
|
426
459
|
|
|
427
460
|
// ----- Bucket ---------------------------------------------------------------
|
|
@@ -550,6 +583,16 @@ export interface ICampaignRecipientChannelState {
|
|
|
550
583
|
failed_at?: Date | null;
|
|
551
584
|
/** Provider error text that accompanies `failed_at`. */
|
|
552
585
|
error?: string | null;
|
|
586
|
+
/**
|
|
587
|
+
* Provider error CODE that accompanies `failed_at` (F6). Kept apart from `error`
|
|
588
|
+
* because the code is what the operator-facing breakdown groups by and what the
|
|
589
|
+
* circuit breaker decides on; parsing it back out of the text would be guessing.
|
|
590
|
+
* String, not number: providers other than Meta do not promise numeric codes.
|
|
591
|
+
*/
|
|
592
|
+
error_code?: string | null;
|
|
593
|
+
/** Ticket outcome when the policy asked to close it (F6) — see ICampaignChannelCounters. */
|
|
594
|
+
ticket_outcome?: CampaignTicketOutcome | null;
|
|
595
|
+
ticket_id?: string | null;
|
|
553
596
|
}
|
|
554
597
|
|
|
555
598
|
/**
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import type { IFireDoc } from "../../shared";
|
|
2
|
+
import type { IThreadMessage } from "../thread-message";
|
|
3
|
+
/**
|
|
4
|
+
* feat-282 — encaminhamento de mensagens no Hub Omni.
|
|
5
|
+
*
|
|
6
|
+
* A Cloud API da Meta não tem forward: o encaminhamento é nosso. Cada ação do
|
|
7
|
+
* operador vira um LOTE (`IForwardBatch`) em
|
|
8
|
+
* `tenants/{t}/apps/evo-chat/forwards/{forwardId}`, com um item por
|
|
9
|
+
* (destinatário × mensagem) na subcoleção `items/` e, por destinatário, um item
|
|
10
|
+
* `intro` opcional (texto de apresentação). Cada entrega é uma mensagem NORMAL de
|
|
11
|
+
* saída na thread de destino, com o bloco `forward` (`IMessageForward`) apontando
|
|
12
|
+
* para a origem. A mensagem de origem só ganha `forward_count`.
|
|
13
|
+
*/
|
|
14
|
+
export declare const FORWARDS_COLLECTION: "forwards";
|
|
15
|
+
export declare const FORWARD_ITEMS_COLLECTION: "items";
|
|
16
|
+
/** Tetos do lote (plan.md D6). Constantes de plataforma, sem config por tenant. */
|
|
17
|
+
export declare const FORWARD_MAX_MESSAGES = 20;
|
|
18
|
+
export declare const FORWARD_MAX_RECIPIENTS = 10;
|
|
19
|
+
export declare const FORWARD_INTRO_MAX_CHARS = 1000;
|
|
20
|
+
/** Lote `running` sem atualização há mais que isto é mostrado como interrompido. */
|
|
21
|
+
export declare const FORWARD_STALE_AFTER_MS: number;
|
|
22
|
+
/** Evento de timeline gravado na thread de ORIGEM ao criar o lote. */
|
|
23
|
+
export declare const FORWARD_TIMELINE_EVENT_TYPE: "messages_forwarded";
|
|
24
|
+
export type ForwardBatchStatus = "running" | "done" | "done_with_failures";
|
|
25
|
+
export type ForwardItemStatus = "pending" | "sending" | "sent" | "failed" | "skipped";
|
|
26
|
+
/** Motivos decididos na pré-validação (item nasce `skipped`, nenhuma chamada ao provedor). */
|
|
27
|
+
export type ForwardSkipReason = "window_closed" | "type_not_supported" | "media_too_large" | "media_unavailable" | "channel_not_supported";
|
|
28
|
+
/** Motivos de falha no envio (item passou por `sending`). */
|
|
29
|
+
export type ForwardFailReason = "provider_error" | "window_closed" | "send_budget_exceeded" | "interrupted";
|
|
30
|
+
export type ForwardItemReason = ForwardSkipReason | ForwardFailReason;
|
|
31
|
+
export type ForwardContentKind = "text" | "image" | "video" | "audio" | "document";
|
|
32
|
+
/** Canais aceitos como DESTINO na F1. E-mail e SMS ficam para a F2. */
|
|
33
|
+
export type ForwardDestinationKind = "whatsapp" | "instagram";
|
|
34
|
+
export type ForwardRecipientProvider = "hub-waba" | "hub-instagram";
|
|
35
|
+
export type ForwardSpecialKind = "doctor" | "secretary" | "employee";
|
|
36
|
+
export interface IForwardActor {
|
|
37
|
+
user_id: string;
|
|
38
|
+
display_name: string;
|
|
39
|
+
}
|
|
40
|
+
export interface IForwardSource {
|
|
41
|
+
thread_id: string;
|
|
42
|
+
ticket_id: string;
|
|
43
|
+
/** Departamento do ticket de origem: é onde o ticket novo do destino abre (Q4-A). */
|
|
44
|
+
department_id: string | null;
|
|
45
|
+
contact_id: string;
|
|
46
|
+
contact_name: string;
|
|
47
|
+
channel_id: string | null;
|
|
48
|
+
channel_type: string | null;
|
|
49
|
+
}
|
|
50
|
+
export interface IForwardRecipient {
|
|
51
|
+
thread_id: string;
|
|
52
|
+
contact_id: string;
|
|
53
|
+
contact_name: string;
|
|
54
|
+
channel_id: string;
|
|
55
|
+
channel_type: string;
|
|
56
|
+
provider: ForwardRecipientProvider;
|
|
57
|
+
special_kind?: ForwardSpecialKind | null;
|
|
58
|
+
}
|
|
59
|
+
export interface IForwardDispatchState {
|
|
60
|
+
claimed_at: Date;
|
|
61
|
+
finished_at?: Date | null;
|
|
62
|
+
}
|
|
63
|
+
export interface IForwardCounts {
|
|
64
|
+
total: number;
|
|
65
|
+
sent: number;
|
|
66
|
+
failed: number;
|
|
67
|
+
skipped: number;
|
|
68
|
+
}
|
|
69
|
+
export interface IForwardBatch extends IFireDoc {
|
|
70
|
+
forward_id: string;
|
|
71
|
+
tenant: string;
|
|
72
|
+
created_by: IForwardActor;
|
|
73
|
+
source: IForwardSource;
|
|
74
|
+
/** Ordem cronológica da origem (o backend ordena por `created_at`, não pelo payload). */
|
|
75
|
+
message_ids: string[];
|
|
76
|
+
intro_text: string | null;
|
|
77
|
+
recipients: IForwardRecipient[];
|
|
78
|
+
status: ForwardBatchStatus;
|
|
79
|
+
counts: IForwardCounts;
|
|
80
|
+
/** Destinatários com pelo menos um item `pending` (os que recebem mensagem PubSub). */
|
|
81
|
+
recipients_to_dispatch: number;
|
|
82
|
+
recipients_done: number;
|
|
83
|
+
/** Chave = `thread_id` do destinatário. Claim do worker contra entrega duplicada. */
|
|
84
|
+
dispatch?: Record<string, IForwardDispatchState>;
|
|
85
|
+
finished_at?: Date | null;
|
|
86
|
+
}
|
|
87
|
+
export interface IForwardItem {
|
|
88
|
+
/** `${recipient_thread_id}__${message_id}` ou `${recipient_thread_id}__intro`. */
|
|
89
|
+
item_id: string;
|
|
90
|
+
forward_id: string;
|
|
91
|
+
recipient_thread_id: string;
|
|
92
|
+
recipient_index: number;
|
|
93
|
+
/** 0 = intro; 1..N = mensagens na ordem da origem. */
|
|
94
|
+
seq: number;
|
|
95
|
+
kind: "intro" | "message";
|
|
96
|
+
message_id: string | null;
|
|
97
|
+
content_kind: ForwardContentKind;
|
|
98
|
+
status: ForwardItemStatus;
|
|
99
|
+
reason?: ForwardItemReason | null;
|
|
100
|
+
error?: string | null;
|
|
101
|
+
error_code?: number | null;
|
|
102
|
+
dest_message_id?: string | null;
|
|
103
|
+
sent_at?: Date | null;
|
|
104
|
+
updated_at?: Date;
|
|
105
|
+
}
|
|
106
|
+
export type ForwardWindowState = "open" | "human_agent" | "closed";
|
|
107
|
+
export interface IForwardPlanItem {
|
|
108
|
+
item_id: string;
|
|
109
|
+
kind: "intro" | "message";
|
|
110
|
+
message_id: string | null;
|
|
111
|
+
status: "pending" | "skipped";
|
|
112
|
+
reason?: ForwardSkipReason;
|
|
113
|
+
}
|
|
114
|
+
export interface IForwardPlanRecipient {
|
|
115
|
+
thread_id: string;
|
|
116
|
+
channel_id: string;
|
|
117
|
+
channel_type: string;
|
|
118
|
+
contact_name: string;
|
|
119
|
+
window: ForwardWindowState;
|
|
120
|
+
needs_ticket: boolean;
|
|
121
|
+
items: IForwardPlanItem[];
|
|
122
|
+
}
|
|
123
|
+
export interface IForwardPlan {
|
|
124
|
+
recipients: IForwardPlanRecipient[];
|
|
125
|
+
counts: {
|
|
126
|
+
total: number;
|
|
127
|
+
pending: number;
|
|
128
|
+
skipped: number;
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
export interface IMessageForward {
|
|
132
|
+
forward_id: string;
|
|
133
|
+
/** Ponte para o item do lote (o status-processor reflete falha assíncrona por aqui). */
|
|
134
|
+
item_id: string;
|
|
135
|
+
/** Vazio no item `intro`: o front não mostra selo quando está vazio. */
|
|
136
|
+
source_message_id: string;
|
|
137
|
+
source_thread_id: string;
|
|
138
|
+
source_ticket_id: string;
|
|
139
|
+
source_contact_id: string;
|
|
140
|
+
source_contact_name: string;
|
|
141
|
+
source_channel_type: string | null;
|
|
142
|
+
source_direction: "in" | "out";
|
|
143
|
+
source_created_at: Date;
|
|
144
|
+
forwarded_by: IForwardActor;
|
|
145
|
+
forwarded_at: Date;
|
|
146
|
+
}
|
|
147
|
+
export type ForwardableMessage = Pick<IThreadMessage, "type" | "direction" | "channel_type" | "body" | "media" | "template"> & {
|
|
148
|
+
revoked?: unknown;
|
|
149
|
+
deleted_at?: unknown;
|
|
150
|
+
};
|
|
151
|
+
export type ForwardContentResolution = {
|
|
152
|
+
ok: true;
|
|
153
|
+
kind: ForwardContentKind;
|
|
154
|
+
text?: string;
|
|
155
|
+
} | {
|
|
156
|
+
ok: false;
|
|
157
|
+
reason: ForwardSkipReason;
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Decide se uma mensagem pode ser encaminhada e como vira conteúdo no destino.
|
|
161
|
+
*
|
|
162
|
+
* `dest = null` é a checagem agnóstica do modo de seleção no front (sem canal
|
|
163
|
+
* escolhido). A regra que depende do destino é só uma: documento não vai para
|
|
164
|
+
* Instagram. O teto de tamanho NÃO fica aqui: depende do objeto no Storage.
|
|
165
|
+
*/
|
|
166
|
+
export declare function resolveForwardContent(m: ForwardableMessage, dest: ForwardDestinationKind | null): ForwardContentResolution;
|
|
167
|
+
/** Id determinístico do item: um destinatário aparece uma vez no lote, então é único. */
|
|
168
|
+
export declare function buildForwardItemId(recipientThreadId: string, messageId: string | null): string;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FORWARD_TIMELINE_EVENT_TYPE = exports.FORWARD_STALE_AFTER_MS = exports.FORWARD_INTRO_MAX_CHARS = exports.FORWARD_MAX_RECIPIENTS = exports.FORWARD_MAX_MESSAGES = exports.FORWARD_ITEMS_COLLECTION = exports.FORWARDS_COLLECTION = void 0;
|
|
4
|
+
exports.resolveForwardContent = resolveForwardContent;
|
|
5
|
+
exports.buildForwardItemId = buildForwardItemId;
|
|
6
|
+
/**
|
|
7
|
+
* feat-282 — encaminhamento de mensagens no Hub Omni.
|
|
8
|
+
*
|
|
9
|
+
* A Cloud API da Meta não tem forward: o encaminhamento é nosso. Cada ação do
|
|
10
|
+
* operador vira um LOTE (`IForwardBatch`) em
|
|
11
|
+
* `tenants/{t}/apps/evo-chat/forwards/{forwardId}`, com um item por
|
|
12
|
+
* (destinatário × mensagem) na subcoleção `items/` e, por destinatário, um item
|
|
13
|
+
* `intro` opcional (texto de apresentação). Cada entrega é uma mensagem NORMAL de
|
|
14
|
+
* saída na thread de destino, com o bloco `forward` (`IMessageForward`) apontando
|
|
15
|
+
* para a origem. A mensagem de origem só ganha `forward_count`.
|
|
16
|
+
*/
|
|
17
|
+
// ── Constants ──
|
|
18
|
+
exports.FORWARDS_COLLECTION = "forwards";
|
|
19
|
+
exports.FORWARD_ITEMS_COLLECTION = "items";
|
|
20
|
+
/** Tetos do lote (plan.md D6). Constantes de plataforma, sem config por tenant. */
|
|
21
|
+
exports.FORWARD_MAX_MESSAGES = 20;
|
|
22
|
+
exports.FORWARD_MAX_RECIPIENTS = 10;
|
|
23
|
+
exports.FORWARD_INTRO_MAX_CHARS = 1000;
|
|
24
|
+
/** Lote `running` sem atualização há mais que isto é mostrado como interrompido. */
|
|
25
|
+
exports.FORWARD_STALE_AFTER_MS = 10 * 60 * 1000;
|
|
26
|
+
/** Evento de timeline gravado na thread de ORIGEM ao criar o lote. */
|
|
27
|
+
exports.FORWARD_TIMELINE_EVENT_TYPE = "messages_forwarded";
|
|
28
|
+
const MEDIA_KINDS = new Set(["image", "video", "audio", "document"]);
|
|
29
|
+
/** Canais que não entram na F1 nem como origem (e-mail, SMS). */
|
|
30
|
+
const UNSUPPORTED_SOURCE_CHANNELS = new Set(["email", "sms"]);
|
|
31
|
+
/**
|
|
32
|
+
* Decide se uma mensagem pode ser encaminhada e como vira conteúdo no destino.
|
|
33
|
+
*
|
|
34
|
+
* `dest = null` é a checagem agnóstica do modo de seleção no front (sem canal
|
|
35
|
+
* escolhido). A regra que depende do destino é só uma: documento não vai para
|
|
36
|
+
* Instagram. O teto de tamanho NÃO fica aqui: depende do objeto no Storage.
|
|
37
|
+
*/
|
|
38
|
+
function resolveForwardContent(m, dest) {
|
|
39
|
+
const direction = String(m.direction ?? "").toLowerCase();
|
|
40
|
+
if (direction !== "in" && direction !== "out")
|
|
41
|
+
return { ok: false, reason: "type_not_supported" };
|
|
42
|
+
if (m.revoked === true)
|
|
43
|
+
return { ok: false, reason: "type_not_supported" };
|
|
44
|
+
if (m.deleted_at !== undefined && m.deleted_at !== null)
|
|
45
|
+
return { ok: false, reason: "type_not_supported" };
|
|
46
|
+
const channelType = String(m.channel_type ?? "").toLowerCase();
|
|
47
|
+
if (UNSUPPORTED_SOURCE_CHANNELS.has(channelType))
|
|
48
|
+
return { ok: false, reason: "type_not_supported" };
|
|
49
|
+
const type = String(m.type ?? "").toLowerCase();
|
|
50
|
+
if (type === "text") {
|
|
51
|
+
const text = (m.body?.text ?? "").trim();
|
|
52
|
+
if (!text)
|
|
53
|
+
return { ok: false, reason: "type_not_supported" };
|
|
54
|
+
return { ok: true, kind: "text", text };
|
|
55
|
+
}
|
|
56
|
+
if (type === "template") {
|
|
57
|
+
const text = (m.template?.rendered?.text ?? "").trim();
|
|
58
|
+
if (!text)
|
|
59
|
+
return { ok: false, reason: "type_not_supported" };
|
|
60
|
+
return { ok: true, kind: "text", text };
|
|
61
|
+
}
|
|
62
|
+
if (MEDIA_KINDS.has(type)) {
|
|
63
|
+
const uri = (m.media?.gcs_uri ?? "").trim();
|
|
64
|
+
if (!uri)
|
|
65
|
+
return { ok: false, reason: "media_unavailable" };
|
|
66
|
+
if (type === "document" && dest === "instagram")
|
|
67
|
+
return { ok: false, reason: "type_not_supported" };
|
|
68
|
+
return { ok: true, kind: type };
|
|
69
|
+
}
|
|
70
|
+
return { ok: false, reason: "type_not_supported" };
|
|
71
|
+
}
|
|
72
|
+
/** Id determinístico do item: um destinatário aparece uma vez no lote, então é único. */
|
|
73
|
+
function buildForwardItemId(recipientThreadId, messageId) {
|
|
74
|
+
return `${recipientThreadId}__${messageId ?? "intro"}`;
|
|
75
|
+
}
|