@adatechnology/meta-whatsapp-module 0.2.0-rc.29 → 0.2.0-rc.30
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 +129 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +109 -3
- package/dist/index.d.ts +109 -3
- package/dist/index.js +124 -33
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -33,6 +33,7 @@ __export(index_exports, {
|
|
|
33
33
|
FlowMediaRepository: () => FlowMediaRepository,
|
|
34
34
|
GetFlowGraphUseCase: () => GetFlowGraphUseCase,
|
|
35
35
|
GetLiveFlowPositionsUseCase: () => GetLiveFlowPositionsUseCase,
|
|
36
|
+
InboundEffectsDispatcher: () => InboundEffectsDispatcher,
|
|
36
37
|
IngestInboundMediaUseCase: () => IngestInboundMediaUseCase,
|
|
37
38
|
InvalidFlowGraphError: () => InvalidFlowGraphError,
|
|
38
39
|
ListCompanyDocumentsUseCase: () => ListCompanyDocumentsUseCase,
|
|
@@ -46,6 +47,7 @@ __export(index_exports, {
|
|
|
46
47
|
OptimisticLockError: () => OptimisticLockError,
|
|
47
48
|
PREVIEW_MEDIA_ID_PREFIX: () => import_meta_whatsapp_contracts8.PREVIEW_MEDIA_ID_PREFIX,
|
|
48
49
|
PRODUCT_LIST_LIMIT: () => PRODUCT_LIST_LIMIT,
|
|
50
|
+
ProcessInboundDispatchUseCase: () => ProcessInboundDispatchUseCase,
|
|
49
51
|
PurgeExpiredDocumentsUseCase: () => PurgeExpiredDocumentsUseCase,
|
|
50
52
|
ReceiveWebhookUseCase: () => ReceiveWebhookUseCase,
|
|
51
53
|
ReleaseConversationUseCase: () => ReleaseConversationUseCase,
|
|
@@ -59,9 +61,12 @@ __export(index_exports, {
|
|
|
59
61
|
TRANSCRIPTION_STATUS: () => TRANSCRIPTION_STATUS,
|
|
60
62
|
TakeoverConversationUseCase: () => TakeoverConversationUseCase,
|
|
61
63
|
TranscribeAudioUseCase: () => TranscribeAudioUseCase,
|
|
64
|
+
WEBHOOK_CLAIM_TTL_SECONDS: () => import_meta_graph_core2.WEBHOOK_CLAIM_TTL_SECONDS,
|
|
62
65
|
WEBHOOK_NONCE_TTL_SECONDS: () => import_meta_graph_core2.WEBHOOK_NONCE_TTL_SECONDS,
|
|
63
66
|
WhatsAppChannelAdapter: () => WhatsAppChannelAdapter,
|
|
67
|
+
buildInboundJobId: () => buildInboundJobId,
|
|
64
68
|
claimWebhookDelivery: () => claimWebhookDelivery,
|
|
69
|
+
confirmWebhookDelivery: () => confirmWebhookDelivery,
|
|
65
70
|
createMetaWhatsAppModule: () => createMetaWhatsAppModule,
|
|
66
71
|
createSendMediaAction: () => createSendMediaAction,
|
|
67
72
|
createSendProductListAction: () => createSendProductListAction,
|
|
@@ -84,6 +89,7 @@ __export(index_exports, {
|
|
|
84
89
|
sessions: () => sessions,
|
|
85
90
|
settings: () => settings,
|
|
86
91
|
toPreviewMediaId: () => import_meta_whatsapp_contracts8.toPreviewMediaId,
|
|
92
|
+
toSessionContract: () => toSessionContract,
|
|
87
93
|
transcriptionRetryAfterSeconds: () => transcriptionRetryAfterSeconds,
|
|
88
94
|
verifyWebhookChallenge: () => verifyWebhookChallenge,
|
|
89
95
|
verifyWebhookSignature: () => verifyWebhookSignature
|
|
@@ -2099,14 +2105,21 @@ function verifyWebhookSignature(params) {
|
|
|
2099
2105
|
if (!(0, import_meta_graph_core2.isValidWebhookSignature)(params)) throw new import_meta_whatsapp_contracts10.InvalidWebhookSignatureError();
|
|
2100
2106
|
}
|
|
2101
2107
|
__name(verifyWebhookSignature, "verifyWebhookSignature");
|
|
2102
|
-
|
|
2103
|
-
|
|
2108
|
+
function deliveryKey(signatureHeader) {
|
|
2109
|
+
return (0, import_meta_graph_core2.buildWebhookDeliveryKey)({
|
|
2104
2110
|
namespace: WEBHOOK_NONCE_NAMESPACE,
|
|
2105
|
-
signatureHeader
|
|
2111
|
+
signatureHeader
|
|
2106
2112
|
});
|
|
2107
|
-
|
|
2113
|
+
}
|
|
2114
|
+
__name(deliveryKey, "deliveryKey");
|
|
2115
|
+
async function claimWebhookDelivery(params) {
|
|
2116
|
+
return params.nonceStore.setIfAbsent(deliveryKey(params.signatureHeader), params.ttlSeconds ?? import_meta_graph_core2.WEBHOOK_CLAIM_TTL_SECONDS);
|
|
2108
2117
|
}
|
|
2109
2118
|
__name(claimWebhookDelivery, "claimWebhookDelivery");
|
|
2119
|
+
async function confirmWebhookDelivery(params) {
|
|
2120
|
+
await params.nonceStore.confirm?.(deliveryKey(params.signatureHeader), params.ttlSeconds ?? import_meta_graph_core2.WEBHOOK_NONCE_TTL_SECONDS);
|
|
2121
|
+
}
|
|
2122
|
+
__name(confirmWebhookDelivery, "confirmWebhookDelivery");
|
|
2110
2123
|
|
|
2111
2124
|
// src/channel/IngestInboundMedia.use-case.ts
|
|
2112
2125
|
var import_drizzle_orm8 = require("drizzle-orm");
|
|
@@ -2427,7 +2440,11 @@ function extractMediaDescriptor(message) {
|
|
|
2427
2440
|
}
|
|
2428
2441
|
__name(extractMediaDescriptor, "extractMediaDescriptor");
|
|
2429
2442
|
|
|
2430
|
-
// src/channel/
|
|
2443
|
+
// src/channel/inboundDispatch.ts
|
|
2444
|
+
function buildInboundJobId(job) {
|
|
2445
|
+
return job.kind === "message" ? `wa-inbound-message:${job.message.id}` : `wa-inbound-status:${job.status.id}:${job.status.status}`;
|
|
2446
|
+
}
|
|
2447
|
+
__name(buildInboundJobId, "buildInboundJobId");
|
|
2431
2448
|
function toSessionContract(row) {
|
|
2432
2449
|
return {
|
|
2433
2450
|
id: row.id,
|
|
@@ -2448,6 +2465,65 @@ function toSessionContract(row) {
|
|
|
2448
2465
|
};
|
|
2449
2466
|
}
|
|
2450
2467
|
__name(toSessionContract, "toSessionContract");
|
|
2468
|
+
function extractAnswer(message) {
|
|
2469
|
+
const interactive = message.interactive;
|
|
2470
|
+
if (interactive?.button_reply) return interactive.button_reply.id;
|
|
2471
|
+
if (interactive?.list_reply) return interactive.list_reply.id;
|
|
2472
|
+
return message.text?.body;
|
|
2473
|
+
}
|
|
2474
|
+
__name(extractAnswer, "extractAnswer");
|
|
2475
|
+
var InboundEffectsDispatcher = class {
|
|
2476
|
+
static {
|
|
2477
|
+
__name(this, "InboundEffectsDispatcher");
|
|
2478
|
+
}
|
|
2479
|
+
params;
|
|
2480
|
+
constructor(params) {
|
|
2481
|
+
this.params = params;
|
|
2482
|
+
}
|
|
2483
|
+
async run(job) {
|
|
2484
|
+
if (job.kind === "message") return this.runMessageEffects(job);
|
|
2485
|
+
return this.runStatusEffects(job);
|
|
2486
|
+
}
|
|
2487
|
+
async runMessageEffects(job) {
|
|
2488
|
+
const { companyId, message, savedMessageId, media } = job;
|
|
2489
|
+
if (media) {
|
|
2490
|
+
await this.params.hooks?.onMediaReceived?.({
|
|
2491
|
+
companyId,
|
|
2492
|
+
messageId: savedMessageId,
|
|
2493
|
+
whatsappNumber: message.from,
|
|
2494
|
+
sourceMediaId: media.sourceMediaId,
|
|
2495
|
+
mimeType: media.mimeType,
|
|
2496
|
+
...media.filename ? {
|
|
2497
|
+
filename: media.filename
|
|
2498
|
+
} : {}
|
|
2499
|
+
});
|
|
2500
|
+
}
|
|
2501
|
+
const sessionRow = await this.params.sessionRepository.getContext(companyId, message.from);
|
|
2502
|
+
if (!sessionRow) return;
|
|
2503
|
+
if (sessionRow.mode === "human") return;
|
|
2504
|
+
const outcome = await this.params.hooks?.onMessageReceived?.(message, toSessionContract(sessionRow));
|
|
2505
|
+
if (outcome?.outcome === "handled") return;
|
|
2506
|
+
void extractAnswer(message);
|
|
2507
|
+
}
|
|
2508
|
+
async runStatusEffects(job) {
|
|
2509
|
+
const sessionRow = await this.params.sessionRepository.getContext(job.companyId, job.whatsappNumber);
|
|
2510
|
+
await this.params.hooks?.onStatusUpdate?.(job.status, sessionRow ? toSessionContract(sessionRow) : null);
|
|
2511
|
+
}
|
|
2512
|
+
};
|
|
2513
|
+
var ProcessInboundDispatchUseCase = class {
|
|
2514
|
+
static {
|
|
2515
|
+
__name(this, "ProcessInboundDispatchUseCase");
|
|
2516
|
+
}
|
|
2517
|
+
dispatcher;
|
|
2518
|
+
constructor(dispatcher) {
|
|
2519
|
+
this.dispatcher = dispatcher;
|
|
2520
|
+
}
|
|
2521
|
+
async execute(job) {
|
|
2522
|
+
await this.dispatcher.run(job);
|
|
2523
|
+
}
|
|
2524
|
+
};
|
|
2525
|
+
|
|
2526
|
+
// src/channel/ReceiveWebhook.use-case.ts
|
|
2451
2527
|
function extractContent(message) {
|
|
2452
2528
|
if (message.text?.body) return message.text.body;
|
|
2453
2529
|
const interactive = message.interactive;
|
|
@@ -2460,13 +2536,6 @@ function extractContent(message) {
|
|
|
2460
2536
|
return message.image?.caption ?? message.document?.caption ?? null;
|
|
2461
2537
|
}
|
|
2462
2538
|
__name(extractContent, "extractContent");
|
|
2463
|
-
function extractAnswer(message) {
|
|
2464
|
-
const interactive = message.interactive;
|
|
2465
|
-
if (interactive?.button_reply) return interactive.button_reply.id;
|
|
2466
|
-
if (interactive?.list_reply) return interactive.list_reply.id;
|
|
2467
|
-
return message.text?.body;
|
|
2468
|
-
}
|
|
2469
|
-
__name(extractAnswer, "extractAnswer");
|
|
2470
2539
|
function extractPayload(message) {
|
|
2471
2540
|
const payload = {};
|
|
2472
2541
|
if (message.interactive) payload["interactive"] = message.interactive;
|
|
@@ -2487,7 +2556,17 @@ var ReceiveWebhookUseCase = class {
|
|
|
2487
2556
|
params;
|
|
2488
2557
|
constructor(params) {
|
|
2489
2558
|
this.params = params;
|
|
2559
|
+
this.dispatcher = new InboundEffectsDispatcher({
|
|
2560
|
+
sessionRepository: params.sessionRepository,
|
|
2561
|
+
...params.hooks ? {
|
|
2562
|
+
hooks: params.hooks
|
|
2563
|
+
} : {},
|
|
2564
|
+
...params.realtime ? {
|
|
2565
|
+
realtime: params.realtime
|
|
2566
|
+
} : {}
|
|
2567
|
+
});
|
|
2490
2568
|
}
|
|
2569
|
+
dispatcher;
|
|
2491
2570
|
async execute(input) {
|
|
2492
2571
|
verifyWebhookSignature({
|
|
2493
2572
|
rawBody: input.rawBody,
|
|
@@ -2526,6 +2605,10 @@ var ReceiveWebhookUseCase = class {
|
|
|
2526
2605
|
}
|
|
2527
2606
|
}
|
|
2528
2607
|
}
|
|
2608
|
+
await confirmWebhookDelivery({
|
|
2609
|
+
nonceStore: this.params.nonceStore,
|
|
2610
|
+
signatureHeader: input.signatureHeader
|
|
2611
|
+
});
|
|
2529
2612
|
return {
|
|
2530
2613
|
duplicate: false,
|
|
2531
2614
|
messagesProcessed,
|
|
@@ -2548,24 +2631,16 @@ var ReceiveWebhookUseCase = class {
|
|
|
2548
2631
|
});
|
|
2549
2632
|
if (!saved) return;
|
|
2550
2633
|
const media = extractMediaDescriptor(saved);
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
});
|
|
2562
|
-
}
|
|
2563
|
-
const sessionRow = await this.params.sessionRepository.getContext(companyId, message.from);
|
|
2564
|
-
if (!sessionRow) return;
|
|
2565
|
-
if (sessionRow.mode === "human") return;
|
|
2566
|
-
const outcome = await this.params.hooks?.onMessageReceived?.(message, toSessionContract(sessionRow));
|
|
2567
|
-
if (outcome?.outcome === "handled") return;
|
|
2568
|
-
void extractAnswer(message);
|
|
2634
|
+
await this.dispatch({
|
|
2635
|
+
kind: "message",
|
|
2636
|
+
companyId,
|
|
2637
|
+
message,
|
|
2638
|
+
savedMessageId: saved.id,
|
|
2639
|
+
...media ? {
|
|
2640
|
+
media
|
|
2641
|
+
} : {},
|
|
2642
|
+
receivedAt: Date.now()
|
|
2643
|
+
});
|
|
2569
2644
|
}
|
|
2570
2645
|
async handleStatus(companyId, status) {
|
|
2571
2646
|
const updated = await this.params.messageRepository.updateMessageStatus(companyId, status.id, status.status);
|
|
@@ -2574,8 +2649,24 @@ var ReceiveWebhookUseCase = class {
|
|
|
2574
2649
|
waMessageId: status.id,
|
|
2575
2650
|
status: status.status
|
|
2576
2651
|
});
|
|
2577
|
-
|
|
2578
|
-
|
|
2652
|
+
await this.dispatch({
|
|
2653
|
+
kind: "status",
|
|
2654
|
+
companyId,
|
|
2655
|
+
status,
|
|
2656
|
+
whatsappNumber: updated.whatsappNumber,
|
|
2657
|
+
receivedAt: Date.now()
|
|
2658
|
+
});
|
|
2659
|
+
}
|
|
2660
|
+
// Com fila configurada, os efeitos saem da requisição do webhook; sem ela, rodam aqui mesmo e o
|
|
2661
|
+
// comportamento é o de sempre. É o mesmo `InboundEffectsDispatcher` nos dois caminhos.
|
|
2662
|
+
async dispatch(job) {
|
|
2663
|
+
if (this.params.inboundQueue) {
|
|
2664
|
+
await this.params.inboundQueue.enqueue(job, {
|
|
2665
|
+
jobId: buildInboundJobId(job)
|
|
2666
|
+
});
|
|
2667
|
+
return;
|
|
2668
|
+
}
|
|
2669
|
+
await this.dispatcher.run(job);
|
|
2579
2670
|
}
|
|
2580
2671
|
};
|
|
2581
2672
|
|
|
@@ -2889,6 +2980,7 @@ __name(redeemSseTicket, "redeemSseTicket");
|
|
|
2889
2980
|
FlowMediaRepository,
|
|
2890
2981
|
GetFlowGraphUseCase,
|
|
2891
2982
|
GetLiveFlowPositionsUseCase,
|
|
2983
|
+
InboundEffectsDispatcher,
|
|
2892
2984
|
IngestInboundMediaUseCase,
|
|
2893
2985
|
InvalidFlowGraphError,
|
|
2894
2986
|
ListCompanyDocumentsUseCase,
|
|
@@ -2902,6 +2994,7 @@ __name(redeemSseTicket, "redeemSseTicket");
|
|
|
2902
2994
|
OptimisticLockError,
|
|
2903
2995
|
PREVIEW_MEDIA_ID_PREFIX,
|
|
2904
2996
|
PRODUCT_LIST_LIMIT,
|
|
2997
|
+
ProcessInboundDispatchUseCase,
|
|
2905
2998
|
PurgeExpiredDocumentsUseCase,
|
|
2906
2999
|
ReceiveWebhookUseCase,
|
|
2907
3000
|
ReleaseConversationUseCase,
|
|
@@ -2915,9 +3008,12 @@ __name(redeemSseTicket, "redeemSseTicket");
|
|
|
2915
3008
|
TRANSCRIPTION_STATUS,
|
|
2916
3009
|
TakeoverConversationUseCase,
|
|
2917
3010
|
TranscribeAudioUseCase,
|
|
3011
|
+
WEBHOOK_CLAIM_TTL_SECONDS,
|
|
2918
3012
|
WEBHOOK_NONCE_TTL_SECONDS,
|
|
2919
3013
|
WhatsAppChannelAdapter,
|
|
3014
|
+
buildInboundJobId,
|
|
2920
3015
|
claimWebhookDelivery,
|
|
3016
|
+
confirmWebhookDelivery,
|
|
2921
3017
|
createMetaWhatsAppModule,
|
|
2922
3018
|
createSendMediaAction,
|
|
2923
3019
|
createSendProductListAction,
|
|
@@ -2940,6 +3036,7 @@ __name(redeemSseTicket, "redeemSseTicket");
|
|
|
2940
3036
|
sessions,
|
|
2941
3037
|
settings,
|
|
2942
3038
|
toPreviewMediaId,
|
|
3039
|
+
toSessionContract,
|
|
2943
3040
|
transcriptionRetryAfterSeconds,
|
|
2944
3041
|
verifyWebhookChallenge,
|
|
2945
3042
|
verifyWebhookSignature
|