@adatechnology/meta-whatsapp-module 0.2.0 → 0.3.1
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.cjs +28 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +30 -8
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -1629,7 +1629,7 @@ declare class SessionRepository {
|
|
|
1629
1629
|
setFlowPosition(companyId: string, whatsappNumber: string, flowKey: string | null, currentNodeId: string | null): Promise<void>;
|
|
1630
1630
|
touchInbound(companyId: string, whatsappNumber: string): Promise<void>;
|
|
1631
1631
|
hoursSinceLastInbound(companyId: string, whatsappNumber: string): Promise<number | undefined>;
|
|
1632
|
-
setMode(companyId: string, whatsappNumber: string, mode: SessionMode, assignedUserId?: string | null): Promise<void>;
|
|
1632
|
+
setMode(companyId: string, whatsappNumber: string, mode: SessionMode, assignedUserId?: string | null, clearHumanRequest?: boolean): Promise<void>;
|
|
1633
1633
|
takeover(companyId: string, whatsappNumber: string, agentUserId: string): Promise<void>;
|
|
1634
1634
|
release(companyId: string, whatsappNumber: string): Promise<void>;
|
|
1635
1635
|
/**
|
|
@@ -2396,6 +2396,14 @@ type InboundMessageEffectsJob = {
|
|
|
2396
2396
|
message: WhatsAppMessage;
|
|
2397
2397
|
savedMessageId: string;
|
|
2398
2398
|
media?: InboundMediaDescriptor;
|
|
2399
|
+
/**
|
|
2400
|
+
* Nome de perfil de quem mandou. Vai no JOB e não é relido depois porque o job pode passar por
|
|
2401
|
+
* fila: o payload da Meta não existe mais quando o worker roda.
|
|
2402
|
+
*
|
|
2403
|
+
* Opcional, e job antigo sem o campo continua válido — é o que permite subir o módulo sem drenar
|
|
2404
|
+
* a fila antes.
|
|
2405
|
+
*/
|
|
2406
|
+
profileName?: string;
|
|
2399
2407
|
receivedAt: number;
|
|
2400
2408
|
};
|
|
2401
2409
|
type InboundStatusEffectsJob = {
|
package/dist/index.d.ts
CHANGED
|
@@ -1629,7 +1629,7 @@ declare class SessionRepository {
|
|
|
1629
1629
|
setFlowPosition(companyId: string, whatsappNumber: string, flowKey: string | null, currentNodeId: string | null): Promise<void>;
|
|
1630
1630
|
touchInbound(companyId: string, whatsappNumber: string): Promise<void>;
|
|
1631
1631
|
hoursSinceLastInbound(companyId: string, whatsappNumber: string): Promise<number | undefined>;
|
|
1632
|
-
setMode(companyId: string, whatsappNumber: string, mode: SessionMode, assignedUserId?: string | null): Promise<void>;
|
|
1632
|
+
setMode(companyId: string, whatsappNumber: string, mode: SessionMode, assignedUserId?: string | null, clearHumanRequest?: boolean): Promise<void>;
|
|
1633
1633
|
takeover(companyId: string, whatsappNumber: string, agentUserId: string): Promise<void>;
|
|
1634
1634
|
release(companyId: string, whatsappNumber: string): Promise<void>;
|
|
1635
1635
|
/**
|
|
@@ -2396,6 +2396,14 @@ type InboundMessageEffectsJob = {
|
|
|
2396
2396
|
message: WhatsAppMessage;
|
|
2397
2397
|
savedMessageId: string;
|
|
2398
2398
|
media?: InboundMediaDescriptor;
|
|
2399
|
+
/**
|
|
2400
|
+
* Nome de perfil de quem mandou. Vai no JOB e não é relido depois porque o job pode passar por
|
|
2401
|
+
* fila: o payload da Meta não existe mais quando o worker roda.
|
|
2402
|
+
*
|
|
2403
|
+
* Opcional, e job antigo sem o campo continua válido — é o que permite subir o módulo sem drenar
|
|
2404
|
+
* a fila antes.
|
|
2405
|
+
*/
|
|
2406
|
+
profileName?: string;
|
|
2399
2407
|
receivedAt: number;
|
|
2400
2408
|
};
|
|
2401
2409
|
type InboundStatusEffectsJob = {
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
3
|
|
|
4
|
-
// ../../../node_modules/.pnpm/tsup@8.5.1_@swc+core@1.
|
|
4
|
+
// ../../../node_modules/.pnpm/tsup@8.5.1_@swc+core@1.16.2_@swc+helpers@0.5.23__jiti@2.7.0_postcss@8.5.28_tsx@4.23.13_typescript@5.9.3_yaml@2.9.1/node_modules/tsup/assets/esm_shims.js
|
|
5
5
|
import path from "path";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
7
|
var getFilename = /* @__PURE__ */ __name(() => fileURLToPath(import.meta.url), "getFilename");
|
|
@@ -416,20 +416,33 @@ var SessionRepository = class {
|
|
|
416
416
|
if (!session?.lastInboundAt) return void 0;
|
|
417
417
|
return (Date.now() - session.lastInboundAt.getTime()) / (1e3 * 60 * 60);
|
|
418
418
|
}
|
|
419
|
-
|
|
419
|
+
// `clearHumanRequest` é opt-in: quem chama `setMode` direto para outros fins (ex.: trocar de
|
|
420
|
+
// atendente sem mexer na fila) continua sem afetar `humanRequestedAt`. Só `takeover`/`release`
|
|
421
|
+
// pedem a limpeza, porque só eles representam "o pedido de atendimento foi resolvido".
|
|
422
|
+
async setMode(companyId, whatsappNumber, mode, assignedUserId, clearHumanRequest = false) {
|
|
420
423
|
await this.db.update(sessions).set({
|
|
421
424
|
mode,
|
|
422
425
|
assignedUserId: assignedUserId ?? null,
|
|
426
|
+
...clearHumanRequest ? {
|
|
427
|
+
humanRequestedAt: null
|
|
428
|
+
} : {},
|
|
423
429
|
updatedAt: sql2`now()`
|
|
424
430
|
}).where(and(eq(sessions.companyId, companyId), eq(sessions.whatsappNumber, whatsappNumber)));
|
|
425
431
|
}
|
|
426
432
|
// T3.3 — takeover: atendente assume a conversa, tirando-a do modo bot.
|
|
433
|
+
//
|
|
434
|
+
// Limpa `humanRequestedAt`: sem isso a conversa nunca sai da fila `waitingHuman` da inbox,
|
|
435
|
+
// mesmo depois de atendida — o filtro é só `humanRequestedAt is not null` (ver
|
|
436
|
+
// `listByContextFilters`), então o campo tem que voltar a null quando o pedido é resolvido.
|
|
427
437
|
async takeover(companyId, whatsappNumber, agentUserId) {
|
|
428
|
-
await this.setMode(companyId, whatsappNumber, "human", agentUserId);
|
|
438
|
+
await this.setMode(companyId, whatsappNumber, "human", agentUserId, true);
|
|
429
439
|
}
|
|
430
440
|
// T3.3 — release: devolve a conversa ao bot.
|
|
441
|
+
//
|
|
442
|
+
// Também limpa `humanRequestedAt` pelo mesmo motivo do takeover: se o cliente pedir atendimento
|
|
443
|
+
// de novo depois, `requestHuman` grava um novo timestamp normalmente.
|
|
431
444
|
async release(companyId, whatsappNumber) {
|
|
432
|
-
await this.setMode(companyId, whatsappNumber, "bot", null);
|
|
445
|
+
await this.setMode(companyId, whatsappNumber, "bot", null, true);
|
|
433
446
|
}
|
|
434
447
|
/**
|
|
435
448
|
* Apaga a sessão; a cascata das FKs leva mensagens e documentos.
|
|
@@ -2085,7 +2098,7 @@ var WhatsAppChannelAdapter = class {
|
|
|
2085
2098
|
};
|
|
2086
2099
|
|
|
2087
2100
|
// src/channel/ReceiveWebhook.use-case.ts
|
|
2088
|
-
import { whatsAppWebhookPayloadSchema, whatsAppTemplateStatusUpdateSchema, whatsAppPhoneNumberQualityUpdateSchema, WHATSAPP_WEBHOOK_FIELDS } from "@adatechnology/meta-whatsapp-contracts";
|
|
2101
|
+
import { whatsAppWebhookPayloadSchema, resolveContactProfileName, whatsAppTemplateStatusUpdateSchema, whatsAppPhoneNumberQualityUpdateSchema, WHATSAPP_WEBHOOK_FIELDS } from "@adatechnology/meta-whatsapp-contracts";
|
|
2089
2102
|
|
|
2090
2103
|
// src/channel/webhookSecurity.ts
|
|
2091
2104
|
import { WEBHOOK_CLAIM_TTL_SECONDS, WEBHOOK_NONCE_TTL_SECONDS, buildWebhookDeliveryKey, isValidWebhookChallenge, isValidWebhookSignature } from "@adatechnology/meta-graph-core";
|
|
@@ -2496,7 +2509,9 @@ var InboundEffectsDispatcher = class {
|
|
|
2496
2509
|
const sessionRow = await this.params.sessionRepository.getContext(companyId, message.from);
|
|
2497
2510
|
if (!sessionRow) return;
|
|
2498
2511
|
if (sessionRow.mode === "human") return;
|
|
2499
|
-
const outcome = await this.params.hooks?.onMessageReceived?.(message, toSessionContract(sessionRow)
|
|
2512
|
+
const outcome = await this.params.hooks?.onMessageReceived?.(message, toSessionContract(sessionRow), job.profileName === void 0 ? {} : {
|
|
2513
|
+
profileName: job.profileName
|
|
2514
|
+
});
|
|
2500
2515
|
if (outcome?.outcome === "handled") return;
|
|
2501
2516
|
void extractAnswer(message);
|
|
2502
2517
|
}
|
|
@@ -2625,7 +2640,11 @@ var ReceiveWebhookUseCase = class {
|
|
|
2625
2640
|
continue;
|
|
2626
2641
|
}
|
|
2627
2642
|
for (const message of change.value.messages ?? []) {
|
|
2628
|
-
|
|
2643
|
+
const profileName = resolveContactProfileName({
|
|
2644
|
+
contacts: change.value.contacts,
|
|
2645
|
+
from: message.from
|
|
2646
|
+
});
|
|
2647
|
+
await this.handleMessage(input.companyId, message, profileName);
|
|
2629
2648
|
messagesProcessed++;
|
|
2630
2649
|
}
|
|
2631
2650
|
for (const status of change.value.statuses ?? []) {
|
|
@@ -2684,7 +2703,7 @@ var ReceiveWebhookUseCase = class {
|
|
|
2684
2703
|
await this.params.hooks?.onPhoneNumberQualityUpdate?.(quality.data);
|
|
2685
2704
|
return true;
|
|
2686
2705
|
}
|
|
2687
|
-
async handleMessage(companyId, message) {
|
|
2706
|
+
async handleMessage(companyId, message, profileName) {
|
|
2688
2707
|
const saved = await this.params.logMessage.execute({
|
|
2689
2708
|
companyId,
|
|
2690
2709
|
whatsappNumber: message.from,
|
|
@@ -2707,6 +2726,9 @@ var ReceiveWebhookUseCase = class {
|
|
|
2707
2726
|
...media ? {
|
|
2708
2727
|
media
|
|
2709
2728
|
} : {},
|
|
2729
|
+
...profileName ? {
|
|
2730
|
+
profileName
|
|
2731
|
+
} : {},
|
|
2710
2732
|
receivedAt: Date.now()
|
|
2711
2733
|
});
|
|
2712
2734
|
}
|