@openclaw/whatsapp 2026.5.22 → 2026.5.24-beta.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/{action-runtime-D4UqEXqf.js → action-runtime-DGx8vCsS.js} +1 -1
- package/dist/action-runtime-api.js +1 -1
- package/dist/action-runtime.runtime.js +1 -1
- package/dist/api.js +6 -6
- package/dist/approval-handler.runtime-j8U6lgcp.js +171 -0
- package/dist/approval-resolver-e1hAVRRy.js +15 -0
- package/dist/{auth-store-GTQvJznL.js → auth-store-BrKb0mwT.js} +2 -2
- package/dist/{channel-BQqQ-Gp5.js → channel-DOxZCBxE.js} +415 -34
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel-react-action-CHdR3gbn.js → channel-react-action-O7asbQQ1.js} +2 -2
- package/dist/{channel.runtime-BZ_ya3mR.js → channel.runtime-B0cFknwD.js} +4 -4
- package/dist/{channel.setup-vWI0fm8Y.js → channel.setup-Bk7Hmp4a.js} +2 -2
- package/dist/{connection-controller-9TXWZRhx.js → connection-controller-ja6z4F_k.js} +2 -2
- package/dist/light-runtime-api.js +1 -1
- package/dist/{login-nJwaNuC-.js → login-BEkrpJbZ.js} +3 -3
- package/dist/{login-qr-l4UaR8Dj.js → login-qr-BVRx8j_M.js} +3 -3
- package/dist/login-qr-runtime.js +1 -1
- package/dist/{monitor-ClhD-fQ6.js → monitor-BU1ydkuF.js} +324 -87
- package/dist/{outbound-adapter-ltiZkW9L.js → outbound-adapter-BObZXXzU.js} +1 -1
- package/dist/outbound-payload-test-api.js +1 -1
- package/dist/{runtime-CboC4QhQ.js → runtime-BfAdAEYT.js} +2 -2
- package/dist/runtime-api.js +8 -8
- package/dist/runtime-setter-api.js +1 -1
- package/dist/send-C9jEw6hx.js +625 -0
- package/dist/{send-api-CXPUXbUL.js → send-api-CC-vHBWG.js} +2 -2
- package/dist/{session-CPsgRMMa.js → session-CDgpDc0l.js} +2 -2
- package/dist/{session.runtime-C6uBkEaI.js → session.runtime-LZFdq3yb.js} +1 -1
- package/dist/{setup-core-BTDKEc-x.js → setup-core-Ce-b_wzQ.js} +2 -2
- package/dist/{setup-finalize-DUYdQs-v.js → setup-finalize-BqOudqJw.js} +2 -2
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{setup-surface-Uoh9W_29.js → setup-surface-CAchPwW5.js} +2 -2
- package/dist/test-api.js +1 -1
- package/npm-shrinkwrap.json +3 -3
- package/package.json +4 -4
- package/dist/send-E_kMiuZP.js +0 -269
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import { a as resolveWhatsAppAccount, s as resolveWhatsAppMediaMaxBytes } from "./accounts-BPYgj8Fv.js";
|
|
2
2
|
import { t as isWhatsAppGroupJid } from "./normalize-target-bVWjgftN.js";
|
|
3
3
|
import { t as resolveWhatsAppReactionLevel } from "./reaction-level-BqMOEBeq.js";
|
|
4
|
+
import { c as maybeResolveWhatsAppApprovalReaction, r as sendReactionWhatsApp } from "./send-C9jEw6hx.js";
|
|
5
|
+
import { n as getWhatsAppRuntime } from "./runtime-BfAdAEYT.js";
|
|
4
6
|
import { i as prepareWhatsAppOutboundMedia, o as sendWhatsAppOutboundWithRetry, r as normalizeWhatsAppPayloadTextPreservingIndentation, t as normalizeWhatsAppOutboundPayload } from "./outbound-media-contract-ioTkt8tn.js";
|
|
5
7
|
import { n as getStatusCode, t as formatError } from "./session-errors-BAj9D2La.js";
|
|
6
8
|
import { d as markdownToWhatsApp, f as resolveJidToE164, l as isSelfChatMode, n as normalizeE164, t as convertMarkdownTables$1, u as jidToE164 } from "./text-runtime-Dk37KYHj.js";
|
|
7
|
-
import { r as sendReactionWhatsApp } from "./send-E_kMiuZP.js";
|
|
8
9
|
import { n as cacheInboundMessageMeta, r as lookupInboundMessageMeta, t as buildQuotedMessageOptions } from "./quoted-message-CveINB35.js";
|
|
9
|
-
import { c as logoutWeb, g as readWebSelfId, o as getWebAuthAgeMs, r as WhatsAppAuthUnstableError, v as readWebSelfIdentityForDecision } from "./auth-store-
|
|
10
|
+
import { c as logoutWeb, g as readWebSelfId, o as getWebAuthAgeMs, r as WhatsAppAuthUnstableError, v as readWebSelfIdentityForDecision } from "./auth-store-BrKb0mwT.js";
|
|
10
11
|
import { a as getSelfIdentity, c as resolveComparableIdentity, i as getReplyContext, n as getMentionIdentities, o as getSenderIdentity, r as getPrimaryIdentityId, s as identitiesOverlap, t as getComparableIdentityValues } from "./identity-xoLLdqEv.js";
|
|
11
12
|
import { i as resolveWhatsAppInboundPolicy, r as resolveWhatsAppCommandAuthorized, t as checkInboundAccessControl } from "./access-control-p_vcYDW7.js";
|
|
12
|
-
import { a as mayContainWhatsAppOutboundMention, c as extractContactContext, d as extractMediaPlaceholder, f as extractMentionedJids, i as addWhatsAppOutboundMentionsToContent, l as extractContextInfo, m as hasInboundUserContent, n as listWhatsAppSendResultMessageIds, o as resolveWhatsAppOutboundMentions, p as extractText, r as normalizeWhatsAppSendResult, s as describeReplyContext, t as createWebSendApi, u as extractLocationData } from "./send-api-
|
|
13
|
-
import { i as resolveWhatsAppSocketTiming, r as waitForWaConnection, t as createWaSocket } from "./session-
|
|
14
|
-
import {
|
|
13
|
+
import { a as mayContainWhatsAppOutboundMention, c as extractContactContext, d as extractMediaPlaceholder, f as extractMentionedJids, i as addWhatsAppOutboundMentionsToContent, l as extractContextInfo, m as hasInboundUserContent, n as listWhatsAppSendResultMessageIds, o as resolveWhatsAppOutboundMentions, p as extractText, r as normalizeWhatsAppSendResult, s as describeReplyContext, t as createWebSendApi, u as extractLocationData } from "./send-api-CC-vHBWG.js";
|
|
14
|
+
import { i as resolveWhatsAppSocketTiming, r as waitForWaConnection, t as createWaSocket } from "./session-CDgpDc0l.js";
|
|
15
|
+
import { t as BufferJSON } from "./session.runtime-LZFdq3yb.js";
|
|
16
|
+
import { c as computeBackoff, d as resolveReconnectPolicy, f as sleepWithAbort, l as newConnectionId, n as WHATSAPP_WATCHDOG_TIMEOUT_ERROR, r as WhatsAppConnectionController, s as DEFAULT_RECONNECT_POLICY, u as resolveHeartbeatSeconds } from "./connection-controller-ja6z4F_k.js";
|
|
15
17
|
import { resolveAccountEntry } from "openclaw/plugin-sdk/account-core";
|
|
16
18
|
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
17
19
|
import { evaluateSupplementalContextVisibility, filterSupplementalContextItems, resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime";
|
|
@@ -22,17 +24,20 @@ import { resolveMarkdownTableMode as resolveMarkdownTableMode$1 } from "openclaw
|
|
|
22
24
|
import { createSubsystemLogger, defaultRuntime, formatDurationPrecise, getChildLogger as getChildLogger$1, logVerbose, logVerbose as logVerbose$1, registerUnhandledRejectionHandler, shouldLogVerbose, shouldLogVerbose as shouldLogVerbose$1, warn } from "openclaw/plugin-sdk/runtime-env";
|
|
23
25
|
import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime";
|
|
24
26
|
import { LocalMediaAccessError, getDefaultLocalRoots, loadWebMedia as loadWebMedia$1, loadWebMediaRaw, optimizeImageToJpeg, optimizeImageToPng } from "openclaw/plugin-sdk/web-media";
|
|
25
|
-
import {
|
|
27
|
+
import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, DEFAULT_MAIN_KEY, buildAgentMainSessionKey, buildAgentSessionKey, buildGroupHistoryKey, deriveLastRoutePolicy, normalizeAccountId as normalizeAccountId$1, normalizeAgentId, resolveAgentRoute, resolveInboundLastRouteSessionKey, resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
|
|
28
|
+
import { createChannelMessageReplyPipeline, createDurableInboundReceiveJournal, createMessageReceiptFromOutboundResults, deliverInboundReplyWithMessageSendContext, resolveChannelMessageSourceReplyDeliveryMode } from "openclaw/plugin-sdk/channel-message";
|
|
26
29
|
import { chunkMarkdownTextWithMode } from "openclaw/plugin-sdk/reply-chunking";
|
|
27
30
|
import { isReasoningReplyPayload, resolveSendableOutboundReplyParts, sendMediaWithLeadingCaption } from "openclaw/plugin-sdk/reply-payload";
|
|
28
|
-
import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, DEFAULT_MAIN_KEY, buildAgentMainSessionKey, buildAgentSessionKey, buildGroupHistoryKey, deriveLastRoutePolicy, normalizeAccountId as normalizeAccountId$1, normalizeAgentId, resolveAgentRoute, resolveInboundLastRouteSessionKey, resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
|
|
29
31
|
import { recordInboundSession } from "openclaw/plugin-sdk/conversation-runtime";
|
|
30
32
|
import { loadSessionStore, resolveStorePath, updateLastRoute, updateSessionStore } from "openclaw/plugin-sdk/session-store-runtime";
|
|
31
33
|
import { DisconnectReason as DisconnectReason$1, downloadMediaMessage, isJidGroup, normalizeMessageContent as normalizeMessageContent$1 } from "baileys";
|
|
32
34
|
import { formatLocationText, resolveInboundSessionEnvelopeContext } from "openclaw/plugin-sdk/channel-inbound";
|
|
33
35
|
import { recordChannelActivity } from "openclaw/plugin-sdk/channel-activity-runtime";
|
|
36
|
+
import { createHash } from "node:crypto";
|
|
34
37
|
import { dispatchReplyWithBufferedBlockDispatcher, finalizeInboundContext, resolveChunkMode, resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-runtime";
|
|
38
|
+
import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-runtime";
|
|
35
39
|
import { createInboundDebouncer, resolveInboundDebounceMs } from "openclaw/plugin-sdk/channel-inbound-debounce";
|
|
40
|
+
import { registerChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runtime-context";
|
|
36
41
|
import { hasControlCommand, isControlCommandMessage, isControlCommandMessage as isControlCommandMessage$1, shouldComputeCommandAuthorized } from "openclaw/plugin-sdk/command-detection";
|
|
37
42
|
import { drainPendingDeliveries } from "openclaw/plugin-sdk/delivery-queue-runtime";
|
|
38
43
|
import { DEFAULT_GROUP_HISTORY_LIMIT, buildHistoryContextFromEntries, buildInboundHistoryFromEntries, createChannelHistoryWindow } from "openclaw/plugin-sdk/reply-history";
|
|
@@ -119,8 +124,8 @@ function resetWebInboundDedupe() {
|
|
|
119
124
|
claimableInboundMessages.clearMemory();
|
|
120
125
|
recentOutboundMessages.clear();
|
|
121
126
|
}
|
|
122
|
-
async function
|
|
123
|
-
return (await claimableInboundMessages.claim(key)).kind
|
|
127
|
+
async function claimRecentInboundMessageDelivery(key) {
|
|
128
|
+
return (await claimableInboundMessages.claim(key)).kind;
|
|
124
129
|
}
|
|
125
130
|
async function commitRecentInboundMessage(key) {
|
|
126
131
|
await claimableInboundMessages.commit(key);
|
|
@@ -139,6 +144,42 @@ function isRecentOutboundMessage(params) {
|
|
|
139
144
|
return recentOutboundMessages.peek(key);
|
|
140
145
|
}
|
|
141
146
|
//#endregion
|
|
147
|
+
//#region extensions/whatsapp/src/inbound/durable-receive.ts
|
|
148
|
+
const WHATSAPP_DURABLE_INBOUND_PENDING_MAX_ENTRIES = 450;
|
|
149
|
+
const WHATSAPP_DURABLE_INBOUND_COMPLETED_MAX_ENTRIES = 450;
|
|
150
|
+
const WHATSAPP_DURABLE_INBOUND_PENDING_TTL_MS = 720 * 60 * 60 * 1e3;
|
|
151
|
+
const WHATSAPP_DURABLE_INBOUND_COMPLETED_TTL_MS = 10080 * 60 * 1e3;
|
|
152
|
+
function hashNamespacePart(value) {
|
|
153
|
+
return createHash("sha256").update(value).digest("hex").slice(0, 24);
|
|
154
|
+
}
|
|
155
|
+
function createWhatsAppDurableInboundMessageId(params) {
|
|
156
|
+
return createHash("sha256").update(`${params.remoteJid}\n${params.id}`).digest("hex");
|
|
157
|
+
}
|
|
158
|
+
function serializeWhatsAppDurableInboundMessage(message) {
|
|
159
|
+
return JSON.parse(JSON.stringify(message, BufferJSON.replacer));
|
|
160
|
+
}
|
|
161
|
+
function deserializeWhatsAppDurableInboundMessage(message) {
|
|
162
|
+
return JSON.parse(JSON.stringify(message), BufferJSON.reviver);
|
|
163
|
+
}
|
|
164
|
+
function createWhatsAppDurableInboundReceiveJournal(accountId) {
|
|
165
|
+
const runtime = getWhatsAppRuntime();
|
|
166
|
+
const accountPart = hashNamespacePart(accountId);
|
|
167
|
+
return createDurableInboundReceiveJournal({
|
|
168
|
+
pendingStore: runtime.state.openKeyedStore({
|
|
169
|
+
namespace: `inbound.v1.pending.${accountPart}`,
|
|
170
|
+
maxEntries: WHATSAPP_DURABLE_INBOUND_PENDING_MAX_ENTRIES,
|
|
171
|
+
defaultTtlMs: WHATSAPP_DURABLE_INBOUND_PENDING_TTL_MS
|
|
172
|
+
}),
|
|
173
|
+
completedStore: runtime.state.openKeyedStore({
|
|
174
|
+
namespace: `inbound.v1.completed.${accountPart}`,
|
|
175
|
+
maxEntries: WHATSAPP_DURABLE_INBOUND_COMPLETED_MAX_ENTRIES,
|
|
176
|
+
defaultTtlMs: WHATSAPP_DURABLE_INBOUND_COMPLETED_TTL_MS
|
|
177
|
+
}),
|
|
178
|
+
pendingTtlMs: WHATSAPP_DURABLE_INBOUND_PENDING_TTL_MS,
|
|
179
|
+
completedTtlMs: WHATSAPP_DURABLE_INBOUND_COMPLETED_TTL_MS
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
//#endregion
|
|
142
183
|
//#region extensions/whatsapp/src/inbound/lifecycle.ts
|
|
143
184
|
function attachEmitterListener(emitter, event, listener) {
|
|
144
185
|
emitter.on(event, listener);
|
|
@@ -298,6 +339,7 @@ async function attachWebInboxToSocket(options) {
|
|
|
298
339
|
const selfIdentity = await readWebSelfIdentityForDecision(options.authDir, sock.user);
|
|
299
340
|
if (selfIdentity.outcome === "unstable") throw new WhatsAppAuthUnstableError("WhatsApp auth state is still stabilizing; retrying inbox attach.");
|
|
300
341
|
const self = selfIdentity.identity;
|
|
342
|
+
const durableInboundJournal = createWhatsAppDurableInboundReceiveJournal(options.accountId);
|
|
301
343
|
const inboundDebounceMs = Math.max(0, Math.trunc(options.debounceMs ?? 0));
|
|
302
344
|
const pendingDebounceKeys = /* @__PURE__ */ new Set();
|
|
303
345
|
const activeInboundFlushes = /* @__PURE__ */ new Set();
|
|
@@ -309,14 +351,17 @@ async function attachWebInboxToSocket(options) {
|
|
|
309
351
|
return `${msg.accountId}:${conversationKey}:${senderKey}`;
|
|
310
352
|
};
|
|
311
353
|
const shouldDebounceInboundMessage = (msg) => options.shouldDebounce?.(msg) ?? true;
|
|
312
|
-
const
|
|
354
|
+
const finalizeInboundDelivery = async (entries, error) => {
|
|
313
355
|
const dedupeKeys = [...new Set(entries.map((entry) => entry.dedupeKey).filter(isNonEmptyString))];
|
|
314
|
-
|
|
356
|
+
const durableEntries = entries.filter((entry) => isNonEmptyString(entry.durableId));
|
|
357
|
+
const readReceiptEntries = entries.filter((entry) => Boolean(entry.readReceipt));
|
|
315
358
|
if (error instanceof WhatsAppRetryableInboundError) {
|
|
316
359
|
dedupeKeys.forEach((dedupeKey) => releaseRecentInboundMessage(dedupeKey, error));
|
|
360
|
+
await Promise.all(durableEntries.map((entry) => durableInboundJournal.release(entry.durableId, { lastError: formatError(error) })));
|
|
317
361
|
return;
|
|
318
362
|
}
|
|
319
|
-
await Promise.all(dedupeKeys.map((dedupeKey) => commitRecentInboundMessage(dedupeKey)));
|
|
363
|
+
await Promise.all([...dedupeKeys.map((dedupeKey) => commitRecentInboundMessage(dedupeKey)), ...durableEntries.map((entry) => durableInboundJournal.complete(entry.durableId, entry.readReceipt ? { metadata: { readReceipt: entry.readReceipt } } : void 0))]);
|
|
364
|
+
await Promise.all(readReceiptEntries.map((entry) => maybeMarkInboundAsRead(entry.readReceipt)));
|
|
320
365
|
};
|
|
321
366
|
const debouncer = createInboundDebouncer({
|
|
322
367
|
debounceMs: inboundDebounceMs,
|
|
@@ -334,7 +379,7 @@ async function attachWebInboxToSocket(options) {
|
|
|
334
379
|
try {
|
|
335
380
|
if (entries.length === 1) {
|
|
336
381
|
await options.onMessage(last);
|
|
337
|
-
await
|
|
382
|
+
await finalizeInboundDelivery(entries);
|
|
338
383
|
return;
|
|
339
384
|
}
|
|
340
385
|
const mentioned = /* @__PURE__ */ new Set();
|
|
@@ -348,9 +393,9 @@ async function attachWebInboxToSocket(options) {
|
|
|
348
393
|
isBatched: true
|
|
349
394
|
};
|
|
350
395
|
await options.onMessage(combinedMessage);
|
|
351
|
-
await
|
|
396
|
+
await finalizeInboundDelivery(entries);
|
|
352
397
|
} catch (error) {
|
|
353
|
-
await
|
|
398
|
+
await finalizeInboundDelivery(entries, error);
|
|
354
399
|
throw error;
|
|
355
400
|
}
|
|
356
401
|
} finally {
|
|
@@ -537,21 +582,121 @@ async function attachWebInboxToSocket(options) {
|
|
|
537
582
|
access
|
|
538
583
|
};
|
|
539
584
|
};
|
|
540
|
-
const
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
585
|
+
const buildReadReceiptTarget = (inbound) => inbound.id ? {
|
|
586
|
+
remoteJid: inbound.remoteJid,
|
|
587
|
+
id: inbound.id,
|
|
588
|
+
...inbound.participantJid ? { participant: inbound.participantJid } : {}
|
|
589
|
+
} : void 0;
|
|
590
|
+
const maybeMarkInboundAsRead = async (target) => {
|
|
591
|
+
if (!target || options.sendReadReceipts === false) return;
|
|
592
|
+
const { id, remoteJid, participant } = target;
|
|
593
|
+
try {
|
|
594
|
+
await (getCurrentSock() ?? sock).readMessages([{
|
|
544
595
|
remoteJid,
|
|
545
596
|
id,
|
|
546
|
-
participant
|
|
597
|
+
participant,
|
|
547
598
|
fromMe: false
|
|
548
599
|
}]);
|
|
549
|
-
const suffix =
|
|
600
|
+
const suffix = participant ? ` (participant ${participant})` : "";
|
|
550
601
|
logWhatsAppVerbose(options.verbose, `Marked message ${id} as read for ${remoteJid}${suffix}`);
|
|
551
602
|
} catch (err) {
|
|
552
603
|
logWhatsAppVerbose(options.verbose, `Failed to mark message ${id} read: ${String(err)}`);
|
|
553
604
|
}
|
|
554
|
-
|
|
605
|
+
};
|
|
606
|
+
const maybeLogSkippedSelfChatReadReceipt = (inbound, target) => {
|
|
607
|
+
if (target?.id && inbound.access.isSelfChat && options.verbose) logWhatsAppVerbose(options.verbose, `Self-chat mode: skipping read receipt for ${target.id}`);
|
|
608
|
+
};
|
|
609
|
+
const maybeMarkReadReceiptAfterCompletedDelivery = async (inbound, target) => {
|
|
610
|
+
if (inbound.access.isSelfChat) {
|
|
611
|
+
maybeLogSkippedSelfChatReadReceipt(inbound, target);
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
await maybeMarkInboundAsRead(target);
|
|
615
|
+
};
|
|
616
|
+
const maybeMarkReadReceiptForSkippedAppend = async (inbound, target) => {
|
|
617
|
+
if (inbound.access.isSelfChat) {
|
|
618
|
+
maybeLogSkippedSelfChatReadReceipt(inbound, target);
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
await maybeMarkInboundAsRead(target);
|
|
622
|
+
};
|
|
623
|
+
const completeUndeliverableDurableInbound = async (durableId, metadata) => {
|
|
624
|
+
if (!durableId) return;
|
|
625
|
+
await durableInboundJournal.complete(durableId, metadata?.readReceipt ? { metadata: { readReceipt: metadata.readReceipt } } : void 0);
|
|
626
|
+
};
|
|
627
|
+
const buildDurableInboundPayload = (msg, upsertType) => ({
|
|
628
|
+
message: serializeWhatsAppDurableInboundMessage(msg),
|
|
629
|
+
...upsertType ? { upsertType } : {},
|
|
630
|
+
receivedAt: Date.now()
|
|
631
|
+
});
|
|
632
|
+
const shouldSkipStaleAppend = (msg, upsertType) => {
|
|
633
|
+
if (upsertType !== "append") return false;
|
|
634
|
+
const APPEND_RECENT_GRACE_MS = 6e4;
|
|
635
|
+
const msgTsRaw = msg.messageTimestamp;
|
|
636
|
+
const msgTsNum = msgTsRaw != null ? Number(msgTsRaw) : NaN;
|
|
637
|
+
return (Number.isFinite(msgTsNum) ? msgTsNum * 1e3 : 0) < connectedAtMs - APPEND_RECENT_GRACE_MS;
|
|
638
|
+
};
|
|
639
|
+
const processDurableInboundMessage = async (msg, upsertType, stored) => {
|
|
640
|
+
const inbound = await normalizeInboundMessage(msg);
|
|
641
|
+
if (!inbound) {
|
|
642
|
+
if (stored) await completeUndeliverableDurableInbound(stored.id, stored.metadata);
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
const readReceipt = stored?.metadata?.readReceipt ?? buildReadReceiptTarget(inbound);
|
|
646
|
+
const deliveryReadReceipt = inbound.access.isSelfChat ? void 0 : readReceipt;
|
|
647
|
+
if (!stored && shouldSkipStaleAppend(msg, upsertType)) {
|
|
648
|
+
await maybeMarkReadReceiptForSkippedAppend(inbound, readReceipt);
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
let durableId = stored?.id ?? (inbound.id ? createWhatsAppDurableInboundMessageId({
|
|
652
|
+
remoteJid: inbound.remoteJid,
|
|
653
|
+
id: inbound.id
|
|
654
|
+
}) : void 0);
|
|
655
|
+
const durableMetadata = deliveryReadReceipt ? { readReceipt: deliveryReadReceipt } : void 0;
|
|
656
|
+
if (durableId && !stored) try {
|
|
657
|
+
const accepted = await durableInboundJournal.accept(durableId, buildDurableInboundPayload(msg, upsertType), {
|
|
658
|
+
metadata: durableMetadata,
|
|
659
|
+
receivedAt: inbound.messageTimestampMs
|
|
660
|
+
});
|
|
661
|
+
if (accepted.kind === "completed") {
|
|
662
|
+
await maybeMarkReadReceiptAfterCompletedDelivery(inbound, accepted.record.metadata?.readReceipt ?? deliveryReadReceipt);
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
if (accepted.kind === "pending" && accepted.record.attempts === 0) return;
|
|
666
|
+
} catch (err) {
|
|
667
|
+
durableId = void 0;
|
|
668
|
+
const error = formatError(err);
|
|
669
|
+
inboundLogger.warn({ error }, "failed persisting durable WhatsApp inbound; delivering live");
|
|
670
|
+
inboundConsoleLog.warn(`Failed persisting durable WhatsApp inbound; delivering live: ${error}`);
|
|
671
|
+
}
|
|
672
|
+
const enriched = await enrichInboundMessage(msg);
|
|
673
|
+
if (!enriched) {
|
|
674
|
+
await completeUndeliverableDurableInbound(durableId, durableMetadata);
|
|
675
|
+
await maybeMarkReadReceiptAfterCompletedDelivery(inbound, deliveryReadReceipt);
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
const dedupeKey = inbound.id ? `${options.accountId}:${inbound.remoteJid}:${inbound.id}` : "";
|
|
679
|
+
const dedupeClaim = dedupeKey ? await claimRecentInboundMessageDelivery(dedupeKey) : "claimed";
|
|
680
|
+
if (dedupeClaim !== "claimed") {
|
|
681
|
+
if (dedupeClaim === "duplicate") {
|
|
682
|
+
await completeUndeliverableDurableInbound(durableId, durableMetadata);
|
|
683
|
+
await maybeMarkReadReceiptAfterCompletedDelivery(inbound, deliveryReadReceipt);
|
|
684
|
+
}
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
recordAcceptedInboundActivity(options.accountId);
|
|
688
|
+
await enqueueInboundMessage(msg, inbound, enriched, {
|
|
689
|
+
durableId,
|
|
690
|
+
readReceipt: deliveryReadReceipt
|
|
691
|
+
});
|
|
692
|
+
};
|
|
693
|
+
const replayPendingDurableInboundMessages = async () => {
|
|
694
|
+
const pending = await durableInboundJournal.pending();
|
|
695
|
+
for (const record of pending) await processDurableInboundMessage(deserializeWhatsAppDurableInboundMessage(record.payload.message), record.payload.upsertType, {
|
|
696
|
+
id: record.id,
|
|
697
|
+
payload: record.payload,
|
|
698
|
+
metadata: record.metadata
|
|
699
|
+
});
|
|
555
700
|
};
|
|
556
701
|
const enrichInboundMessage = async (msg) => {
|
|
557
702
|
const location = extractLocationData(msg.message ?? void 0);
|
|
@@ -590,7 +735,7 @@ async function attachWebInboxToSocket(options) {
|
|
|
590
735
|
mediaFileName
|
|
591
736
|
};
|
|
592
737
|
};
|
|
593
|
-
const enqueueInboundMessage = async (msg, inbound, enriched) => {
|
|
738
|
+
const enqueueInboundMessage = async (msg, inbound, enriched, durable) => {
|
|
594
739
|
const chatJid = inbound.remoteJid;
|
|
595
740
|
const sendComposing = async () => {
|
|
596
741
|
const currentSock = getCurrentSock();
|
|
@@ -668,7 +813,9 @@ async function attachWebInboxToSocket(options) {
|
|
|
668
813
|
mediaPath: enriched.mediaPath,
|
|
669
814
|
mediaType: enriched.mediaType,
|
|
670
815
|
mediaFileName: enriched.mediaFileName,
|
|
671
|
-
dedupeKey: inbound.id ? `${options.accountId}:${inbound.remoteJid}:${inbound.id}` : void 0
|
|
816
|
+
dedupeKey: inbound.id ? `${options.accountId}:${inbound.remoteJid}:${inbound.id}` : void 0,
|
|
817
|
+
durableId: durable.durableId,
|
|
818
|
+
readReceipt: durable.readReceipt
|
|
672
819
|
};
|
|
673
820
|
const debounceKey = buildInboundDebounceKey(inboundMessage);
|
|
674
821
|
if (debounceKey) {
|
|
@@ -695,21 +842,16 @@ async function attachWebInboxToSocket(options) {
|
|
|
695
842
|
const handleMessagesUpsert = async (upsert) => {
|
|
696
843
|
if (upsert.type !== "notify" && upsert.type !== "append") return;
|
|
697
844
|
for (const msg of upsert.messages ?? []) {
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
if (!enriched) continue;
|
|
709
|
-
const dedupeKey = inbound.id ? `${options.accountId}:${inbound.remoteJid}:${inbound.id}` : "";
|
|
710
|
-
if (dedupeKey && !await claimRecentInboundMessage(dedupeKey)) continue;
|
|
711
|
-
recordAcceptedInboundActivity(options.accountId);
|
|
712
|
-
await enqueueInboundMessage(msg, inbound, enriched);
|
|
845
|
+
if (await maybeResolveWhatsAppApprovalReaction({
|
|
846
|
+
cfg: options.loadConfig?.() ?? options.cfg,
|
|
847
|
+
accountId: options.accountId,
|
|
848
|
+
msg,
|
|
849
|
+
selfJid: self.jid,
|
|
850
|
+
selfLid: self.lid,
|
|
851
|
+
resolveInboundJid,
|
|
852
|
+
logVerboseMessage: (message) => logWhatsAppVerbose(options.verbose, message)
|
|
853
|
+
})) continue;
|
|
854
|
+
await processDurableInboundMessage(msg, upsert.type);
|
|
713
855
|
}
|
|
714
856
|
};
|
|
715
857
|
const handleMessagesUpsertEvent = (upsert) => {
|
|
@@ -773,6 +915,14 @@ async function attachWebInboxToSocket(options) {
|
|
|
773
915
|
};
|
|
774
916
|
const detachMessagesUpsert = attachEmitterListener(sock.ev, "messages.upsert", handleMessagesUpsertEvent);
|
|
775
917
|
const detachConnectionUpdate = attachEmitterListener(sock.ev, "connection.update", handleConnectionUpdate);
|
|
918
|
+
const replayTask = replayPendingDurableInboundMessages().catch((err) => {
|
|
919
|
+
inboundLogger.error({ error: String(err) }, "failed replaying durable WhatsApp inbound");
|
|
920
|
+
inboundConsoleLog.error(`Failed replaying durable WhatsApp inbound: ${String(err)}`);
|
|
921
|
+
});
|
|
922
|
+
pendingMessageHandlers.add(replayTask);
|
|
923
|
+
replayTask.finally(() => {
|
|
924
|
+
pendingMessageHandlers.delete(replayTask);
|
|
925
|
+
});
|
|
776
926
|
(async () => {
|
|
777
927
|
try {
|
|
778
928
|
const groups = await sock.groupFetchAllParticipating();
|
|
@@ -1496,6 +1646,21 @@ function createWhatsAppReplyDeliveryReceipt(results) {
|
|
|
1496
1646
|
kind: resolveWhatsAppReceiptKind(results)
|
|
1497
1647
|
});
|
|
1498
1648
|
}
|
|
1649
|
+
function markWhatsAppVisibleDeliveryError(error) {
|
|
1650
|
+
if (typeof error === "object" && error !== null && !Array.isArray(error)) try {
|
|
1651
|
+
Object.assign(error, {
|
|
1652
|
+
sentBeforeError: true,
|
|
1653
|
+
visibleReplySent: true
|
|
1654
|
+
});
|
|
1655
|
+
return error;
|
|
1656
|
+
} catch {}
|
|
1657
|
+
const visibleError = new Error("visible WhatsApp reply delivery failed", { cause: error });
|
|
1658
|
+
Object.assign(visibleError, {
|
|
1659
|
+
sentBeforeError: true,
|
|
1660
|
+
visibleReplySent: true
|
|
1661
|
+
});
|
|
1662
|
+
return visibleError;
|
|
1663
|
+
}
|
|
1499
1664
|
async function deliverWebReply(params) {
|
|
1500
1665
|
const { replyResult, msg, maxMediaBytes, textLimit, replyLogger, connectionId, skipLog } = params;
|
|
1501
1666
|
const replyStarted = Date.now();
|
|
@@ -1531,13 +1696,18 @@ async function deliverWebReply(params) {
|
|
|
1531
1696
|
});
|
|
1532
1697
|
};
|
|
1533
1698
|
const sendWithRetry = async (fn, label, maxAttempts = 3) => {
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1699
|
+
try {
|
|
1700
|
+
return await sendWhatsAppOutboundWithRetry({
|
|
1701
|
+
send: fn,
|
|
1702
|
+
maxAttempts,
|
|
1703
|
+
onRetry: ({ attempt, maxAttempts: retryMaxAttempts, backoffMs, errorText }) => {
|
|
1704
|
+
logVerbose(`Retrying ${label} to ${msg.from} after failure (${attempt}/${retryMaxAttempts - 1}) in ${backoffMs}ms: ${errorText}`);
|
|
1705
|
+
}
|
|
1706
|
+
});
|
|
1707
|
+
} catch (error) {
|
|
1708
|
+
if (sendResults.some((result) => result.providerAccepted)) throw markWhatsAppVisibleDeliveryError(error);
|
|
1709
|
+
throw error;
|
|
1710
|
+
}
|
|
1541
1711
|
};
|
|
1542
1712
|
if (mediaList.length === 0 && textChunks.length) {
|
|
1543
1713
|
const totalChunks = textChunks.length;
|
|
@@ -1679,9 +1849,42 @@ function resolveVisibleWhatsAppReplyContext(params) {
|
|
|
1679
1849
|
}
|
|
1680
1850
|
//#endregion
|
|
1681
1851
|
//#region extensions/whatsapp/src/auto-reply/monitor/inbound-dispatch.ts
|
|
1852
|
+
function normalizeErrForLog(err) {
|
|
1853
|
+
if (err instanceof Error) return {
|
|
1854
|
+
...Object.fromEntries(Object.entries(err)),
|
|
1855
|
+
type: err.name,
|
|
1856
|
+
message: err.message,
|
|
1857
|
+
stack: err.stack
|
|
1858
|
+
};
|
|
1859
|
+
return err;
|
|
1860
|
+
}
|
|
1861
|
+
function whatsAppReplyDeliveryVisibility(visibleReplySent) {
|
|
1862
|
+
return { visibleReplySent };
|
|
1863
|
+
}
|
|
1864
|
+
function whatsAppReplyDeliveryVisibilityFromDurableResult(result) {
|
|
1865
|
+
return whatsAppReplyDeliveryVisibility(result.visibleReplySent === true);
|
|
1866
|
+
}
|
|
1867
|
+
function markWhatsAppReplyDeliveryErrorVisible(error) {
|
|
1868
|
+
if (typeof error === "object" && error !== null && !Array.isArray(error)) try {
|
|
1869
|
+
Object.assign(error, {
|
|
1870
|
+
sentBeforeError: true,
|
|
1871
|
+
visibleReplySent: true
|
|
1872
|
+
});
|
|
1873
|
+
return error;
|
|
1874
|
+
} catch {}
|
|
1875
|
+
const visibleError = new Error("visible WhatsApp reply delivery failed", { cause: error });
|
|
1876
|
+
Object.assign(visibleError, {
|
|
1877
|
+
sentBeforeError: true,
|
|
1878
|
+
visibleReplySent: true
|
|
1879
|
+
});
|
|
1880
|
+
return visibleError;
|
|
1881
|
+
}
|
|
1882
|
+
function markWhatsAppReplyDeliveryErrorVisibleAfterFlush(error, flushResult) {
|
|
1883
|
+
return flushResult.delivered > 0 ? markWhatsAppReplyDeliveryErrorVisible(error) : error;
|
|
1884
|
+
}
|
|
1682
1885
|
function logWhatsAppReplyDeliveryError(params) {
|
|
1683
1886
|
params.replyLogger.error({
|
|
1684
|
-
err: params.err,
|
|
1887
|
+
err: normalizeErrForLog(params.err),
|
|
1685
1888
|
replyKind: params.info.kind,
|
|
1686
1889
|
correlationId: params.msg.id ?? null,
|
|
1687
1890
|
connectionId: params.connectionId,
|
|
@@ -1730,8 +1933,11 @@ function createWhatsAppMediaOnlyReplyCoalescer(params) {
|
|
|
1730
1933
|
flushResult.droppedDuplicateMedia += 1;
|
|
1731
1934
|
continue;
|
|
1732
1935
|
}
|
|
1733
|
-
|
|
1734
|
-
|
|
1936
|
+
try {
|
|
1937
|
+
if ((await params.deliver(candidate)).visibleReplySent) flushResult.delivered += 1;
|
|
1938
|
+
} catch (error) {
|
|
1939
|
+
throw markWhatsAppReplyDeliveryErrorVisibleAfterFlush(error, flushResult);
|
|
1940
|
+
}
|
|
1735
1941
|
}
|
|
1736
1942
|
return flushResult;
|
|
1737
1943
|
};
|
|
@@ -1895,7 +2101,7 @@ async function dispatchWhatsAppBufferedReply(params) {
|
|
|
1895
2101
|
let didLogHeartbeatStrip = false;
|
|
1896
2102
|
const deliverNormalizedPayload = async (normalizedDeliveryPayload, info) => {
|
|
1897
2103
|
const reply = resolveSendableOutboundReplyParts(normalizedDeliveryPayload);
|
|
1898
|
-
if (!reply.hasMedia && !reply.text.trim()) return;
|
|
2104
|
+
if (!reply.hasMedia && !reply.text.trim()) return whatsAppReplyDeliveryVisibility(false);
|
|
1899
2105
|
if (!(await params.deliverReply({
|
|
1900
2106
|
replyResult: normalizedDeliveryPayload,
|
|
1901
2107
|
normalizedReplyResult: normalizedDeliveryPayload,
|
|
@@ -1918,7 +2124,7 @@ async function dispatchWhatsAppBufferedReply(params) {
|
|
|
1918
2124
|
from: params.msg.to,
|
|
1919
2125
|
replyKind: info.kind
|
|
1920
2126
|
}, "auto-reply was not accepted by WhatsApp provider");
|
|
1921
|
-
return;
|
|
2127
|
+
return whatsAppReplyDeliveryVisibility(false);
|
|
1922
2128
|
}
|
|
1923
2129
|
didSendReply = true;
|
|
1924
2130
|
const shouldLog = normalizedDeliveryPayload.text ? true : void 0;
|
|
@@ -1929,9 +2135,10 @@ async function dispatchWhatsAppBufferedReply(params) {
|
|
|
1929
2135
|
});
|
|
1930
2136
|
const fromDisplay = params.msg.chatType === "group" ? params.conversationId : params.msg.from ?? "unknown";
|
|
1931
2137
|
if (shouldLogVerbose$1()) logVerbose$1(`Reply body: ${normalizedDeliveryPayload.text != null ? reply.text : "<media>"}${reply.hasMedia ? " (media)" : ""} -> ${fromDisplay}`);
|
|
2138
|
+
return whatsAppReplyDeliveryVisibility(true);
|
|
1932
2139
|
};
|
|
1933
2140
|
const mediaOnlyCoalescer = createWhatsAppMediaOnlyReplyCoalescer({ deliver: async (pending) => {
|
|
1934
|
-
await deliverNormalizedPayload(pending.payload, pending.info);
|
|
2141
|
+
return await deliverNormalizedPayload(pending.payload, pending.info);
|
|
1935
2142
|
} });
|
|
1936
2143
|
if (statusReactionController) statusReactionController.setThinking();
|
|
1937
2144
|
const { queuedFinal, counts } = await dispatchReplyWithBufferedBlockDispatcher({
|
|
@@ -1948,45 +2155,53 @@ async function dispatchWhatsAppBufferedReply(params) {
|
|
|
1948
2155
|
},
|
|
1949
2156
|
deliver: async (payload, info) => {
|
|
1950
2157
|
const deliveryPayload = resolveWhatsAppDeliverablePayload(payload, info);
|
|
1951
|
-
if (!deliveryPayload) return;
|
|
2158
|
+
if (!deliveryPayload) return whatsAppReplyDeliveryVisibility(false);
|
|
1952
2159
|
const normalizedOutboundPayload = normalizeWhatsAppOutboundPayload(deliveryPayload, { normalizeText: normalizeWhatsAppPayloadTextPreservingIndentation });
|
|
1953
2160
|
const normalizedDeliveryPayload = deliveryPayload.text === void 0 ? {
|
|
1954
2161
|
...normalizedOutboundPayload,
|
|
1955
2162
|
text: void 0
|
|
1956
2163
|
} : normalizedOutboundPayload;
|
|
1957
2164
|
const reply = resolveSendableOutboundReplyParts(normalizedDeliveryPayload);
|
|
1958
|
-
if (!reply.hasMedia && !reply.text.trim()) return;
|
|
2165
|
+
if (!reply.hasMedia && !reply.text.trim()) return whatsAppReplyDeliveryVisibility(false);
|
|
1959
2166
|
if (!reply.hasMedia) {
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
if (durable.status === "handled_visible") {
|
|
1978
|
-
didSendReply = true;
|
|
1979
|
-
const shouldLog = normalizedDeliveryPayload.text ? true : void 0;
|
|
1980
|
-
params.rememberSentText(normalizedDeliveryPayload.text, {
|
|
1981
|
-
combinedBody: params.context.Body,
|
|
1982
|
-
combinedBodySessionKey: params.route.sessionKey,
|
|
1983
|
-
logVerboseMessage: shouldLog
|
|
2167
|
+
const flushResult = await mediaOnlyCoalescer.flushAll();
|
|
2168
|
+
logWhatsAppMediaOnlyFlushResult(flushResult);
|
|
2169
|
+
try {
|
|
2170
|
+
const durable = await deliverInboundReplyWithMessageSendContext({
|
|
2171
|
+
cfg: params.cfg,
|
|
2172
|
+
channel: "whatsapp",
|
|
2173
|
+
accountId: params.route.accountId,
|
|
2174
|
+
agentId: params.route.agentId,
|
|
2175
|
+
ctxPayload: params.context,
|
|
2176
|
+
payload: normalizedDeliveryPayload,
|
|
2177
|
+
info,
|
|
2178
|
+
to: params.msg.from,
|
|
2179
|
+
formatting: {
|
|
2180
|
+
textLimit,
|
|
2181
|
+
tableMode,
|
|
2182
|
+
chunkMode
|
|
2183
|
+
}
|
|
1984
2184
|
});
|
|
1985
|
-
|
|
2185
|
+
if (durable.status === "failed") {
|
|
2186
|
+
if (durable.sentBeforeError === true) throw markWhatsAppReplyDeliveryErrorVisible(durable.error);
|
|
2187
|
+
throw durable.error;
|
|
2188
|
+
}
|
|
2189
|
+
if (durable.status === "handled_visible") {
|
|
2190
|
+
didSendReply = true;
|
|
2191
|
+
const shouldLog = normalizedDeliveryPayload.text ? true : void 0;
|
|
2192
|
+
params.rememberSentText(normalizedDeliveryPayload.text, {
|
|
2193
|
+
combinedBody: params.context.Body,
|
|
2194
|
+
combinedBodySessionKey: params.route.sessionKey,
|
|
2195
|
+
logVerboseMessage: shouldLog
|
|
2196
|
+
});
|
|
2197
|
+
return whatsAppReplyDeliveryVisibilityFromDurableResult(durable.delivery);
|
|
2198
|
+
}
|
|
2199
|
+
if (durable.status === "handled_no_send") return flushResult.delivered > 0 ? whatsAppReplyDeliveryVisibility(true) : whatsAppReplyDeliveryVisibilityFromDurableResult(durable.delivery);
|
|
2200
|
+
const delivery = await deliverNormalizedPayload(normalizedDeliveryPayload, info);
|
|
2201
|
+
return flushResult.delivered > 0 && !delivery.visibleReplySent ? whatsAppReplyDeliveryVisibility(true) : delivery;
|
|
2202
|
+
} catch (error) {
|
|
2203
|
+
throw markWhatsAppReplyDeliveryErrorVisibleAfterFlush(error, flushResult);
|
|
1986
2204
|
}
|
|
1987
|
-
if (durable.status === "handled_no_send") return;
|
|
1988
|
-
await deliverNormalizedPayload(normalizedDeliveryPayload, info);
|
|
1989
|
-
return;
|
|
1990
2205
|
}
|
|
1991
2206
|
const mediaUrls = getWhatsAppPayloadMediaUrls(normalizedDeliveryPayload);
|
|
1992
2207
|
if (shouldDeferWhatsAppMediaOnlyPayload({
|
|
@@ -1999,10 +2214,21 @@ async function dispatchWhatsAppBufferedReply(params) {
|
|
|
1999
2214
|
mediaUrls,
|
|
2000
2215
|
payload: normalizedDeliveryPayload
|
|
2001
2216
|
});
|
|
2002
|
-
return;
|
|
2217
|
+
return whatsAppReplyDeliveryVisibility(false);
|
|
2003
2218
|
}
|
|
2004
|
-
|
|
2005
|
-
|
|
2219
|
+
const flushResult = await mediaOnlyCoalescer.flushExceptDuplicateMedia(mediaUrls);
|
|
2220
|
+
logWhatsAppMediaOnlyFlushResult(flushResult);
|
|
2221
|
+
try {
|
|
2222
|
+
const delivery = await deliverNormalizedPayload(normalizedDeliveryPayload, info);
|
|
2223
|
+
return flushResult.delivered > 0 && !delivery.visibleReplySent ? whatsAppReplyDeliveryVisibility(true) : delivery;
|
|
2224
|
+
} catch (error) {
|
|
2225
|
+
throw markWhatsAppReplyDeliveryErrorVisibleAfterFlush(error, flushResult);
|
|
2226
|
+
}
|
|
2227
|
+
},
|
|
2228
|
+
onSettled: async () => {
|
|
2229
|
+
const flushResult = await mediaOnlyCoalescer.flushAll();
|
|
2230
|
+
logWhatsAppMediaOnlyFlushResult(flushResult);
|
|
2231
|
+
return whatsAppReplyDeliveryVisibility(flushResult.delivered > 0);
|
|
2006
2232
|
},
|
|
2007
2233
|
onReplyStart: params.msg.sendComposing,
|
|
2008
2234
|
...statusReactionController ? {
|
|
@@ -2035,7 +2261,6 @@ async function dispatchWhatsAppBufferedReply(params) {
|
|
|
2035
2261
|
} } : {}
|
|
2036
2262
|
}
|
|
2037
2263
|
});
|
|
2038
|
-
logWhatsAppMediaOnlyFlushResult(await mediaOnlyCoalescer.flushAll());
|
|
2039
2264
|
if (!hasVisibleInboundReplyDispatch({
|
|
2040
2265
|
queuedFinal,
|
|
2041
2266
|
counts
|
|
@@ -3054,6 +3279,14 @@ async function monitorWebChannel(verbose, listenerFactory = attachWebInboxToSock
|
|
|
3054
3279
|
continue;
|
|
3055
3280
|
}
|
|
3056
3281
|
statusController.noteConnected();
|
|
3282
|
+
const approvalContextLease = registerChannelRuntimeContext({
|
|
3283
|
+
channelRuntime: tuning.channelRuntime,
|
|
3284
|
+
channelId: "whatsapp",
|
|
3285
|
+
accountId: account.accountId,
|
|
3286
|
+
capability: CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY,
|
|
3287
|
+
context: { accountId: account.accountId },
|
|
3288
|
+
abortSignal
|
|
3289
|
+
});
|
|
3057
3290
|
controller.setUnhandledRejectionCleanup(registerUnhandledRejectionHandler((reason) => {
|
|
3058
3291
|
if (!isLikelyWhatsAppCryptoError(reason)) return false;
|
|
3059
3292
|
const errorStr = formatError(reason);
|
|
@@ -3121,10 +3354,14 @@ async function monitorWebChannel(verbose, listenerFactory = attachWebInboxToSock
|
|
|
3121
3354
|
if (process.stdout.isTTY || process.stderr.isTTY) whatsappLog.raw("Ctrl+C to stop.");
|
|
3122
3355
|
if (!keepAlive) {
|
|
3123
3356
|
clearInterval(periodicDrainInterval);
|
|
3357
|
+
approvalContextLease?.dispose();
|
|
3124
3358
|
await controller.shutdown();
|
|
3125
3359
|
return;
|
|
3126
3360
|
}
|
|
3127
|
-
const reason = await controller.waitForClose().finally(() =>
|
|
3361
|
+
const reason = await controller.waitForClose().finally(() => {
|
|
3362
|
+
clearInterval(periodicDrainInterval);
|
|
3363
|
+
approvalContextLease?.dispose();
|
|
3364
|
+
});
|
|
3128
3365
|
if (stopRequested() || sigintStop || reason === "aborted") {
|
|
3129
3366
|
await controller.shutdown();
|
|
3130
3367
|
break;
|
|
@@ -6,7 +6,7 @@ import { chunkText } from "openclaw/plugin-sdk/reply-chunking";
|
|
|
6
6
|
//#region extensions/whatsapp/src/outbound-adapter.ts
|
|
7
7
|
let whatsAppSendModulePromise;
|
|
8
8
|
function loadWhatsAppSendModule() {
|
|
9
|
-
whatsAppSendModulePromise ??= import("./send-
|
|
9
|
+
whatsAppSendModulePromise ??= import("./send-C9jEw6hx.js").then((n) => n.a);
|
|
10
10
|
return whatsAppSendModulePromise;
|
|
11
11
|
}
|
|
12
12
|
function normalizeOutboundText(text) {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as whatsappOutbound } from "./outbound-adapter-
|
|
1
|
+
import { t as whatsappOutbound } from "./outbound-adapter-BObZXXzU.js";
|
|
2
2
|
export { whatsappOutbound };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
|
2
2
|
//#region extensions/whatsapp/src/runtime.ts
|
|
3
|
-
const { setRuntime: setWhatsAppRuntime, getRuntime: getWhatsAppRuntime } = createPluginRuntimeStore({
|
|
3
|
+
const { setRuntime: setWhatsAppRuntime, getRuntime: getWhatsAppRuntime, tryGetRuntime: getOptionalWhatsAppRuntime } = createPluginRuntimeStore({
|
|
4
4
|
pluginId: "whatsapp",
|
|
5
5
|
errorMessage: "WhatsApp runtime not initialized"
|
|
6
6
|
});
|
|
7
7
|
//#endregion
|
|
8
|
-
export {
|
|
8
|
+
export { getWhatsAppRuntime as n, setWhatsAppRuntime as r, getOptionalWhatsAppRuntime as t };
|