@automagik/omni 2.260907.3 → 2.260907.4
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/index.js +1 -1
- package/dist/server/index.js +154 -41
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -136390,7 +136390,7 @@ import { fileURLToPath } from "url";
|
|
|
136390
136390
|
// package.json
|
|
136391
136391
|
var package_default = {
|
|
136392
136392
|
name: "@automagik/omni",
|
|
136393
|
-
version: "2.260907.
|
|
136393
|
+
version: "2.260907.4",
|
|
136394
136394
|
repository: {
|
|
136395
136395
|
type: "git",
|
|
136396
136396
|
url: "git+https://github.com/automagik-dev/omni.git",
|
package/dist/server/index.js
CHANGED
|
@@ -250957,7 +250957,7 @@ var init_sentry_scrub = __esm(() => {
|
|
|
250957
250957
|
var require_package7 = __commonJS((exports, module) => {
|
|
250958
250958
|
module.exports = {
|
|
250959
250959
|
name: "@omni/api",
|
|
250960
|
-
version: "2.260907.
|
|
250960
|
+
version: "2.260907.4",
|
|
250961
250961
|
private: true,
|
|
250962
250962
|
type: "module",
|
|
250963
250963
|
exports: {
|
|
@@ -389339,11 +389339,23 @@ class AscFlowClient {
|
|
|
389339
389339
|
}
|
|
389340
389340
|
return response;
|
|
389341
389341
|
}
|
|
389342
|
-
rawPost(path, payload, token) {
|
|
389343
|
-
return this.rawRequest("POST", path, {}, payload, token);
|
|
389342
|
+
rawPost(path, payload, token, form = false) {
|
|
389343
|
+
return this.rawRequest("POST", path, {}, payload, token, form);
|
|
389344
389344
|
}
|
|
389345
|
-
async
|
|
389346
|
-
|
|
389345
|
+
async callForm(path, payload) {
|
|
389346
|
+
let response = await this.rawPost(path, payload, await this.getToken(), true);
|
|
389347
|
+
if (response.status === 401 && codErrorOf(response.body) === undefined) {
|
|
389348
|
+
response = await this.rawPost(path, payload, await this.getToken(true), true);
|
|
389349
|
+
}
|
|
389350
|
+
if (isPlatformOk(response))
|
|
389351
|
+
return response.body;
|
|
389352
|
+
const codError = codErrorOf(response.body);
|
|
389353
|
+
throw new AscFlowApiError(mapHttpStatusToAscFlowError(response.status, codError !== undefined), `ASC ${path} failed (HTTP ${response.status}${codError === undefined ? "" : `, cod_error ${codError}`})`, { httpStatus: response.status, operation: path, codError, raw: JSON.stringify(response.body).slice(0, 500) });
|
|
389354
|
+
}
|
|
389355
|
+
async rawRequest(method, path, query, payload, token, form = false) {
|
|
389356
|
+
const headers = {
|
|
389357
|
+
"content-type": form ? "application/x-www-form-urlencoded" : "application/json"
|
|
389358
|
+
};
|
|
389347
389359
|
if (token)
|
|
389348
389360
|
headers.authorization = `Bearer ${token}`;
|
|
389349
389361
|
const url = new URL(`${this.baseUrl}${path}`);
|
|
@@ -389354,7 +389366,7 @@ class AscFlowClient {
|
|
|
389354
389366
|
response = await fetch(url.toString(), {
|
|
389355
389367
|
method,
|
|
389356
389368
|
headers,
|
|
389357
|
-
...payload === undefined ? {} : { body: JSON.stringify(payload) },
|
|
389369
|
+
...payload === undefined ? {} : { body: form ? formEncode(payload) : JSON.stringify(payload) },
|
|
389358
389370
|
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
389359
389371
|
});
|
|
389360
389372
|
} catch (err2) {
|
|
@@ -389370,6 +389382,21 @@ class AscFlowClient {
|
|
|
389370
389382
|
return { status: response.status, body };
|
|
389371
389383
|
}
|
|
389372
389384
|
}
|
|
389385
|
+
function formEncode(payload) {
|
|
389386
|
+
const params = new URLSearchParams;
|
|
389387
|
+
const walk = (value, key) => {
|
|
389388
|
+
if (Array.isArray(value)) {
|
|
389389
|
+
value.forEach((item, i) => walk(item, `${key}[${i}]`));
|
|
389390
|
+
} else if (typeof value === "object" && value !== null) {
|
|
389391
|
+
for (const [k2, v2] of Object.entries(value))
|
|
389392
|
+
walk(v2, key ? `${key}[${k2}]` : k2);
|
|
389393
|
+
} else if (value !== undefined && value !== null) {
|
|
389394
|
+
params.set(key, String(value));
|
|
389395
|
+
}
|
|
389396
|
+
};
|
|
389397
|
+
walk(payload, "");
|
|
389398
|
+
return params.toString();
|
|
389399
|
+
}
|
|
389373
389400
|
|
|
389374
389401
|
// ../channel-asc-flow/src/utils/emoji.ts
|
|
389375
389402
|
var MARKER = /##([0-9a-f]{2,6}(?:-[0-9a-f]{2,6})*)##/gi;
|
|
@@ -389431,10 +389458,21 @@ function parseInboundTurn(body) {
|
|
|
389431
389458
|
codAtendimento,
|
|
389432
389459
|
text,
|
|
389433
389460
|
fromFallback: !typed,
|
|
389461
|
+
entradaDefasada: Boolean(typed) && Boolean(fallback) && typed !== fallback,
|
|
389434
389462
|
phone: firstString(body.phone, body.telefone),
|
|
389435
389463
|
...messageId ? { messageId } : {}
|
|
389436
389464
|
};
|
|
389437
389465
|
}
|
|
389466
|
+
async function isReenvioDoFlow(plugin2, instanceId, turn, logger5) {
|
|
389467
|
+
if (turn.entradaDefasada && plugin2.hasSeenCod(instanceId, turn.codAtendimento)) {
|
|
389468
|
+
logger5.info("[asc-flow] chatInput is behind message \u2014 the flow re-sent an old input", {
|
|
389469
|
+
instanceId,
|
|
389470
|
+
codAtendimento: turn.codAtendimento
|
|
389471
|
+
});
|
|
389472
|
+
return true;
|
|
389473
|
+
}
|
|
389474
|
+
return plugin2.isStaleFlowReplay(instanceId, turn);
|
|
389475
|
+
}
|
|
389438
389476
|
async function handleAscFlowWebhookRequest(request, plugin2, instanceId, verifyToken, dedupeCache) {
|
|
389439
389477
|
const logger5 = plugin2.getLogger();
|
|
389440
389478
|
if (request.method !== "POST") {
|
|
@@ -389485,7 +389523,7 @@ async function handleAscFlowWebhookRequest(request, plugin2, instanceId, verifyT
|
|
|
389485
389523
|
});
|
|
389486
389524
|
return pending();
|
|
389487
389525
|
}
|
|
389488
|
-
if (await plugin2
|
|
389526
|
+
if (await isReenvioDoFlow(plugin2, instanceId, turn, logger5)) {
|
|
389489
389527
|
return pending();
|
|
389490
389528
|
}
|
|
389491
389529
|
const isRedelivery = turn.messageId ? dedupeCache.isDuplicate(instanceId, turn.messageId, "asc-flow", logger5) : plugin2.isRedeliveryOfTurnInFlight(instanceId, turn);
|
|
@@ -389541,6 +389579,15 @@ function planHandoff(mode, meta, fallbackServico, logger5) {
|
|
|
389541
389579
|
}
|
|
389542
389580
|
return { transfer: { codServico, codPrioridade }, fields };
|
|
389543
389581
|
}
|
|
389582
|
+
var IDENTITY_FIELDS = [
|
|
389583
|
+
"nome_beneficiario_vq",
|
|
389584
|
+
"cpf_vq",
|
|
389585
|
+
"carteirinha_vq",
|
|
389586
|
+
"vinculo_vq",
|
|
389587
|
+
"plano_vq",
|
|
389588
|
+
"filial_vq"
|
|
389589
|
+
];
|
|
389590
|
+
var IDENTITY_MAX_LENGTH = 200;
|
|
389544
389591
|
function buildGenesysFields(read, logger5, mode) {
|
|
389545
389592
|
const fields = {};
|
|
389546
389593
|
const rawFila = read("handoffQueue", "fila_vq");
|
|
@@ -389566,6 +389613,12 @@ function buildGenesysFields(read, logger5, mode) {
|
|
|
389566
389613
|
if (motivo)
|
|
389567
389614
|
fields.motivo_transf_vq = motivo;
|
|
389568
389615
|
}
|
|
389616
|
+
for (const key of IDENTITY_FIELDS) {
|
|
389617
|
+
const raw = read(key);
|
|
389618
|
+
if (typeof raw !== "string")
|
|
389619
|
+
continue;
|
|
389620
|
+
fields[key] = raw.replace(/\s+/g, " ").trim().slice(0, IDENTITY_MAX_LENGTH);
|
|
389621
|
+
}
|
|
389569
389622
|
return fields;
|
|
389570
389623
|
}
|
|
389571
389624
|
|
|
@@ -389573,16 +389626,9 @@ function buildGenesysFields(read, logger5, mode) {
|
|
|
389573
389626
|
init_src2();
|
|
389574
389627
|
var MAX_OPTIONS = 10;
|
|
389575
389628
|
var MAX_BODY_TEXT = 1024;
|
|
389576
|
-
var
|
|
389577
|
-
var
|
|
389578
|
-
|
|
389579
|
-
const value = title.trim();
|
|
389580
|
-
if (value.length <= BUTTON_TITLE_MAX)
|
|
389581
|
-
return value;
|
|
389582
|
-
const head = value.slice(0, BUTTON_TITLE_MAX);
|
|
389583
|
-
const boundary = head.lastIndexOf(" ");
|
|
389584
|
-
return (boundary >= 8 ? head.slice(0, boundary) : head).trim();
|
|
389585
|
-
}
|
|
389629
|
+
var TIPO_LISTA = 1;
|
|
389630
|
+
var TIPO_BOTOES = 2;
|
|
389631
|
+
var LIST_BUTTON_LABEL = "Op\xE7\xF5es";
|
|
389586
389632
|
function foldTitle(value) {
|
|
389587
389633
|
return value.normalize("NFD").replace(/\p{Mn}/gu, "").toLocaleLowerCase().split(/\s+/).filter(Boolean).join(" ");
|
|
389588
389634
|
}
|
|
@@ -389595,37 +389641,50 @@ function titlesOf(interactive) {
|
|
|
389595
389641
|
const sections = action?.sections ?? [];
|
|
389596
389642
|
return (sections[0]?.rows ?? []).map((r) => r.title ?? "");
|
|
389597
389643
|
}
|
|
389598
|
-
function
|
|
389644
|
+
function splitBubbles(text) {
|
|
389645
|
+
return text.trim().split(/\n\s*\n/).map((b2) => b2.trim()).filter(Boolean);
|
|
389646
|
+
}
|
|
389647
|
+
function buildInteractive(body, buttons, listOptions = {}) {
|
|
389599
389648
|
const trimmed = body.trim();
|
|
389600
389649
|
if (!trimmed || trimmed.length > MAX_BODY_TEXT)
|
|
389601
389650
|
return null;
|
|
389602
389651
|
const replyButtons = (buttons ?? []).filter((b2) => !b2.url && b2.text?.trim());
|
|
389603
389652
|
if (replyButtons.length === 0 || replyButtons.length > MAX_OPTIONS)
|
|
389604
389653
|
return null;
|
|
389605
|
-
const plan = planInteractive(trimmed, replyButtons,
|
|
389654
|
+
const plan = planInteractive(trimmed, replyButtons, LIST_BUTTON_LABEL, listOptions);
|
|
389606
389655
|
if (!plan.interactive || plan.droppedRows > 0)
|
|
389607
389656
|
return null;
|
|
389608
389657
|
const type = plan.interactive.type;
|
|
389609
389658
|
if (type !== "button" && type !== "list")
|
|
389610
389659
|
return null;
|
|
389611
|
-
|
|
389612
|
-
let asButtons = type === "button";
|
|
389613
|
-
if (!asButtons && replyButtons.length <= MAX_BUTTONS) {
|
|
389614
|
-
titles = replyButtons.map((b2) => shortenTitle(b2.text ?? ""));
|
|
389615
|
-
asButtons = true;
|
|
389616
|
-
}
|
|
389660
|
+
const titles = titlesOf(plan.interactive);
|
|
389617
389661
|
if (titles.length !== replyButtons.length || titles.some((t) => !t))
|
|
389618
389662
|
return null;
|
|
389619
389663
|
if (new Set(titles.map(foldTitle)).size !== titles.length)
|
|
389620
389664
|
return null;
|
|
389665
|
+
if (type === "button") {
|
|
389666
|
+
return { tipo: TIPO_BOTOES, mensagem: trimmed, button: titles };
|
|
389667
|
+
}
|
|
389668
|
+
const action = plan.interactive.action;
|
|
389669
|
+
const sections = action?.sections ?? [];
|
|
389670
|
+
const rows = sections[0]?.rows ?? [];
|
|
389621
389671
|
return {
|
|
389622
|
-
|
|
389623
|
-
|
|
389672
|
+
tipo: TIPO_LISTA,
|
|
389673
|
+
mensagem: trimmed,
|
|
389674
|
+
list: {
|
|
389675
|
+
texto_botao: action?.button || LIST_BUTTON_LABEL,
|
|
389676
|
+
secao: [
|
|
389677
|
+
{
|
|
389678
|
+
texto: sections[0]?.title ?? "",
|
|
389679
|
+
linhas: rows.map((row) => ({
|
|
389680
|
+
texto: row.title ?? "",
|
|
389681
|
+
descricao: row.description ?? ""
|
|
389682
|
+
}))
|
|
389683
|
+
}
|
|
389684
|
+
]
|
|
389685
|
+
}
|
|
389624
389686
|
};
|
|
389625
389687
|
}
|
|
389626
|
-
function splitBubbles(text) {
|
|
389627
|
-
return text.trim().split(/\n\s*\n/).map((b2) => b2.trim()).filter(Boolean);
|
|
389628
|
-
}
|
|
389629
389688
|
|
|
389630
389689
|
// ../channel-asc-flow/src/utils/media.ts
|
|
389631
389690
|
init_src2();
|
|
@@ -389936,6 +389995,19 @@ function normalizeBaseUrl(raw) {
|
|
|
389936
389995
|
const trimmed = raw.trim().replace(/\/+$/, "");
|
|
389937
389996
|
return trimmed.endsWith(REST_PREFIX) ? trimmed : `${trimmed}${REST_PREFIX}`;
|
|
389938
389997
|
}
|
|
389998
|
+
function interactiveKindOf(params) {
|
|
389999
|
+
if (!params)
|
|
390000
|
+
return "text";
|
|
390001
|
+
return params.tipo === 2 ? "buttons" : "list";
|
|
390002
|
+
}
|
|
390003
|
+
function interactiveRowsOf(params) {
|
|
390004
|
+
if (!params)
|
|
390005
|
+
return 0;
|
|
390006
|
+
if (Array.isArray(params.button))
|
|
390007
|
+
return params.button.length;
|
|
390008
|
+
const list = params.list;
|
|
390009
|
+
return list?.secao?.[0]?.linhas?.length ?? 0;
|
|
390010
|
+
}
|
|
389939
390011
|
function buildReadyBody(turn) {
|
|
389940
390012
|
return {
|
|
389941
390013
|
pronto: 1,
|
|
@@ -389944,8 +390016,7 @@ function buildReadyBody(turn) {
|
|
|
389944
390016
|
bolhas: turn.bubbles,
|
|
389945
390017
|
fila_vq: "",
|
|
389946
390018
|
motivo_transf_vq: "",
|
|
389947
|
-
...turn.handoff ?? {}
|
|
389948
|
-
...turn.ura ?? {}
|
|
390019
|
+
...turn.handoff ?? {}
|
|
389949
390020
|
};
|
|
389950
390021
|
}
|
|
389951
390022
|
|
|
@@ -389998,7 +390069,8 @@ class AscFlowPlugin extends BaseChannelPlugin {
|
|
|
389998
390069
|
inFlight: new Map,
|
|
389999
390070
|
lastSweepAt: Date.now(),
|
|
390000
390071
|
seenCods: new Set,
|
|
390001
|
-
lastAnswered: new Map
|
|
390072
|
+
lastAnswered: new Map,
|
|
390073
|
+
destinos: new Map
|
|
390002
390074
|
});
|
|
390003
390075
|
await this.updateInstanceStatus(instanceId, config2, {
|
|
390004
390076
|
state: "connected",
|
|
@@ -390056,20 +390128,20 @@ class AscFlowPlugin extends BaseChannelPlugin {
|
|
|
390056
390128
|
const text = resolveOutboundText(turnMessage, this.logger);
|
|
390057
390129
|
const { rich, bubbles } = await this.prepareTurn(turnMessage, text);
|
|
390058
390130
|
const lastBubble = bubbles[bubbles.length - 1] ?? "";
|
|
390059
|
-
const
|
|
390131
|
+
const interativa = rich ? null : buildInteractive(lastBubble, content.buttons, listOptionsOf(content));
|
|
390060
390132
|
const { delivered } = await this.deliver(state, cod, {
|
|
390061
390133
|
text,
|
|
390062
390134
|
bubbles,
|
|
390063
390135
|
lastBubble,
|
|
390064
390136
|
rich,
|
|
390065
|
-
|
|
390137
|
+
interativa,
|
|
390066
390138
|
message: turnMessage
|
|
390067
390139
|
});
|
|
390068
390140
|
if (!delivered && !polling)
|
|
390069
390141
|
return this.refuseUndeliverable(instanceId, to, content.type);
|
|
390070
390142
|
const handoff = meta.isHandoff === true ? await this.runHandoff(state, instanceId, cod, meta, delivered ? "" : lastBubble) : null;
|
|
390071
390143
|
const handoffRefused = meta.isHandoff === true && handoff === null;
|
|
390072
|
-
this.resolveTurn(state, to, buildReadyBody({ delivered, lastBubble, bubbles, handoff
|
|
390144
|
+
this.resolveTurn(state, to, buildReadyBody({ delivered, lastBubble, bubbles, handoff }), answering, correlationId);
|
|
390073
390145
|
if (handoffRefused)
|
|
390074
390146
|
return this.refuseSend(instanceId, to, HANDOFF_REFUSED_ERROR);
|
|
390075
390147
|
if (correlationId)
|
|
@@ -390078,7 +390150,7 @@ class AscFlowPlugin extends BaseChannelPlugin {
|
|
|
390078
390150
|
await this.emitTurnSent(instanceId, turnMessage, messageId, {
|
|
390079
390151
|
cod,
|
|
390080
390152
|
bubbles: bubbles.length,
|
|
390081
|
-
|
|
390153
|
+
interativa,
|
|
390082
390154
|
delivered,
|
|
390083
390155
|
handoff: handoff !== null
|
|
390084
390156
|
});
|
|
@@ -390111,8 +390183,8 @@ class AscFlowPlugin extends BaseChannelPlugin {
|
|
|
390111
390183
|
ascFlow: {
|
|
390112
390184
|
codAtendimento: turn.cod,
|
|
390113
390185
|
bubbles: turn.bubbles,
|
|
390114
|
-
interactive: turn.
|
|
390115
|
-
|
|
390186
|
+
interactive: interactiveKindOf(turn.interativa),
|
|
390187
|
+
interactiveRows: interactiveRowsOf(turn.interativa),
|
|
390116
390188
|
viaMensagem: turn.delivered,
|
|
390117
390189
|
handoff: turn.handoff
|
|
390118
390190
|
}
|
|
@@ -390226,15 +390298,56 @@ class AscFlowPlugin extends BaseChannelPlugin {
|
|
|
390226
390298
|
const texto = turn.bubbles.length > 0 ? turn.bubbles : [OUTBOUND_MEDIA_FALLBACK_TEXT];
|
|
390227
390299
|
return { delivered: await this.pushBubbles(state, cod, texto) > 0 };
|
|
390228
390300
|
}
|
|
390229
|
-
if (turn.
|
|
390301
|
+
if (turn.interativa) {
|
|
390230
390302
|
await this.pushBubbles(state, cod, turn.bubbles.slice(0, -1));
|
|
390231
|
-
if (await this.
|
|
390303
|
+
if (await this.sendInterativa(state, cod, turn.interativa))
|
|
390232
390304
|
return { delivered: true };
|
|
390233
390305
|
return { delivered: await this.pushBubbles(state, cod, [turn.lastBubble]) > 0 };
|
|
390234
390306
|
}
|
|
390235
390307
|
const pushed = await this.pushBubbles(state, cod, turn.bubbles);
|
|
390236
390308
|
return { delivered: pushed > 0 };
|
|
390237
390309
|
}
|
|
390310
|
+
async sendInterativa(state, cod, params) {
|
|
390311
|
+
try {
|
|
390312
|
+
const destino = await this.resolveDestino(state, cod);
|
|
390313
|
+
if (!destino)
|
|
390314
|
+
return false;
|
|
390315
|
+
await state.client.callForm("/sendMsgInterativaAvancado", {
|
|
390316
|
+
cod_conta: destino.codConta,
|
|
390317
|
+
tipo_envio: 1,
|
|
390318
|
+
bol_incluir_atual: 1,
|
|
390319
|
+
contato: { telefone: destino.telefone },
|
|
390320
|
+
msg_interativa_parametros: params
|
|
390321
|
+
});
|
|
390322
|
+
return true;
|
|
390323
|
+
} catch (err2) {
|
|
390324
|
+
this.logger.warn("[asc-flow] interactive message refused \u2014 degrading to the numbered text", {
|
|
390325
|
+
cod,
|
|
390326
|
+
err: String(err2)
|
|
390327
|
+
});
|
|
390328
|
+
return false;
|
|
390329
|
+
}
|
|
390330
|
+
}
|
|
390331
|
+
async resolveDestino(state, cod) {
|
|
390332
|
+
const chave = String(cod);
|
|
390333
|
+
const cacheado = state.destinos.get(chave);
|
|
390334
|
+
if (cacheado)
|
|
390335
|
+
return cacheado;
|
|
390336
|
+
const { status, body } = await state.client.get("/atendimento", { codigo_atendimento: cod });
|
|
390337
|
+
if (status !== 200 || typeof body !== "object" || body === null)
|
|
390338
|
+
return null;
|
|
390339
|
+
const dados = body;
|
|
390340
|
+
const contato = dados.contato ?? {};
|
|
390341
|
+
const codConta = String(dados.id_conta ?? "").trim();
|
|
390342
|
+
const telefone = String(contato.telefone ?? "").trim();
|
|
390343
|
+
if (!codConta || !telefone) {
|
|
390344
|
+
this.logger.warn("[asc-flow] atendimento carries no account/phone \u2014 no interactive message for it", { cod });
|
|
390345
|
+
return null;
|
|
390346
|
+
}
|
|
390347
|
+
const destino = { codConta, telefone };
|
|
390348
|
+
state.destinos.set(chave, destino);
|
|
390349
|
+
return destino;
|
|
390350
|
+
}
|
|
390238
390351
|
async sendMensagem(state, cod, text, extra) {
|
|
390239
390352
|
try {
|
|
390240
390353
|
await state.client.call("/mensagem", {
|