@openclaw/whatsapp 2026.5.2-beta.2 → 2026.5.3-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/access-control-BQ3tCkH8.js +288 -0
- package/dist/account-config-CNQ33oav.js +47 -0
- package/dist/account-ids-DG18xddX.js +5 -0
- package/dist/accounts-BDqgpFEB.js +116 -0
- package/dist/action-runtime-DTGNgG-i.js +74 -0
- package/dist/action-runtime-api.js +2 -0
- package/dist/action-runtime.runtime.js +2 -0
- package/dist/active-listener-N7GFKsuN.js +11 -0
- package/dist/agent-tools-login-DpRxLNRB.js +89 -0
- package/dist/api.js +148 -0
- package/dist/audio-preflight.runtime-Bcdsl_ri.js +7 -0
- package/dist/auth-presence.js +32 -0
- package/dist/auth-store-BjCb50Ry.js +381 -0
- package/dist/channel-DQ-5Xoj9.js +542 -0
- package/dist/channel-config-api.js +2 -0
- package/dist/channel-plugin-api.js +2 -0
- package/dist/channel-react-action-Df20qAy9.js +42 -0
- package/dist/channel.runtime-DKXRnA8x.js +55 -0
- package/dist/channel.setup-DOHR2BGp.js +20 -0
- package/dist/command-policy-O8sRnqUV.js +8 -0
- package/dist/config-schema-Dmo66Ubb.js +27 -0
- package/dist/connection-controller-BiHAsTM8.js +596 -0
- package/dist/connection-controller-registry-D_iIGz5m.js +22 -0
- package/dist/constants-DLGCIbfl.js +4 -0
- package/dist/constants.js +2 -0
- package/dist/contract-api.js +19 -0
- package/dist/creds-files-_2V8jzQa.js +19 -0
- package/dist/directory-config-DVs4ffXu.js +37 -0
- package/dist/directory-contract-api.js +2 -0
- package/dist/doctor-A9tXm9Om.js +48 -0
- package/dist/doctor-contract-api.js +10 -0
- package/dist/group-session-contract-B8QBn0I2.js +15 -0
- package/dist/identity-QHAlV7Fu.js +75 -0
- package/dist/index.js +18 -0
- package/dist/legacy-session-surface-api.js +8 -0
- package/dist/legacy-state-migrations-api.js +2 -0
- package/dist/light-runtime-api.js +5 -0
- package/dist/login-DymdrKca.js +52 -0
- package/dist/login-qr-DIS0Iv-7.js +378 -0
- package/dist/login-qr-api.js +2 -0
- package/dist/login-qr-runtime.js +16 -0
- package/dist/monitor-C4Fhg_lD.js +3349 -0
- package/dist/normalize-CWYiGkXw.js +2 -0
- package/dist/normalize-target-BPVHNsM5.js +74 -0
- package/dist/outbound-adapter-BssVnZdz.js +29 -0
- package/dist/outbound-base-Bq1UYEK5.js +119 -0
- package/dist/outbound-media-contract-CGss_QHy.js +163 -0
- package/dist/outbound-payload-test-api.js +2 -0
- package/dist/quoted-message-TENQzyxV.js +108 -0
- package/dist/reaction-level-CRVEVAfi.js +16 -0
- package/dist/reply-resolver.runtime-BRCgoO4C.js +2 -0
- package/dist/resolve-outbound-target-CN-Wo6IY.js +39 -0
- package/dist/rolldown-runtime-RkAeH_Qm.js +27 -0
- package/dist/runtime-6fZ67abR.js +8 -0
- package/dist/runtime-api.js +15 -0
- package/dist/runtime-group-policy-Gp1lQ0at.js +11 -0
- package/dist/secret-contract-api.js +5 -0
- package/dist/security-contract-DqH8JDX6.js +26 -0
- package/dist/security-contract-api.js +2 -0
- package/dist/send-CIyLFxdZ.js +234 -0
- package/dist/session-contract-B0efQf9P.js +27 -0
- package/dist/session-errors-CSuKZPub.js +63 -0
- package/dist/session.runtime-C1eSE_KK.js +13 -0
- package/dist/setup-core-DZKvpzbH.js +46 -0
- package/dist/setup-entry.js +23 -0
- package/dist/setup-plugin-api.js +2 -0
- package/dist/setup-surface-ieFnIW4g.js +344 -0
- package/dist/shared-D_wzSVar.js +307 -0
- package/dist/state-migrations-DnCdvoYD.js +39 -0
- package/dist/targets.js +2 -0
- package/dist/test-api.js +3 -0
- package/dist/text-runtime-C1zNiZeO.js +116 -0
- package/package.json +14 -6
- package/action-runtime-api.ts +0 -1
- package/action-runtime.runtime.ts +0 -1
- package/api.ts +0 -213
- package/auth-presence.ts +0 -80
- package/channel-config-api.ts +0 -1
- package/channel-plugin-api.ts +0 -3
- package/config-api.ts +0 -4
- package/constants.ts +0 -1
- package/contract-api.ts +0 -29
- package/directory-contract-api.ts +0 -4
- package/doctor-contract-api.ts +0 -8
- package/index.test.ts +0 -13
- package/index.ts +0 -16
- package/legacy-session-surface-api.ts +0 -6
- package/legacy-state-migrations-api.ts +0 -1
- package/light-runtime-api.ts +0 -12
- package/login-qr-api.ts +0 -1
- package/login-qr-runtime.ts +0 -23
- package/outbound-payload-test-api.ts +0 -1
- package/runtime-api.ts +0 -84
- package/secret-contract-api.ts +0 -4
- package/security-contract-api.ts +0 -4
- package/setup-entry.test.ts +0 -21
- package/setup-entry.ts +0 -21
- package/setup-plugin-api.ts +0 -3
- package/src/account-config.ts +0 -77
- package/src/account-ids.ts +0 -13
- package/src/account-types.ts +0 -5
- package/src/accounts.test.ts +0 -182
- package/src/accounts.ts +0 -176
- package/src/accounts.whatsapp-auth.test.ts +0 -59
- package/src/action-runtime-target-auth.ts +0 -27
- package/src/action-runtime.test.ts +0 -330
- package/src/action-runtime.ts +0 -76
- package/src/active-listener.test.ts +0 -65
- package/src/active-listener.ts +0 -17
- package/src/agent-tools-login.test.ts +0 -81
- package/src/agent-tools-login.ts +0 -113
- package/src/approval-auth.test.ts +0 -24
- package/src/approval-auth.ts +0 -27
- package/src/auth-store.runtime.ts +0 -1
- package/src/auth-store.test.ts +0 -311
- package/src/auth-store.ts +0 -502
- package/src/auto-reply/config.runtime.ts +0 -16
- package/src/auto-reply/constants.ts +0 -1
- package/src/auto-reply/deliver-reply.test.ts +0 -843
- package/src/auto-reply/deliver-reply.ts +0 -279
- package/src/auto-reply/loggers.ts +0 -6
- package/src/auto-reply/mentions.ts +0 -131
- package/src/auto-reply/monitor/ack-reaction.test.ts +0 -170
- package/src/auto-reply/monitor/ack-reaction.ts +0 -99
- package/src/auto-reply/monitor/audio-preflight.runtime.ts +0 -9
- package/src/auto-reply/monitor/broadcast.ts +0 -153
- package/src/auto-reply/monitor/commands.ts +0 -19
- package/src/auto-reply/monitor/echo.ts +0 -64
- package/src/auto-reply/monitor/group-activation.runtime.ts +0 -1
- package/src/auto-reply/monitor/group-activation.test.ts +0 -189
- package/src/auto-reply/monitor/group-activation.ts +0 -73
- package/src/auto-reply/monitor/group-gating.audio-preflight.test.ts +0 -103
- package/src/auto-reply/monitor/group-gating.runtime.ts +0 -8
- package/src/auto-reply/monitor/group-gating.ts +0 -217
- package/src/auto-reply/monitor/group-members.test.ts +0 -56
- package/src/auto-reply/monitor/group-members.ts +0 -65
- package/src/auto-reply/monitor/inbound-context.test.ts +0 -97
- package/src/auto-reply/monitor/inbound-context.ts +0 -92
- package/src/auto-reply/monitor/inbound-dispatch.runtime.ts +0 -21
- package/src/auto-reply/monitor/inbound-dispatch.test.ts +0 -895
- package/src/auto-reply/monitor/inbound-dispatch.ts +0 -422
- package/src/auto-reply/monitor/last-route.test.ts +0 -37
- package/src/auto-reply/monitor/last-route.ts +0 -61
- package/src/auto-reply/monitor/message-line.runtime.ts +0 -38
- package/src/auto-reply/monitor/message-line.ts +0 -54
- package/src/auto-reply/monitor/on-message.audio-preflight.test.ts +0 -354
- package/src/auto-reply/monitor/on-message.ts +0 -291
- package/src/auto-reply/monitor/peer.ts +0 -17
- package/src/auto-reply/monitor/process-message.audio-preflight.test.ts +0 -420
- package/src/auto-reply/monitor/process-message.test.ts +0 -355
- package/src/auto-reply/monitor/process-message.ts +0 -531
- package/src/auto-reply/monitor/runtime-api.ts +0 -30
- package/src/auto-reply/monitor-state.test.ts +0 -64
- package/src/auto-reply/monitor-state.ts +0 -106
- package/src/auto-reply/monitor.ts +0 -600
- package/src/auto-reply/reply-resolver.runtime.ts +0 -1
- package/src/auto-reply/types.ts +0 -48
- package/src/auto-reply/util.ts +0 -63
- package/src/auto-reply/web-auto-reply-monitor.test.ts +0 -687
- package/src/auto-reply/web-auto-reply-utils.test.ts +0 -392
- package/src/auto-reply.broadcast-groups.combined.test.ts +0 -246
- package/src/auto-reply.broadcast-groups.test-harness.ts +0 -47
- package/src/auto-reply.impl.ts +0 -6
- package/src/auto-reply.test-harness.ts +0 -421
- package/src/auto-reply.ts +0 -1
- package/src/auto-reply.web-auto-reply.compresses-common-formats-jpeg-cap.test.ts +0 -427
- package/src/auto-reply.web-auto-reply.connection-and-logging.e2e.test.ts +0 -908
- package/src/auto-reply.web-auto-reply.last-route.test.ts +0 -184
- package/src/channel-actions.runtime.ts +0 -7
- package/src/channel-actions.test.ts +0 -216
- package/src/channel-actions.ts +0 -84
- package/src/channel-outbound.test.ts +0 -131
- package/src/channel-outbound.ts +0 -36
- package/src/channel-react-action.runtime.ts +0 -7
- package/src/channel-react-action.test.ts +0 -294
- package/src/channel-react-action.ts +0 -84
- package/src/channel.runtime.ts +0 -117
- package/src/channel.setup.test.ts +0 -461
- package/src/channel.setup.ts +0 -28
- package/src/channel.ts +0 -334
- package/src/command-policy.ts +0 -7
- package/src/config-accessors.test.ts +0 -34
- package/src/config-accessors.ts +0 -22
- package/src/config-schema.test.ts +0 -121
- package/src/config-schema.ts +0 -6
- package/src/config-ui-hints.ts +0 -24
- package/src/connection-controller-registry.test.ts +0 -27
- package/src/connection-controller-registry.ts +0 -49
- package/src/connection-controller.test.ts +0 -282
- package/src/connection-controller.ts +0 -679
- package/src/creds-files.ts +0 -19
- package/src/creds-persistence.ts +0 -102
- package/src/directory-config.test.ts +0 -60
- package/src/directory-config.ts +0 -40
- package/src/directory-contract.test.ts +0 -56
- package/src/doctor-contract.ts +0 -11
- package/src/doctor.test.ts +0 -74
- package/src/doctor.ts +0 -56
- package/src/group-intro.ts +0 -15
- package/src/group-policy.test.ts +0 -36
- package/src/group-policy.ts +0 -40
- package/src/group-session-contract.ts +0 -20
- package/src/group-session-key.test.ts +0 -53
- package/src/group-session-key.ts +0 -41
- package/src/heartbeat.ts +0 -34
- package/src/identity.ts +0 -164
- package/src/inbound/access-control.test-harness.ts +0 -37
- package/src/inbound/access-control.test.ts +0 -375
- package/src/inbound/access-control.ts +0 -237
- package/src/inbound/dedupe.ts +0 -132
- package/src/inbound/extract.test.ts +0 -282
- package/src/inbound/extract.ts +0 -488
- package/src/inbound/lifecycle.ts +0 -39
- package/src/inbound/media.node.test.ts +0 -83
- package/src/inbound/media.ts +0 -102
- package/src/inbound/monitor.ts +0 -890
- package/src/inbound/runtime-api.ts +0 -7
- package/src/inbound/save-media.runtime.ts +0 -1
- package/src/inbound/send-api.test.ts +0 -307
- package/src/inbound/send-api.ts +0 -141
- package/src/inbound/send-result.ts +0 -61
- package/src/inbound/types.ts +0 -106
- package/src/inbound-context.contract.test.ts +0 -32
- package/src/inbound-policy.ts +0 -231
- package/src/inbound.media.test.ts +0 -320
- package/src/inbound.test.ts +0 -290
- package/src/inbound.ts +0 -9
- package/src/login-qr.test.ts +0 -483
- package/src/login-qr.ts +0 -542
- package/src/login.coverage.test.ts +0 -133
- package/src/login.test.ts +0 -89
- package/src/login.ts +0 -70
- package/src/logout.test.ts +0 -162
- package/src/media.test.ts +0 -480
- package/src/media.ts +0 -10
- package/src/monitor-inbox.allows-messages-from-senders-allowfrom-list.test-support.ts +0 -400
- package/src/monitor-inbox.append-upsert.test-support.ts +0 -133
- package/src/monitor-inbox.behavior.test.ts +0 -5
- package/src/monitor-inbox.blocks-messages-from-unauthorized-senders-not-allowfrom.test-support.ts +0 -362
- package/src/monitor-inbox.captures-media-path-image-messages.test-support.ts +0 -306
- package/src/monitor-inbox.streams-inbound-messages.test-support.ts +0 -729
- package/src/monitor-inbox.test-harness.ts +0 -304
- package/src/normalize-target.ts +0 -112
- package/src/normalize.ts +0 -6
- package/src/outbound-adapter.poll.test.ts +0 -62
- package/src/outbound-adapter.sendpayload.test.ts +0 -195
- package/src/outbound-adapter.ts +0 -36
- package/src/outbound-base.test.ts +0 -560
- package/src/outbound-base.ts +0 -244
- package/src/outbound-media-contract.ts +0 -278
- package/src/outbound-media.runtime.ts +0 -36
- package/src/outbound-payload.contract.test.ts +0 -61
- package/src/outbound-send-deps.ts +0 -1
- package/src/outbound-test-support.ts +0 -16
- package/src/pairing-security.test-harness.ts +0 -59
- package/src/qr-image.ts +0 -1
- package/src/qr-terminal.ts +0 -1
- package/src/quoted-message.test.ts +0 -83
- package/src/quoted-message.ts +0 -184
- package/src/reaction-level.test.ts +0 -94
- package/src/reaction-level.ts +0 -21
- package/src/reconnect.test.ts +0 -51
- package/src/reconnect.ts +0 -55
- package/src/resolve-outbound-target.test.ts +0 -265
- package/src/resolve-outbound-target.ts +0 -54
- package/src/resolve-target.test.ts +0 -97
- package/src/runtime-api.ts +0 -59
- package/src/runtime-group-policy.ts +0 -16
- package/src/runtime.ts +0 -9
- package/src/security-contract.ts +0 -47
- package/src/security-fix.ts +0 -71
- package/src/send.test.ts +0 -515
- package/src/send.ts +0 -287
- package/src/session-contract.test.ts +0 -31
- package/src/session-contract.ts +0 -43
- package/src/session-errors.ts +0 -125
- package/src/session-route.ts +0 -26
- package/src/session.runtime.ts +0 -8
- package/src/session.test.ts +0 -559
- package/src/session.ts +0 -330
- package/src/setup-core.ts +0 -52
- package/src/setup-finalize.ts +0 -446
- package/src/setup-surface.test.ts +0 -367
- package/src/setup-surface.ts +0 -69
- package/src/setup-test-helpers.ts +0 -216
- package/src/shared.ts +0 -291
- package/src/socket-timing.test.ts +0 -49
- package/src/socket-timing.ts +0 -38
- package/src/state-migrations.ts +0 -54
- package/src/status-issues.test.ts +0 -137
- package/src/status-issues.ts +0 -185
- package/src/system-prompt.test.ts +0 -199
- package/src/system-prompt.ts +0 -31
- package/src/targets-runtime.ts +0 -180
- package/src/test-helpers.ts +0 -690
- package/src/text-runtime.test.ts +0 -162
- package/src/text-runtime.ts +0 -11
- package/src/vcard.ts +0 -84
- package/targets.ts +0 -5
- package/test-api.ts +0 -2
- package/tsconfig.json +0 -16
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
|
2
|
+
import { normalizeE164 } from "openclaw/plugin-sdk/account-resolution";
|
|
3
|
+
//#region extensions/whatsapp/src/normalize-target.ts
|
|
4
|
+
const WHATSAPP_USER_JID_RE = /^(\d+)(?::\d+)?@s\.whatsapp\.net$/i;
|
|
5
|
+
const WHATSAPP_LEGACY_USER_JID_RE = /^(\d+)@c\.us$/i;
|
|
6
|
+
const WHATSAPP_LID_RE = /^(\d+)@lid$/i;
|
|
7
|
+
const NON_WHATSAPP_PROVIDER_PREFIX_RE = /^[a-z][a-z0-9-]*:/i;
|
|
8
|
+
const WHATSAPP_NEWSLETTER_JID_RE = /^([0-9]+)@newsletter$/i;
|
|
9
|
+
function stripWhatsAppTargetPrefixes(value) {
|
|
10
|
+
let candidate = value.trim();
|
|
11
|
+
for (;;) {
|
|
12
|
+
const before = candidate;
|
|
13
|
+
candidate = candidate.replace(/^whatsapp:/i, "").trim();
|
|
14
|
+
if (candidate === before) return candidate;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function isWhatsAppGroupJid(value) {
|
|
18
|
+
const candidate = stripWhatsAppTargetPrefixes(value);
|
|
19
|
+
if (!normalizeLowercaseStringOrEmpty(candidate).endsWith("@g.us")) return false;
|
|
20
|
+
const localPart = candidate.slice(0, candidate.length - 5);
|
|
21
|
+
if (!localPart || localPart.includes("@")) return false;
|
|
22
|
+
return /^[0-9]+(-[0-9]+)*$/.test(localPart);
|
|
23
|
+
}
|
|
24
|
+
function isWhatsAppNewsletterJid(value) {
|
|
25
|
+
const candidate = stripWhatsAppTargetPrefixes(value);
|
|
26
|
+
return WHATSAPP_NEWSLETTER_JID_RE.test(candidate);
|
|
27
|
+
}
|
|
28
|
+
function isWhatsAppUserTarget(value) {
|
|
29
|
+
const candidate = stripWhatsAppTargetPrefixes(value);
|
|
30
|
+
return WHATSAPP_USER_JID_RE.test(candidate) || WHATSAPP_LEGACY_USER_JID_RE.test(candidate) || WHATSAPP_LID_RE.test(candidate);
|
|
31
|
+
}
|
|
32
|
+
function extractUserJidPhone(jid) {
|
|
33
|
+
const userMatch = jid.match(WHATSAPP_USER_JID_RE);
|
|
34
|
+
if (userMatch) return userMatch[1];
|
|
35
|
+
const legacyUserMatch = jid.match(WHATSAPP_LEGACY_USER_JID_RE);
|
|
36
|
+
if (legacyUserMatch) return legacyUserMatch[1];
|
|
37
|
+
const lidMatch = jid.match(WHATSAPP_LID_RE);
|
|
38
|
+
if (lidMatch) return lidMatch[1];
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
function normalizeWhatsAppTarget(value) {
|
|
42
|
+
const candidate = stripWhatsAppTargetPrefixes(value);
|
|
43
|
+
if (!candidate) return null;
|
|
44
|
+
if (isWhatsAppGroupJid(candidate)) return `${candidate.slice(0, candidate.length - 5)}@g.us`;
|
|
45
|
+
if (isWhatsAppNewsletterJid(candidate)) {
|
|
46
|
+
const match = candidate.match(WHATSAPP_NEWSLETTER_JID_RE);
|
|
47
|
+
return match ? `${match[1]}@newsletter` : null;
|
|
48
|
+
}
|
|
49
|
+
if (isWhatsAppUserTarget(candidate)) {
|
|
50
|
+
const phone = extractUserJidPhone(candidate);
|
|
51
|
+
if (!phone) return null;
|
|
52
|
+
const normalized = normalizeE164(phone);
|
|
53
|
+
return normalized.length > 1 ? normalized : null;
|
|
54
|
+
}
|
|
55
|
+
if (candidate.includes("@")) return null;
|
|
56
|
+
if (NON_WHATSAPP_PROVIDER_PREFIX_RE.test(candidate)) return null;
|
|
57
|
+
const normalized = normalizeE164(candidate);
|
|
58
|
+
return normalized.length > 1 ? normalized : null;
|
|
59
|
+
}
|
|
60
|
+
function normalizeWhatsAppMessagingTarget(raw) {
|
|
61
|
+
const trimmed = raw.trim();
|
|
62
|
+
if (!trimmed) return;
|
|
63
|
+
return normalizeWhatsAppTarget(trimmed) ?? void 0;
|
|
64
|
+
}
|
|
65
|
+
function normalizeWhatsAppAllowFromEntries(allowFrom) {
|
|
66
|
+
return allowFrom.map((entry) => String(entry).trim()).filter((entry) => Boolean(entry)).map((entry) => entry === "*" ? entry : normalizeWhatsAppTarget(entry)).filter((entry) => Boolean(entry));
|
|
67
|
+
}
|
|
68
|
+
function looksLikeWhatsAppTargetId(raw) {
|
|
69
|
+
const trimmed = raw.trim();
|
|
70
|
+
if (!trimmed) return false;
|
|
71
|
+
return /^whatsapp:/i.test(trimmed) || isWhatsAppGroupJid(trimmed) || isWhatsAppNewsletterJid(trimmed) || isWhatsAppUserTarget(trimmed) || normalizeWhatsAppTarget(trimmed) !== null;
|
|
72
|
+
}
|
|
73
|
+
//#endregion
|
|
74
|
+
export { normalizeWhatsAppAllowFromEntries as a, looksLikeWhatsAppTargetId as i, isWhatsAppNewsletterJid as n, normalizeWhatsAppMessagingTarget as o, isWhatsAppUserTarget as r, normalizeWhatsAppTarget as s, isWhatsAppGroupJid as t };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { t as resolveWhatsAppOutboundTarget } from "./resolve-outbound-target-CN-Wo6IY.js";
|
|
2
|
+
import { n as normalizeWhatsAppPayloadText } from "./outbound-media-contract-CGss_QHy.js";
|
|
3
|
+
import { t as createWhatsAppOutboundBase } from "./outbound-base-Bq1UYEK5.js";
|
|
4
|
+
import { shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env";
|
|
5
|
+
import { chunkText } from "openclaw/plugin-sdk/reply-chunking";
|
|
6
|
+
//#region extensions/whatsapp/src/outbound-adapter.ts
|
|
7
|
+
let whatsAppSendModulePromise;
|
|
8
|
+
function loadWhatsAppSendModule() {
|
|
9
|
+
whatsAppSendModulePromise ??= import("./send-CIyLFxdZ.js").then((n) => n.a);
|
|
10
|
+
return whatsAppSendModulePromise;
|
|
11
|
+
}
|
|
12
|
+
function normalizeOutboundText(text) {
|
|
13
|
+
return normalizeWhatsAppPayloadText(text);
|
|
14
|
+
}
|
|
15
|
+
const whatsappOutbound = createWhatsAppOutboundBase({
|
|
16
|
+
chunker: chunkText,
|
|
17
|
+
sendMessageWhatsApp: async (to, text, options) => await (await loadWhatsAppSendModule()).sendMessageWhatsApp(to, normalizeOutboundText(text), { ...options }),
|
|
18
|
+
sendPollWhatsApp: async (to, poll, options) => await (await loadWhatsAppSendModule()).sendPollWhatsApp(to, poll, options),
|
|
19
|
+
shouldLogVerbose: () => shouldLogVerbose(),
|
|
20
|
+
resolveTarget: ({ to, allowFrom, mode }) => resolveWhatsAppOutboundTarget({
|
|
21
|
+
to,
|
|
22
|
+
allowFrom,
|
|
23
|
+
mode
|
|
24
|
+
}),
|
|
25
|
+
normalizeText: normalizeOutboundText,
|
|
26
|
+
skipEmptyText: true
|
|
27
|
+
});
|
|
28
|
+
//#endregion
|
|
29
|
+
export { whatsappOutbound as t };
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { s as toWhatsappJid } from "./text-runtime-C1zNiZeO.js";
|
|
2
|
+
import { n as normalizeWhatsAppPayloadText, t as normalizeWhatsAppOutboundPayload } from "./outbound-media-contract-CGss_QHy.js";
|
|
3
|
+
import { i as lookupInboundMessageMetaForTarget } from "./quoted-message-TENQzyxV.js";
|
|
4
|
+
import { DEFAULT_ACCOUNT_ID, listCombinedAccountIds, normalizeOptionalAccountId, resolveListedDefaultAccountId } from "openclaw/plugin-sdk/account-core";
|
|
5
|
+
import { createAttachedChannelResultAdapter } from "openclaw/plugin-sdk/channel-send-result";
|
|
6
|
+
import { resolveOutboundSendDep } from "openclaw/plugin-sdk/outbound-send-deps";
|
|
7
|
+
import { sendTextMediaPayload } from "openclaw/plugin-sdk/reply-payload";
|
|
8
|
+
//#region extensions/whatsapp/src/outbound-send-deps.ts
|
|
9
|
+
const WHATSAPP_LEGACY_OUTBOUND_SEND_DEP_KEYS = ["sendWhatsApp"];
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region extensions/whatsapp/src/outbound-base.ts
|
|
12
|
+
function resolveQuoteLookupAccountId(cfg, accountId) {
|
|
13
|
+
const explicitAccountId = normalizeOptionalAccountId(accountId);
|
|
14
|
+
if (explicitAccountId) return explicitAccountId;
|
|
15
|
+
const channelCfg = cfg?.channels?.whatsapp;
|
|
16
|
+
return resolveListedDefaultAccountId({
|
|
17
|
+
accountIds: listCombinedAccountIds({
|
|
18
|
+
configuredAccountIds: channelCfg?.accounts && typeof channelCfg.accounts === "object" ? Object.keys(channelCfg.accounts).filter(Boolean) : [],
|
|
19
|
+
fallbackAccountIdWhenEmpty: DEFAULT_ACCOUNT_ID
|
|
20
|
+
}),
|
|
21
|
+
configuredDefaultAccountId: normalizeOptionalAccountId(channelCfg?.defaultAccount)
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function createWhatsAppOutboundBase({ chunker, sendMessageWhatsApp, sendPollWhatsApp, shouldLogVerbose, resolveTarget, normalizeText = normalizeWhatsAppPayloadText, skipEmptyText = true }) {
|
|
25
|
+
const resolveQuotedMessageKey = (params) => {
|
|
26
|
+
const replyToId = params.replyToId?.trim();
|
|
27
|
+
if (!replyToId) return;
|
|
28
|
+
const targetJid = toWhatsappJid(params.to);
|
|
29
|
+
const cachedMeta = lookupInboundMessageMetaForTarget(params.accountId, targetJid, replyToId);
|
|
30
|
+
return {
|
|
31
|
+
id: replyToId,
|
|
32
|
+
remoteJid: cachedMeta?.remoteJid ?? targetJid,
|
|
33
|
+
fromMe: cachedMeta?.fromMe ?? false,
|
|
34
|
+
participant: cachedMeta?.participant,
|
|
35
|
+
messageText: cachedMeta?.body
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
const outbound = {
|
|
39
|
+
deliveryMode: "gateway",
|
|
40
|
+
chunker,
|
|
41
|
+
chunkerMode: "text",
|
|
42
|
+
textChunkLimit: 4e3,
|
|
43
|
+
sanitizeText: ({ text }) => normalizeText(text),
|
|
44
|
+
pollMaxOptions: 12,
|
|
45
|
+
resolveTarget,
|
|
46
|
+
...createAttachedChannelResultAdapter({
|
|
47
|
+
channel: "whatsapp",
|
|
48
|
+
sendText: async ({ cfg, to, text, accountId, deps, gifPlayback, replyToId }) => {
|
|
49
|
+
const normalizedText = normalizeText(text);
|
|
50
|
+
if (skipEmptyText && !normalizedText) return { messageId: "" };
|
|
51
|
+
const send = resolveOutboundSendDep(deps, "whatsapp", { legacyKeys: WHATSAPP_LEGACY_OUTBOUND_SEND_DEP_KEYS }) ?? sendMessageWhatsApp;
|
|
52
|
+
const quotedMessageKey = resolveQuotedMessageKey({
|
|
53
|
+
accountId: resolveQuoteLookupAccountId(cfg, accountId),
|
|
54
|
+
to,
|
|
55
|
+
replyToId
|
|
56
|
+
});
|
|
57
|
+
return await send(to, normalizedText, {
|
|
58
|
+
verbose: false,
|
|
59
|
+
cfg,
|
|
60
|
+
accountId: accountId ?? void 0,
|
|
61
|
+
gifPlayback,
|
|
62
|
+
quotedMessageKey
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
sendMedia: async ({ cfg, to, text, mediaUrl, mediaAccess, mediaLocalRoots, mediaReadFile, audioAsVoice, accountId, deps, gifPlayback, replyToId }) => {
|
|
66
|
+
const send = resolveOutboundSendDep(deps, "whatsapp", { legacyKeys: WHATSAPP_LEGACY_OUTBOUND_SEND_DEP_KEYS }) ?? sendMessageWhatsApp;
|
|
67
|
+
const quotedMessageKey = resolveQuotedMessageKey({
|
|
68
|
+
accountId: resolveQuoteLookupAccountId(cfg, accountId),
|
|
69
|
+
to,
|
|
70
|
+
replyToId
|
|
71
|
+
});
|
|
72
|
+
return await send(to, normalizeText(text), {
|
|
73
|
+
verbose: false,
|
|
74
|
+
cfg,
|
|
75
|
+
mediaUrl,
|
|
76
|
+
mediaAccess,
|
|
77
|
+
mediaLocalRoots,
|
|
78
|
+
mediaReadFile,
|
|
79
|
+
...audioAsVoice === void 0 ? {} : { audioAsVoice },
|
|
80
|
+
accountId: accountId ?? void 0,
|
|
81
|
+
gifPlayback,
|
|
82
|
+
quotedMessageKey
|
|
83
|
+
});
|
|
84
|
+
},
|
|
85
|
+
sendPoll: async ({ cfg, to, poll, accountId }) => await sendPollWhatsApp(to, poll, {
|
|
86
|
+
verbose: shouldLogVerbose(),
|
|
87
|
+
accountId: accountId ?? void 0,
|
|
88
|
+
cfg
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
};
|
|
92
|
+
return {
|
|
93
|
+
...outbound,
|
|
94
|
+
sendPayload: async (ctx) => {
|
|
95
|
+
if (ctx.payload.isError === true) return {
|
|
96
|
+
channel: "whatsapp",
|
|
97
|
+
messageId: ""
|
|
98
|
+
};
|
|
99
|
+
const payload = normalizeWhatsAppOutboundPayload(ctx.payload, { normalizeText });
|
|
100
|
+
if (!payload.text && !(payload.mediaUrl || payload.mediaUrls?.length)) {
|
|
101
|
+
if (ctx.payload.interactive || ctx.payload.presentation || ctx.payload.channelData) throw new Error("WhatsApp sendPayload does not support structured-only payloads without text or media.");
|
|
102
|
+
return {
|
|
103
|
+
channel: "whatsapp",
|
|
104
|
+
messageId: ""
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return await sendTextMediaPayload({
|
|
108
|
+
channel: "whatsapp",
|
|
109
|
+
ctx: {
|
|
110
|
+
...ctx,
|
|
111
|
+
payload
|
|
112
|
+
},
|
|
113
|
+
adapter: outbound
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
//#endregion
|
|
119
|
+
export { WHATSAPP_LEGACY_OUTBOUND_SEND_DEP_KEYS as n, createWhatsAppOutboundBase as t };
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { t as formatError } from "./session-errors-CSuKZPub.js";
|
|
2
|
+
import { t as text_runtime_exports } from "./text-runtime-C1zNiZeO.js";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import fs from "node:fs/promises";
|
|
5
|
+
import { MEDIA_FFMPEG_MAX_AUDIO_DURATION_SECS, runFfmpeg } from "openclaw/plugin-sdk/media-runtime";
|
|
6
|
+
import { sanitizeForPlainText } from "openclaw/plugin-sdk/outbound-runtime";
|
|
7
|
+
import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path";
|
|
8
|
+
//#region extensions/whatsapp/src/outbound-media-contract.ts
|
|
9
|
+
const WHATSAPP_VOICE_FILE_NAME = "voice.ogg";
|
|
10
|
+
const WHATSAPP_VOICE_SAMPLE_RATE_HZ = 48e3;
|
|
11
|
+
const WHATSAPP_VOICE_BITRATE = "64k";
|
|
12
|
+
const WHATSAPP_VOICE_MIMETYPE = "audio/ogg; codecs=opus";
|
|
13
|
+
function stripWhatsAppPluralToolXml(text) {
|
|
14
|
+
return (0, text_runtime_exports.stripToolCallXmlTags)(text, { stripFunctionCallsXmlPayloads: true });
|
|
15
|
+
}
|
|
16
|
+
function finalizeWhatsAppVisibleText(text) {
|
|
17
|
+
return sanitizeForPlainText(stripWhatsAppPluralToolXml(text));
|
|
18
|
+
}
|
|
19
|
+
function normalizeWhatsAppPayloadText(text) {
|
|
20
|
+
return finalizeWhatsAppVisibleText((0, text_runtime_exports.sanitizeAssistantVisibleText)(text ?? "")).trimStart();
|
|
21
|
+
}
|
|
22
|
+
function stripLeadingBlankLines(text) {
|
|
23
|
+
return text.replace(/^(?:[ \t]*\r?\n)+/, "");
|
|
24
|
+
}
|
|
25
|
+
function normalizeWhatsAppPayloadTextPreservingIndentation(text) {
|
|
26
|
+
const normalized = stripLeadingBlankLines(finalizeWhatsAppVisibleText((0, text_runtime_exports.sanitizeAssistantVisibleTextWithProfile)(stripLeadingBlankLines(text ?? ""), "history")));
|
|
27
|
+
return normalized.trim() ? normalized : "";
|
|
28
|
+
}
|
|
29
|
+
function resolveWhatsAppOutboundMediaUrls(payload) {
|
|
30
|
+
const orderedMediaUrls = [payload.mediaUrl?.trim(), ...(payload.mediaUrls ? [...payload.mediaUrls] : []).map((entry) => entry.trim()).filter((entry) => Boolean(entry))].filter((entry) => Boolean(entry));
|
|
31
|
+
return Array.from(new Set(orderedMediaUrls));
|
|
32
|
+
}
|
|
33
|
+
function normalizeWhatsAppOutboundPayload(payload, options) {
|
|
34
|
+
const mediaUrls = resolveWhatsAppOutboundMediaUrls(payload);
|
|
35
|
+
const normalizeText = options?.normalizeText ?? normalizeWhatsAppPayloadText;
|
|
36
|
+
return {
|
|
37
|
+
...payload,
|
|
38
|
+
text: normalizeText(payload.text),
|
|
39
|
+
mediaUrl: mediaUrls[0],
|
|
40
|
+
mediaUrls: mediaUrls.length > 0 ? mediaUrls : void 0
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function normalizeWhatsAppLoadedMedia(media, mediaUrl) {
|
|
44
|
+
const kind = media.kind === "image" || media.kind === "audio" || media.kind === "video" ? media.kind : "document";
|
|
45
|
+
const mimetype = kind === "audio" && isWhatsAppNativeVoiceAudio({
|
|
46
|
+
contentType: media.contentType,
|
|
47
|
+
mediaUrl
|
|
48
|
+
}) ? WHATSAPP_VOICE_MIMETYPE : media.contentType ?? "application/octet-stream";
|
|
49
|
+
const fileName = kind === "document" ? media.fileName ?? deriveWhatsAppDocumentFileName(mediaUrl) ?? "file" : void 0;
|
|
50
|
+
return {
|
|
51
|
+
buffer: media.buffer,
|
|
52
|
+
kind,
|
|
53
|
+
mimetype,
|
|
54
|
+
...fileName ? { fileName } : {}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
async function prepareWhatsAppOutboundMedia(media, mediaUrl) {
|
|
58
|
+
const normalized = normalizeWhatsAppLoadedMedia(media, mediaUrl);
|
|
59
|
+
if (normalized.kind !== "audio") return normalized;
|
|
60
|
+
if (isWhatsAppNativeVoiceAudio({
|
|
61
|
+
contentType: media.contentType,
|
|
62
|
+
fileName: media.fileName,
|
|
63
|
+
mediaUrl
|
|
64
|
+
})) return normalized;
|
|
65
|
+
return {
|
|
66
|
+
buffer: await transcodeToWhatsAppVoiceOpus({
|
|
67
|
+
buffer: media.buffer,
|
|
68
|
+
fileName: media.fileName ?? deriveWhatsAppDocumentFileName(mediaUrl) ?? "audio"
|
|
69
|
+
}),
|
|
70
|
+
kind: "audio",
|
|
71
|
+
mimetype: WHATSAPP_VOICE_MIMETYPE
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function normalizeContentType(value) {
|
|
75
|
+
return value?.split(";", 1)[0]?.trim().toLowerCase() ?? "";
|
|
76
|
+
}
|
|
77
|
+
function isWhatsAppNativeVoiceAudio(params) {
|
|
78
|
+
const contentType = normalizeContentType(params.contentType);
|
|
79
|
+
if (contentType === "audio/ogg" || contentType === "audio/opus") return true;
|
|
80
|
+
const fileName = params.fileName ?? deriveWhatsAppDocumentFileName(params.mediaUrl) ?? "";
|
|
81
|
+
const ext = path.extname(fileName).toLowerCase();
|
|
82
|
+
return ext === ".ogg" || ext === ".opus";
|
|
83
|
+
}
|
|
84
|
+
async function transcodeToWhatsAppVoiceOpus(params) {
|
|
85
|
+
const tempRoot = resolvePreferredOpenClawTmpDir();
|
|
86
|
+
await fs.mkdir(tempRoot, {
|
|
87
|
+
recursive: true,
|
|
88
|
+
mode: 448
|
|
89
|
+
});
|
|
90
|
+
const tempDir = await fs.mkdtemp(path.join(tempRoot, "whatsapp-voice-"));
|
|
91
|
+
try {
|
|
92
|
+
const ext = path.extname(params.fileName).toLowerCase();
|
|
93
|
+
const inputExt = ext && ext.length <= 12 ? ext : ".audio";
|
|
94
|
+
const inputPath = path.join(tempDir, `input${inputExt}`);
|
|
95
|
+
const outputPath = path.join(tempDir, WHATSAPP_VOICE_FILE_NAME);
|
|
96
|
+
await fs.writeFile(inputPath, params.buffer, { mode: 384 });
|
|
97
|
+
await runFfmpeg([
|
|
98
|
+
"-hide_banner",
|
|
99
|
+
"-loglevel",
|
|
100
|
+
"error",
|
|
101
|
+
"-y",
|
|
102
|
+
"-i",
|
|
103
|
+
inputPath,
|
|
104
|
+
"-vn",
|
|
105
|
+
"-sn",
|
|
106
|
+
"-dn",
|
|
107
|
+
"-t",
|
|
108
|
+
String(MEDIA_FFMPEG_MAX_AUDIO_DURATION_SECS),
|
|
109
|
+
"-ar",
|
|
110
|
+
String(WHATSAPP_VOICE_SAMPLE_RATE_HZ),
|
|
111
|
+
"-ac",
|
|
112
|
+
"1",
|
|
113
|
+
"-c:a",
|
|
114
|
+
"libopus",
|
|
115
|
+
"-b:a",
|
|
116
|
+
WHATSAPP_VOICE_BITRATE,
|
|
117
|
+
outputPath
|
|
118
|
+
]);
|
|
119
|
+
return await fs.readFile(outputPath);
|
|
120
|
+
} finally {
|
|
121
|
+
await fs.rm(tempDir, {
|
|
122
|
+
recursive: true,
|
|
123
|
+
force: true
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function deriveWhatsAppDocumentFileName(mediaUrl) {
|
|
128
|
+
if (!mediaUrl) return;
|
|
129
|
+
try {
|
|
130
|
+
const parsed = new URL(mediaUrl);
|
|
131
|
+
const fileName = path.posix.basename(parsed.pathname);
|
|
132
|
+
return fileName ? decodeURIComponent(fileName) : void 0;
|
|
133
|
+
} catch {
|
|
134
|
+
return (mediaUrl.split(/[?#]/, 1)[0] ?? "").split(/[\\/]/).pop() || void 0;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function isRetryableWhatsAppOutboundError(error) {
|
|
138
|
+
return /closed|reset|timed\s*out|disconnect/i.test(formatError(error));
|
|
139
|
+
}
|
|
140
|
+
async function sendWhatsAppOutboundWithRetry(params) {
|
|
141
|
+
const maxAttempts = params.maxAttempts ?? 3;
|
|
142
|
+
let lastError;
|
|
143
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) try {
|
|
144
|
+
return await params.send();
|
|
145
|
+
} catch (error) {
|
|
146
|
+
lastError = error;
|
|
147
|
+
const errorText = formatError(error);
|
|
148
|
+
const isLastAttempt = attempt === maxAttempts;
|
|
149
|
+
if (!isRetryableWhatsAppOutboundError(error) || isLastAttempt) throw error;
|
|
150
|
+
const backoffMs = 500 * attempt;
|
|
151
|
+
await params.onRetry?.({
|
|
152
|
+
attempt,
|
|
153
|
+
maxAttempts,
|
|
154
|
+
backoffMs,
|
|
155
|
+
error,
|
|
156
|
+
errorText
|
|
157
|
+
});
|
|
158
|
+
await (0, text_runtime_exports.sleep)(backoffMs);
|
|
159
|
+
}
|
|
160
|
+
throw lastError;
|
|
161
|
+
}
|
|
162
|
+
//#endregion
|
|
163
|
+
export { resolveWhatsAppOutboundMediaUrls as a, prepareWhatsAppOutboundMedia as i, normalizeWhatsAppPayloadText as n, sendWhatsAppOutboundWithRetry as o, normalizeWhatsAppPayloadTextPreservingIndentation as r, normalizeWhatsAppOutboundPayload as t };
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { i as jidToE164 } from "./text-runtime-C1zNiZeO.js";
|
|
2
|
+
//#region extensions/whatsapp/src/quoted-message.ts
|
|
3
|
+
const CACHE_TTL_MS = 600 * 1e3;
|
|
4
|
+
const MAX_ENTRIES = 500;
|
|
5
|
+
const cache = /* @__PURE__ */ new Map();
|
|
6
|
+
function makeCacheKey(accountId, remoteJid, messageId) {
|
|
7
|
+
return `${accountId}:${remoteJid}:${messageId}`;
|
|
8
|
+
}
|
|
9
|
+
function cacheInboundMessageMeta(accountId, remoteJid, messageId, meta) {
|
|
10
|
+
if (!accountId || !messageId || !remoteJid) return;
|
|
11
|
+
if (cache.size >= MAX_ENTRIES) {
|
|
12
|
+
const oldest = cache.keys().next().value;
|
|
13
|
+
if (oldest) cache.delete(oldest);
|
|
14
|
+
}
|
|
15
|
+
cache.set(makeCacheKey(accountId, remoteJid, messageId), {
|
|
16
|
+
...meta,
|
|
17
|
+
ts: Date.now()
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
function lookupInboundMessageMeta(accountId, remoteJid, messageId) {
|
|
21
|
+
const cacheKey = makeCacheKey(accountId, remoteJid, messageId);
|
|
22
|
+
const entry = cache.get(cacheKey);
|
|
23
|
+
if (!entry) return;
|
|
24
|
+
if (Date.now() - entry.ts > CACHE_TTL_MS) {
|
|
25
|
+
cache.delete(cacheKey);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
participant: entry.participant,
|
|
30
|
+
participantE164: entry.participantE164,
|
|
31
|
+
body: entry.body,
|
|
32
|
+
fromMe: entry.fromMe
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function normalizeComparableJid(jid) {
|
|
36
|
+
return jid?.trim().replace(/:\d+/, "").toLowerCase() || void 0;
|
|
37
|
+
}
|
|
38
|
+
function isGroupJid(jid) {
|
|
39
|
+
return Boolean(jid && jid.endsWith("@g.us"));
|
|
40
|
+
}
|
|
41
|
+
function areComparableE164sEqual(left, right) {
|
|
42
|
+
const normalizedLeft = left?.trim();
|
|
43
|
+
const normalizedRight = right?.trim();
|
|
44
|
+
if (!normalizedLeft || !normalizedRight) return false;
|
|
45
|
+
return normalizedLeft === normalizedRight;
|
|
46
|
+
}
|
|
47
|
+
function areComparableJidsEqual(left, right) {
|
|
48
|
+
const normalizedLeft = normalizeComparableJid(left);
|
|
49
|
+
const normalizedRight = normalizeComparableJid(right);
|
|
50
|
+
if (!normalizedLeft || !normalizedRight) return false;
|
|
51
|
+
if (normalizedLeft === normalizedRight) return true;
|
|
52
|
+
const leftE164 = jidToE164(normalizedLeft);
|
|
53
|
+
const rightE164 = jidToE164(normalizedRight);
|
|
54
|
+
return Boolean(leftE164 && rightE164 && leftE164 === rightE164);
|
|
55
|
+
}
|
|
56
|
+
function matchesQuotedConversationTarget(targetJid, candidate) {
|
|
57
|
+
if (areComparableJidsEqual(targetJid, candidate.remoteJid)) return true;
|
|
58
|
+
if (isGroupJid(targetJid) || isGroupJid(candidate.remoteJid)) return false;
|
|
59
|
+
return areComparableJidsEqual(targetJid, candidate.participant) || areComparableE164sEqual(jidToE164(targetJid) ?? void 0, candidate.participantE164);
|
|
60
|
+
}
|
|
61
|
+
function lookupInboundMessageMetaForTarget(accountId, targetJid, messageId) {
|
|
62
|
+
if (!accountId || !messageId || !targetJid) return;
|
|
63
|
+
const exact = lookupInboundMessageMeta(accountId, targetJid, messageId);
|
|
64
|
+
if (exact) return {
|
|
65
|
+
remoteJid: targetJid,
|
|
66
|
+
participant: exact.participant,
|
|
67
|
+
participantE164: exact.participantE164,
|
|
68
|
+
body: exact.body,
|
|
69
|
+
fromMe: exact.fromMe
|
|
70
|
+
};
|
|
71
|
+
const prefix = `${accountId}:`;
|
|
72
|
+
const suffix = `:${messageId}`;
|
|
73
|
+
let matched;
|
|
74
|
+
for (const [cacheKey, entry] of cache.entries()) {
|
|
75
|
+
if (!cacheKey.startsWith(prefix) || !cacheKey.endsWith(suffix)) continue;
|
|
76
|
+
if (Date.now() - entry.ts > CACHE_TTL_MS) {
|
|
77
|
+
cache.delete(cacheKey);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const candidate = {
|
|
81
|
+
remoteJid: cacheKey.slice(prefix.length, cacheKey.length - suffix.length),
|
|
82
|
+
participant: entry.participant,
|
|
83
|
+
participantE164: entry.participantE164,
|
|
84
|
+
body: entry.body,
|
|
85
|
+
fromMe: entry.fromMe
|
|
86
|
+
};
|
|
87
|
+
if (!matchesQuotedConversationTarget(targetJid, candidate)) continue;
|
|
88
|
+
if (matched) return;
|
|
89
|
+
matched = candidate;
|
|
90
|
+
}
|
|
91
|
+
return matched;
|
|
92
|
+
}
|
|
93
|
+
function buildQuotedMessageOptions(params) {
|
|
94
|
+
const id = params.messageId?.trim();
|
|
95
|
+
const remoteJid = params.remoteJid?.trim();
|
|
96
|
+
if (!id || !remoteJid) return;
|
|
97
|
+
return { quoted: {
|
|
98
|
+
key: {
|
|
99
|
+
remoteJid,
|
|
100
|
+
id,
|
|
101
|
+
fromMe: params.fromMe ?? false,
|
|
102
|
+
participant: params.participant
|
|
103
|
+
},
|
|
104
|
+
message: { conversation: params.messageText ?? "" }
|
|
105
|
+
} };
|
|
106
|
+
}
|
|
107
|
+
//#endregion
|
|
108
|
+
export { lookupInboundMessageMetaForTarget as i, cacheInboundMessageMeta as n, lookupInboundMessageMeta as r, buildQuotedMessageOptions as t };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { t as resolveMergedWhatsAppAccountConfig } from "./account-config-CNQ33oav.js";
|
|
2
|
+
import { resolveReactionLevel } from "openclaw/plugin-sdk/text-runtime";
|
|
3
|
+
//#region extensions/whatsapp/src/reaction-level.ts
|
|
4
|
+
/** Resolve the effective reaction level and its implications for WhatsApp. */
|
|
5
|
+
function resolveWhatsAppReactionLevel(params) {
|
|
6
|
+
return resolveReactionLevel({
|
|
7
|
+
value: resolveMergedWhatsAppAccountConfig({
|
|
8
|
+
cfg: params.cfg,
|
|
9
|
+
accountId: params.accountId
|
|
10
|
+
}).reactionLevel,
|
|
11
|
+
defaultLevel: "minimal",
|
|
12
|
+
invalidFallback: "minimal"
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { resolveWhatsAppReactionLevel as t };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { n as isWhatsAppNewsletterJid, s as normalizeWhatsAppTarget, t as isWhatsAppGroupJid } from "./normalize-target-BPVHNsM5.js";
|
|
2
|
+
import { missingTargetError } from "openclaw/plugin-sdk/channel-feedback";
|
|
3
|
+
//#region extensions/whatsapp/src/resolve-outbound-target.ts
|
|
4
|
+
function whatsappAllowFromPolicyError(target) {
|
|
5
|
+
return /* @__PURE__ */ new Error(`Target "${target}" is not listed in the configured WhatsApp allowFrom policy.`);
|
|
6
|
+
}
|
|
7
|
+
function resolveWhatsAppOutboundTarget(params) {
|
|
8
|
+
const trimmed = params.to?.trim() ?? "";
|
|
9
|
+
if (!trimmed) return {
|
|
10
|
+
ok: false,
|
|
11
|
+
error: missingTargetError("WhatsApp", "<E.164|group JID|newsletter JID>")
|
|
12
|
+
};
|
|
13
|
+
const normalizedTo = normalizeWhatsAppTarget(trimmed);
|
|
14
|
+
if (!normalizedTo) return {
|
|
15
|
+
ok: false,
|
|
16
|
+
error: missingTargetError("WhatsApp", "<E.164|group JID|newsletter JID>")
|
|
17
|
+
};
|
|
18
|
+
if (isWhatsAppGroupJid(normalizedTo) || isWhatsAppNewsletterJid(normalizedTo)) return {
|
|
19
|
+
ok: true,
|
|
20
|
+
to: normalizedTo
|
|
21
|
+
};
|
|
22
|
+
const allowListRaw = (params.allowFrom ?? []).map((entry) => String(entry).trim()).filter(Boolean);
|
|
23
|
+
const hasWildcard = allowListRaw.includes("*");
|
|
24
|
+
const allowList = allowListRaw.filter((entry) => entry !== "*").map((entry) => normalizeWhatsAppTarget(entry)).filter((entry) => Boolean(entry));
|
|
25
|
+
if (hasWildcard || allowList.length === 0) return {
|
|
26
|
+
ok: true,
|
|
27
|
+
to: normalizedTo
|
|
28
|
+
};
|
|
29
|
+
if (allowList.includes(normalizedTo)) return {
|
|
30
|
+
ok: true,
|
|
31
|
+
to: normalizedTo
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
ok: false,
|
|
35
|
+
error: whatsappAllowFromPolicyError(normalizedTo)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
export { resolveWhatsAppOutboundTarget as t };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __exportAll = (all, no_symbols) => {
|
|
7
|
+
let target = {};
|
|
8
|
+
for (var name in all) __defProp(target, name, {
|
|
9
|
+
get: all[name],
|
|
10
|
+
enumerable: true
|
|
11
|
+
});
|
|
12
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
13
|
+
return target;
|
|
14
|
+
};
|
|
15
|
+
var __copyProps = (to, from, except, desc) => {
|
|
16
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
17
|
+
key = keys[i];
|
|
18
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
19
|
+
get: ((k) => from[k]).bind(null, key),
|
|
20
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return to;
|
|
24
|
+
};
|
|
25
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
26
|
+
//#endregion
|
|
27
|
+
export { __reExport as n, __exportAll as t };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
|
2
|
+
//#region extensions/whatsapp/src/runtime.ts
|
|
3
|
+
const { setRuntime: setWhatsAppRuntime, getRuntime: getWhatsAppRuntime } = createPluginRuntimeStore({
|
|
4
|
+
pluginId: "whatsapp",
|
|
5
|
+
errorMessage: "WhatsApp runtime not initialized"
|
|
6
|
+
});
|
|
7
|
+
//#endregion
|
|
8
|
+
export { setWhatsAppRuntime as n, getWhatsAppRuntime as t };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { n as resolveWebCredsBackupPath, r as resolveWebCredsPath, t as hasWebCredsSync } from "./creds-files-_2V8jzQa.js";
|
|
2
|
+
import { n as whatsAppActionRuntime, t as handleWhatsAppAction } from "./action-runtime-DTGNgG-i.js";
|
|
3
|
+
import { n as getStatusCode, t as formatError } from "./session-errors-CSuKZPub.js";
|
|
4
|
+
import { i as sendTypingWhatsApp, n as sendPollWhatsApp, r as sendReactionWhatsApp, t as sendMessageWhatsApp } from "./send-CIyLFxdZ.js";
|
|
5
|
+
import { startWebLoginWithQr, waitForWebLogin } from "./login-qr-runtime.js";
|
|
6
|
+
import { t as createWhatsAppLoginTool } from "./agent-tools-login-DpRxLNRB.js";
|
|
7
|
+
import { n as setWhatsAppRuntime } from "./runtime-6fZ67abR.js";
|
|
8
|
+
import { C as waitForCredsSaveQueueWithTimeout, S as waitForCredsSaveQueue, _ as readWebSelfIdentityForDecision, a as getWebAuthAgeMs, b as webAuthExists, c as pickWebChannel, d as readWebAuthExistsForDecision, f as readWebAuthSnapshot, g as readWebSelfIdentity, h as readWebSelfId, i as formatWhatsAppWebAuthStatusState, l as readCredsJsonRaw, m as readWebAuthState, n as WHATSAPP_AUTH_UNSTABLE_CODE, o as logWebSelfId, p as readWebAuthSnapshotBestEffort, r as WhatsAppAuthUnstableError, s as logoutWeb, t as WA_WEB_AUTH_DIR, u as readWebAuthExistsBestEffort, v as resolveDefaultWebAuthDir, w as writeCredsJsonAtomically, y as restoreCredsFromBackupIfNeeded } from "./auth-store-BjCb50Ry.js";
|
|
9
|
+
import { t as DEFAULT_WEB_MEDIA_BYTES } from "./constants-DLGCIbfl.js";
|
|
10
|
+
import { n as resolveWebAccountId, t as getActiveWebListener } from "./active-listener-N7GFKsuN.js";
|
|
11
|
+
import { c as waitForWaConnection, o as createWaSocket, s as newConnectionId } from "./connection-controller-BiHAsTM8.js";
|
|
12
|
+
import { a as loadWebMediaRaw, c as monitorWebInbox, d as extractMediaPlaceholder, f as extractText, i as loadWebMedia, l as extractContactContext, n as LocalMediaAccessError, o as optimizeImageToJpeg, p as resetWebInboundDedupe, r as getDefaultLocalRoots, s as optimizeImageToPng, t as monitorWebChannel, u as extractLocationData } from "./monitor-C4Fhg_lD.js";
|
|
13
|
+
import { t as loginWeb } from "./login-DymdrKca.js";
|
|
14
|
+
import { HEARTBEAT_PROMPT, HEARTBEAT_TOKEN, SILENT_REPLY_TOKEN, stripHeartbeatToken } from "openclaw/plugin-sdk/reply-runtime";
|
|
15
|
+
export { DEFAULT_WEB_MEDIA_BYTES, HEARTBEAT_PROMPT, HEARTBEAT_TOKEN, LocalMediaAccessError, SILENT_REPLY_TOKEN, WA_WEB_AUTH_DIR, WHATSAPP_AUTH_UNSTABLE_CODE, WhatsAppAuthUnstableError, createWaSocket, createWhatsAppLoginTool, extractContactContext, extractLocationData, extractMediaPlaceholder, extractText, formatError, formatWhatsAppWebAuthStatusState, getActiveWebListener, getDefaultLocalRoots, getStatusCode, getWebAuthAgeMs, handleWhatsAppAction, hasWebCredsSync, loadWebMedia, loadWebMediaRaw, logWebSelfId, loginWeb, logoutWeb, monitorWebChannel, monitorWebInbox, newConnectionId, optimizeImageToJpeg, optimizeImageToPng, pickWebChannel, readCredsJsonRaw, readWebAuthExistsBestEffort, readWebAuthExistsForDecision, readWebAuthSnapshot, readWebAuthSnapshotBestEffort, readWebAuthState, readWebSelfId, readWebSelfIdentity, readWebSelfIdentityForDecision, resetWebInboundDedupe, resolveDefaultWebAuthDir, resolveWebAccountId, resolveWebCredsBackupPath, resolveWebCredsPath, restoreCredsFromBackupIfNeeded, sendMessageWhatsApp, sendPollWhatsApp, sendReactionWhatsApp, sendTypingWhatsApp, setWhatsAppRuntime, startWebLoginWithQr, stripHeartbeatToken, waitForCredsSaveQueue, waitForCredsSaveQueueWithTimeout, waitForWaConnection, waitForWebLogin, webAuthExists, whatsAppActionRuntime, writeCredsJsonAtomically };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { resolveOpenProviderRuntimeGroupPolicy } from "openclaw/plugin-sdk/runtime-group-policy";
|
|
2
|
+
//#region extensions/whatsapp/src/runtime-group-policy.ts
|
|
3
|
+
function resolveWhatsAppRuntimeGroupPolicy(params) {
|
|
4
|
+
return resolveOpenProviderRuntimeGroupPolicy({
|
|
5
|
+
providerConfigPresent: params.providerConfigPresent,
|
|
6
|
+
groupPolicy: params.groupPolicy,
|
|
7
|
+
defaultGroupPolicy: params.defaultGroupPolicy
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { resolveWhatsAppRuntimeGroupPolicy as t };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { isRecord } from "openclaw/plugin-sdk/text-runtime";
|
|
2
|
+
//#region extensions/whatsapp/src/security-contract.ts
|
|
3
|
+
const unsupportedSecretRefSurfacePatterns = ["channels.whatsapp.creds.json", "channels.whatsapp.accounts.*.creds.json"];
|
|
4
|
+
function collectUnsupportedSecretRefConfigCandidates(raw) {
|
|
5
|
+
if (!isRecord(raw)) return [];
|
|
6
|
+
if (!isRecord(raw.channels) || !isRecord(raw.channels.whatsapp)) return [];
|
|
7
|
+
const candidates = [];
|
|
8
|
+
const whatsapp = raw.channels.whatsapp;
|
|
9
|
+
const creds = isRecord(whatsapp.creds) ? whatsapp.creds : null;
|
|
10
|
+
if (creds) candidates.push({
|
|
11
|
+
path: "channels.whatsapp.creds.json",
|
|
12
|
+
value: creds.json
|
|
13
|
+
});
|
|
14
|
+
const accounts = isRecord(whatsapp.accounts) ? whatsapp.accounts : null;
|
|
15
|
+
if (!accounts) return candidates;
|
|
16
|
+
for (const [accountId, account] of Object.entries(accounts)) {
|
|
17
|
+
if (!isRecord(account) || !isRecord(account.creds)) continue;
|
|
18
|
+
candidates.push({
|
|
19
|
+
path: `channels.whatsapp.accounts.${accountId}.creds.json`,
|
|
20
|
+
value: account.creds.json
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return candidates;
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { unsupportedSecretRefSurfacePatterns as n, collectUnsupportedSecretRefConfigCandidates as t };
|