@openclaw/whatsapp 2026.7.1 → 2026.7.2-beta.2

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.
Files changed (62) hide show
  1. package/dist/{access-control-DYE5dXna.js → access-control-DazDX3RB.js} +4 -4
  2. package/dist/{account-config-6PTOSfaI.js → account-config-LiT9wWH9.js} +4 -8
  3. package/dist/{accounts-4YgwroRU.js → accounts-CKOFMPf-.js} +2 -3
  4. package/dist/{action-runtime-DPahAqxV.js → action-runtime-Bf-12TIH.js} +3 -3
  5. package/dist/action-runtime-api.js +1 -1
  6. package/dist/action-runtime.runtime.js +1 -1
  7. package/dist/{active-listener-B4SDebQ6.js → active-listener-5kHap439.js} +2 -2
  8. package/dist/{agent-tools-login-BX7eHgDm.js → agent-tools-login-DfyToBpG.js} +1 -4
  9. package/dist/api.js +17 -18
  10. package/dist/{approval-handler.runtime-DNWS4aYQ.js → approval-handler.runtime-CBiGQuZ5.js} +19 -13
  11. package/dist/approval-reactions-BGQoz25s.js +373 -0
  12. package/dist/{approval-resolver-DF-lu8k5.js → approval-resolver-DoeBBt22.js} +2 -1
  13. package/dist/{auth-store-Db-wfApd.js → auth-store-BQi9pZqQ.js} +31 -19
  14. package/dist/call-tool-api.js +6 -14
  15. package/dist/{channel-BWp7h1uY.js → channel-DbadDUDD.js} +84 -52
  16. package/dist/channel-config-api.js +1 -1
  17. package/dist/channel-plugin-api.js +1 -1
  18. package/dist/{channel-react-action-CKJHL_Wf.js → channel-react-action-PoRWfP9x.js} +7 -7
  19. package/dist/{channel.runtime-CAssfx9p.js → channel.runtime-BDDy4Lhz.js} +5 -5
  20. package/dist/{channel.setup-CURc5rEt.js → channel.setup-BZ-po8fg.js} +4 -5
  21. package/dist/config-schema-BZ8h1hWA.js +40 -0
  22. package/dist/{connection-controller-DkbrFSIn.js → connection-controller-C1rwfWb4.js} +52 -12
  23. package/dist/connection-controller-runtime-context-CbTsqmPT.js +14 -0
  24. package/dist/contract-api.js +2 -2
  25. package/dist/{directory-config-Dijefxc3.js → directory-config-CLBQrjtC.js} +3 -3
  26. package/dist/directory-contract-api.js +1 -1
  27. package/dist/doctor-contract-api.js +89 -4
  28. package/dist/{group-session-key-BhC1RQOE.js → group-session-key-CLTZeH_F.js} +31 -3
  29. package/dist/{identity-Dqft3mFA.js → identity-D7L8LCuH.js} +2 -2
  30. package/dist/legacy-state-migrations-api.js +1 -1
  31. package/dist/light-runtime-api.js +4 -4
  32. package/dist/{login-C48y0jlx.js → login-DGIoToX8.js} +48 -8
  33. package/dist/{login-qr-BjId7dll.js → login-qr-X-CZHOk9.js} +6 -7
  34. package/dist/login-qr-runtime.js +1 -1
  35. package/dist/{monitor-DD8bXohk.js → monitor-BZ8QvCeV.js} +145 -188
  36. package/dist/normalize-C-Z16y7Q.js +2 -0
  37. package/dist/{normalize-target-bVWjgftN.js → normalize-target-DSZnHkKF.js} +14 -10
  38. package/dist/{resolve-outbound-target-CcdugbDf.js → resolve-outbound-target-BR97fAbB.js} +1 -1
  39. package/dist/runtime-api.js +10 -10
  40. package/dist/{send-C5CpFcBG.js → send-D9Ydnn4o.js} +25 -320
  41. package/dist/{send-api-DLlXl8CH.js → send-api-W33lI2nR.js} +28 -88
  42. package/dist/{session-errors-BAj9D2La.js → session-errors-JuazczrA.js} +2 -1
  43. package/dist/{session-DriaHt7V.js → session-mxWFn0eS.js} +181 -19
  44. package/dist/session.runtime-Nsqaehbd.js +16 -0
  45. package/dist/{setup-core-DH-DFPLY.js → setup-core-3aSOoK2T.js} +18 -33
  46. package/dist/{setup-finalize-c8dl34sO.js → setup-finalize-DBf1jjBj.js} +41 -11
  47. package/dist/setup-plugin-api.js +1 -1
  48. package/dist/{setup-surface-DlWb0Z09.js → setup-surface-CiKGdNJv.js} +3 -3
  49. package/dist/{state-migrations-D_BmQUR9.js → state-migrations-CAMTrs2U.js} +1 -8
  50. package/dist/{targets-runtime-C-GiVn6Y.js → targets-runtime-Bsh0HR9y.js} +13 -6
  51. package/dist/text-runtime-BTGkMN0o.js +4 -0
  52. package/npm-shrinkwrap.json +3 -3
  53. package/openclaw.plugin.json +72 -48
  54. package/package.json +4 -4
  55. package/dist/config-schema-mBX2nmn1.js +0 -47
  56. package/dist/connection-controller-registry-TSX_udJp.js +0 -22
  57. package/dist/constants.js +0 -2
  58. package/dist/normalize-Bxwqo-bW.js +0 -2
  59. package/dist/session.runtime-CyooSQvj.js +0 -12
  60. package/dist/socket-timing-DhbVFjah.js +0 -77
  61. package/dist/targets.js +0 -2
  62. package/dist/text-runtime-DdX6-mC_.js +0 -4
@@ -1,4 +1,4 @@
1
- import { c as normalizeWhatsAppTarget, n as isWhatsAppNewsletterJid, t as isWhatsAppGroupJid } from "./normalize-target-bVWjgftN.js";
1
+ import { c as normalizeWhatsAppTarget, n as isWhatsAppNewsletterJid, t as isWhatsAppGroupJid } from "./normalize-target-DSZnHkKF.js";
2
2
  import { normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
3
3
  import { missingTargetError } from "openclaw/plugin-sdk/channel-feedback";
4
4
  //#region extensions/whatsapp/src/resolve-outbound-target.ts
@@ -1,16 +1,16 @@
1
1
  import { o as resolveWebCredsBackupPath, r as hasWebCredsSync, s as resolveWebCredsPath } from "./creds-files-B1kSWtBg.js";
2
- import { n as whatsAppActionRuntime, t as handleWhatsAppAction } from "./action-runtime-DPahAqxV.js";
3
- import { i as sendTypingWhatsApp, n as sendPollWhatsApp, r as sendReactionWhatsApp, t as sendMessageWhatsApp } from "./send-C5CpFcBG.js";
2
+ import { n as whatsAppActionRuntime, t as handleWhatsAppAction } from "./action-runtime-Bf-12TIH.js";
3
+ import { i as sendTypingWhatsApp, n as sendPollWhatsApp, r as sendReactionWhatsApp, t as sendMessageWhatsApp } from "./send-D9Ydnn4o.js";
4
4
  import { r as setWhatsAppRuntime } from "./runtime-BfAdAEYT.js";
5
- import { n as getStatusCode, t as formatError } from "./session-errors-BAj9D2La.js";
6
5
  import { startWebLoginWithQr, waitForWebLogin } from "./login-qr-runtime.js";
7
- import { t as createWhatsAppLoginTool } from "./agent-tools-login-BX7eHgDm.js";
8
- import { C as waitForCredsSaveQueue, T as writeCredsJsonAtomically, _ as readWebSelfIdentity, a as formatWhatsAppWebAuthStatusState, b as restoreCredsFromBackupIfNeeded, c as logoutWeb, d as readWebAuthExistsBestEffort, f as readWebAuthExistsForDecision, g as readWebSelfId, h as readWebAuthState, l as pickWebChannel, m as readWebAuthSnapshotBestEffort, n as WHATSAPP_AUTH_UNSTABLE_CODE, o as getWebAuthAgeMs, p as readWebAuthSnapshot, r as WhatsAppAuthUnstableError, s as logWebSelfId, t as WA_WEB_AUTH_DIR, u as readCredsJsonRaw, v as readWebSelfIdentityForDecision, w as waitForCredsSaveQueueWithTimeout, x as webAuthExists, y as resolveDefaultWebAuthDir } from "./auth-store-Db-wfApd.js";
6
+ import { t as createWhatsAppLoginTool } from "./agent-tools-login-DfyToBpG.js";
7
+ import { C as waitForCredsSaveQueue, T as writeCredsJsonAtomically, _ as readWebSelfIdentity, a as formatWhatsAppWebAuthStatusState, b as restoreCredsFromBackupIfNeeded, c as logoutWeb, d as readWebAuthExistsBestEffort, f as readWebAuthExistsForDecision, g as readWebSelfId, h as readWebAuthState, l as pickWebChannel, m as readWebAuthSnapshotBestEffort, n as WHATSAPP_AUTH_UNSTABLE_CODE, o as getWebAuthAgeMs, p as readWebAuthSnapshot, r as WhatsAppAuthUnstableError, s as logWebSelfId, t as WA_WEB_AUTH_DIR, u as readCredsJsonRaw, v as readWebSelfIdentityForDecision, w as waitForCredsSaveQueueWithTimeout, x as webAuthExists, y as resolveDefaultWebAuthDir } from "./auth-store-BQi9pZqQ.js";
9
8
  import { t as DEFAULT_WEB_MEDIA_BYTES } from "./constants-HU41RHGI.js";
10
- import { _ as extractLocationData, b as extractText, m as extractContactContext, v as extractMediaPlaceholder } from "./send-api-DLlXl8CH.js";
11
- import { n as newConnectionId, r as waitForWaConnection, t as createWaSocket } from "./session-DriaHt7V.js";
12
- import { n as resolveWebAccountId, t as getActiveWebListener } from "./active-listener-B4SDebQ6.js";
13
- import { a as loadWebMediaRaw, c as monitorWebInbox, i as loadWebMedia, l as resetWebInboundDedupe, n as LocalMediaAccessError, o as optimizeImageToJpeg, r as getDefaultLocalRoots, s as optimizeImageToPng, t as monitorWebChannel } from "./monitor-DD8bXohk.js";
14
- import { t as loginWeb } from "./login-C48y0jlx.js";
9
+ import { _ as extractLocationData, b as extractText, m as extractContactContext, v as extractMediaPlaceholder } from "./send-api-W33lI2nR.js";
10
+ import { n as newConnectionId, r as waitForWaConnection, t as createWaSocket } from "./session-mxWFn0eS.js";
11
+ import { n as getStatusCode, t as formatError } from "./session-errors-JuazczrA.js";
12
+ import { n as resolveWebAccountId, t as getActiveWebListener } from "./active-listener-5kHap439.js";
13
+ import { a as loadWebMediaRaw, c as monitorWebInbox, i as loadWebMedia, l as resetWebInboundDedupe, n as LocalMediaAccessError, o as optimizeImageToJpeg, r as getDefaultLocalRoots, s as optimizeImageToPng, t as monitorWebChannel } from "./monitor-BZ8QvCeV.js";
14
+ import { t as loginWeb } from "./login-DGIoToX8.js";
15
15
  import { HEARTBEAT_PROMPT, HEARTBEAT_TOKEN, SILENT_REPLY_TOKEN, stripHeartbeatToken } from "openclaw/plugin-sdk/reply-runtime";
16
16
  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 };
@@ -1,31 +1,27 @@
1
- import { t as resolveMergedWhatsAppAccountConfig } from "./account-config-6PTOSfaI.js";
1
+ import { t as resolveMergedWhatsAppAccountConfig } from "./account-config-LiT9wWH9.js";
2
2
  import { r as resolveDefaultWhatsAppAccountId } from "./account-ids-CB5SOWjc.js";
3
- import { a as resolveWhatsAppAccount, s as resolveWhatsAppMediaMaxBytes } from "./accounts-4YgwroRU.js";
4
- import { c as normalizeWhatsAppTarget, n as isWhatsAppNewsletterJid } from "./normalize-target-bVWjgftN.js";
5
- import "./normalize-Bxwqo-bW.js";
6
- import { t as getOptionalWhatsAppRuntime } from "./runtime-BfAdAEYT.js";
7
- import { t as getRegisteredWhatsAppConnectionController } from "./connection-controller-registry-TSX_udJp.js";
8
- import { t as formatError } from "./session-errors-BAj9D2La.js";
9
- import { r as isWhatsAppSocketOperationTimeoutError } from "./socket-timing-DhbVFjah.js";
10
- import { i as markdownToWhatsApp, s as toWhatsappJid } from "./targets-runtime-C-GiVn6Y.js";
11
- import { a as sanitizeAssistantVisibleTextWithProfile, i as sanitizeAssistantVisibleText, o as sleep, s as stripToolCallXmlTags } from "./text-runtime-DdX6-mC_.js";
3
+ import { a as resolveWhatsAppAccount, s as resolveWhatsAppMediaMaxBytes } from "./accounts-CKOFMPf-.js";
4
+ import { n as isWhatsAppNewsletterJid } from "./normalize-target-DSZnHkKF.js";
5
+ import { n as getWhatsAppConnectionController } from "./connection-controller-runtime-context-CbTsqmPT.js";
6
+ import "./normalize-C-Z16y7Q.js";
7
+ import { i as markdownToWhatsApp, s as toWhatsappJid } from "./targets-runtime-Bsh0HR9y.js";
8
+ import { a as sanitizeAssistantVisibleTextWithProfile, i as sanitizeAssistantVisibleText, o as stripToolCallXmlTags } from "./text-runtime-BTGkMN0o.js";
12
9
  import path from "node:path";
13
- import { uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
14
- import { sanitizeForPlainText } from "openclaw/plugin-sdk/channel-outbound";
10
+ import { normalizeUniqueStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
15
11
  import { writeExternalFileWithinRoot } from "openclaw/plugin-sdk/security-runtime";
16
12
  import { resolveReactionLevel } from "openclaw/plugin-sdk/status-helpers";
17
13
  import { formatCliCommand } from "openclaw/plugin-sdk/cli-runtime";
18
14
  import { generateSecureUuid } from "openclaw/plugin-sdk/core";
15
+ import { PlatformMessageNotDispatchedError } from "openclaw/plugin-sdk/error-runtime";
19
16
  import { redactIdentifier } from "openclaw/plugin-sdk/logging-core";
20
17
  import { convertMarkdownTables, resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
21
18
  import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
22
19
  import { normalizePollInput } from "openclaw/plugin-sdk/poll-runtime";
23
20
  import { createSubsystemLogger, getChildLogger as getChildLogger$1 } from "openclaw/plugin-sdk/runtime-env";
24
- import { createApprovalReactionTargetStore, listApprovalReactionBindings, resolveApprovalReactionTarget } from "openclaw/plugin-sdk/approval-reaction-runtime";
25
- import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
26
- import { createResolvedApproverActionAuthAdapter, resolveApprovalApprovers } from "openclaw/plugin-sdk/approval-auth-runtime";
27
21
  import { extensionForMime } from "openclaw/plugin-sdk/media-mime";
22
+ import { sanitizeForPlainText } from "openclaw/plugin-sdk/channel-outbound";
28
23
  import { MEDIA_FFMPEG_MAX_AUDIO_DURATION_SECS, runFfmpeg } from "openclaw/plugin-sdk/media-runtime";
24
+ import { resolveOutboundMediaUrls } from "openclaw/plugin-sdk/reply-payload";
29
25
  import { resolvePreferredOpenClawTmpDir, withTempWorkspace } from "openclaw/plugin-sdk/temp-path";
30
26
  import { loadWebMedia } from "openclaw/plugin-sdk/web-media";
31
27
  //#region extensions/whatsapp/src/reaction-level.ts
@@ -41,272 +37,6 @@ function resolveWhatsAppReactionLevel(params) {
41
37
  });
42
38
  }
43
39
  //#endregion
44
- //#region extensions/whatsapp/src/approval-auth.ts
45
- function normalizeWhatsAppApproverId(value) {
46
- const normalized = normalizeWhatsAppTarget(String(value));
47
- if (!normalized || normalized.endsWith("@g.us")) return;
48
- return normalized;
49
- }
50
- function normalizeWhatsAppApproverEntry(value) {
51
- return String(value).trim() === "*" ? "*" : normalizeWhatsAppApproverId(value);
52
- }
53
- function getWhatsAppApprovalApprovers(params) {
54
- return resolveApprovalApprovers({
55
- allowFrom: resolveWhatsAppAccount({
56
- cfg: params.cfg,
57
- accountId: params.accountId
58
- }).allowFrom,
59
- normalizeApprover: normalizeWhatsAppApproverEntry
60
- });
61
- }
62
- const whatsappResolvedApproverAuth = createResolvedApproverActionAuthAdapter({
63
- channelLabel: "WhatsApp",
64
- resolveApprovers: ({ cfg, accountId }) => getWhatsAppApprovalApprovers({
65
- cfg,
66
- accountId
67
- }),
68
- normalizeSenderId: (value) => normalizeWhatsAppApproverId(value)
69
- });
70
- const whatsappApprovalAuth = { authorizeActorAction({ cfg, accountId, senderId, approvalKind }) {
71
- if (getWhatsAppApprovalApprovers({
72
- cfg,
73
- accountId
74
- }).includes("*")) return { authorized: true };
75
- return whatsappResolvedApproverAuth.authorizeActorAction({
76
- cfg,
77
- accountId,
78
- senderId,
79
- action: "approve",
80
- approvalKind
81
- });
82
- } };
83
- //#endregion
84
- //#region extensions/whatsapp/src/approval-reactions.ts
85
- const PERSISTENT_NAMESPACE = "whatsapp.approval-reactions";
86
- const PERSISTENT_MAX_ENTRIES = 1e3;
87
- const DEFAULT_REACTION_TARGET_TTL_MS = 1440 * 60 * 1e3;
88
- const resolverRuntimeLoader = createLazyRuntimeModule(() => import("./approval-resolver-DF-lu8k5.js"));
89
- const whatsappApprovalReactionTargets = createApprovalReactionTargetStore({
90
- namespace: PERSISTENT_NAMESPACE,
91
- maxEntries: PERSISTENT_MAX_ENTRIES,
92
- defaultTtlMs: DEFAULT_REACTION_TARGET_TTL_MS,
93
- openStore: (storeParams) => getOptionalWhatsAppRuntime()?.state.openKeyedStore(storeParams),
94
- logPersistentError: reportPersistentApprovalReactionError,
95
- readPersistedTarget
96
- });
97
- const loadApprovalResolver = resolverRuntimeLoader;
98
- function buildReactionTargetKey(params) {
99
- const accountId = params.accountId.trim();
100
- const remoteJid = params.remoteJid.trim();
101
- const messageId = params.messageId.trim();
102
- if (!accountId || !remoteJid || !messageId) return null;
103
- return `${accountId}:${remoteJid}:${messageId}`;
104
- }
105
- function addCandidateRemoteJid(target, value) {
106
- const remoteJid = value?.trim();
107
- if (remoteJid && !target.includes(remoteJid)) target.push(remoteJid);
108
- }
109
- function reportPersistentApprovalReactionError(error) {
110
- try {
111
- getOptionalWhatsAppRuntime()?.logging.getChildLogger({
112
- plugin: "whatsapp",
113
- feature: "approval-reaction-state"
114
- }).warn("WhatsApp persistent approval reaction state failed", { error: String(error) });
115
- } catch {}
116
- }
117
- function readPersistedTarget(target) {
118
- const value = target;
119
- if (!value || typeof value.approvalId !== "string" || !Array.isArray(value.allowedDecisions)) return null;
120
- return {
121
- approvalId: value.approvalId,
122
- ...value.approvalKind === "exec" || value.approvalKind === "plugin" ? { approvalKind: value.approvalKind } : {},
123
- allowedDecisions: value.allowedDecisions
124
- };
125
- }
126
- function listWhatsAppApprovalReactionBindings(allowedDecisions) {
127
- return listApprovalReactionBindings({ allowedDecisions });
128
- }
129
- function normalizeApprovalDecision(value) {
130
- const normalized = value.trim().toLowerCase();
131
- if (normalized === "always") return "allow-always";
132
- if (normalized === "allow-once" || normalized === "allow-always" || normalized === "deny") return normalized;
133
- return null;
134
- }
135
- const APPROVAL_ID_LINE_RE = /^\s*ID:\s*([A-Za-z0-9][A-Za-z0-9._:-]*)\s*$/i;
136
- const APPROVE_COMMAND_LINE_RE = /\/approve(?:@[^\s]+)?\s+([A-Za-z0-9][A-Za-z0-9._:-]*)\s+(.+)$/i;
137
- function extractWhatsAppApprovalPromptBinding(text) {
138
- const lines = text.split(/\r?\n/);
139
- const idHeaderMatch = lines.map((line) => line.match(APPROVAL_ID_LINE_RE)).find((match) => Boolean(match));
140
- if (!idHeaderMatch) return null;
141
- const approvalId = idHeaderMatch[1];
142
- const allowedDecisions = [];
143
- for (const line of lines) {
144
- const match = line.match(APPROVE_COMMAND_LINE_RE);
145
- if (!match || match[1] !== approvalId) continue;
146
- for (const decisionText of match[2].split(/[\s|,]+/)) {
147
- const decision = normalizeApprovalDecision(decisionText);
148
- if (decision && !allowedDecisions.includes(decision)) allowedDecisions.push(decision);
149
- }
150
- }
151
- return allowedDecisions.length > 0 ? {
152
- approvalId,
153
- allowedDecisions
154
- } : null;
155
- }
156
- function registerWhatsAppApprovalReactionTarget(params) {
157
- const key = buildReactionTargetKey(params);
158
- const approvalId = params.approvalId.trim();
159
- const allowedDecisions = listWhatsAppApprovalReactionBindings(params.allowedDecisions).map((binding) => binding.decision);
160
- if (!key || !approvalId || allowedDecisions.length === 0) return null;
161
- const target = {
162
- approvalId,
163
- approvalKind: approvalId.startsWith("plugin:") ? "plugin" : "exec",
164
- allowedDecisions
165
- };
166
- whatsappApprovalReactionTargets.register(key, target, { ttlMs: params.ttlMs });
167
- return target;
168
- }
169
- function registerWhatsAppApprovalReactionTargetForOutboundMessage(params) {
170
- const binding = extractWhatsAppApprovalPromptBinding(params.text);
171
- if (!binding) return false;
172
- return Boolean(registerWhatsAppApprovalReactionTarget({
173
- accountId: params.accountId,
174
- remoteJid: params.remoteJid,
175
- messageId: params.messageId,
176
- approvalId: binding.approvalId,
177
- allowedDecisions: binding.allowedDecisions,
178
- ttlMs: params.ttlMs
179
- }));
180
- }
181
- function unregisterWhatsAppApprovalReactionTarget(params) {
182
- const key = buildReactionTargetKey(params);
183
- if (!key) return;
184
- whatsappApprovalReactionTargets.delete(key);
185
- }
186
- function resolveTarget(params) {
187
- const resolved = resolveApprovalReactionTarget({
188
- target: params.target,
189
- reactionKey: params.reactionKey
190
- });
191
- return resolved ? {
192
- approvalId: resolved.approvalId,
193
- decision: resolved.decision
194
- } : null;
195
- }
196
- async function resolveWhatsAppApprovalReactionTargetWithPersistence(params) {
197
- const key = buildReactionTargetKey(params);
198
- if (!key) return null;
199
- return resolveTarget({
200
- target: await whatsappApprovalReactionTargets.lookup(key),
201
- reactionKey: params.reactionKey
202
- });
203
- }
204
- async function resolveWhatsAppApprovalReactionTargetFromCandidates(params) {
205
- const candidateRemoteJids = [];
206
- for (const observedRemoteJid of params.observedRemoteJids) {
207
- addCandidateRemoteJid(candidateRemoteJids, observedRemoteJid);
208
- try {
209
- for (const candidate of await params.resolveReactionTargetJids?.(observedRemoteJid) ?? []) addCandidateRemoteJid(candidateRemoteJids, candidate);
210
- } catch (error) {
211
- params.logVerboseMessage?.(`whatsapp: approval reaction target JID mapping failed for ${observedRemoteJid}: ${String(error)}`);
212
- }
213
- }
214
- for (const remoteJid of candidateRemoteJids) {
215
- const target = await resolveWhatsAppApprovalReactionTargetWithPersistence({
216
- accountId: params.accountId,
217
- remoteJid,
218
- messageId: params.messageId,
219
- reactionKey: params.reactionKey
220
- });
221
- if (target) return {
222
- ...target,
223
- remoteJid
224
- };
225
- }
226
- return null;
227
- }
228
- function readWhatsAppApprovalReactionEvent(params) {
229
- const msg = params.msg;
230
- const reaction = msg.message?.reactionMessage;
231
- const reactionKey = reaction?.text?.trim() ?? "";
232
- const messageId = reaction?.key?.id?.trim() ?? "";
233
- const remoteJids = [];
234
- addCandidateRemoteJid(remoteJids, reaction?.key?.remoteJid);
235
- addCandidateRemoteJid(remoteJids, msg.key?.remoteJid);
236
- const actorJid = msg.key?.participant?.trim() || (msg.key?.fromMe ? params.selfLid?.trim() ?? params.selfJid?.trim() ?? "" : msg.key?.remoteJid?.trim() ?? "");
237
- if (!reactionKey || !messageId || remoteJids.length === 0 || !actorJid) return null;
238
- return {
239
- remoteJids,
240
- messageId,
241
- actorJid,
242
- reactionKey
243
- };
244
- }
245
- async function maybeResolveWhatsAppApprovalReaction(params) {
246
- const event = readWhatsAppApprovalReactionEvent({
247
- msg: params.msg,
248
- selfJid: params.selfJid,
249
- selfLid: params.selfLid
250
- });
251
- if (!event) return false;
252
- const target = await resolveWhatsAppApprovalReactionTargetFromCandidates({
253
- accountId: params.accountId,
254
- observedRemoteJids: event.remoteJids,
255
- messageId: event.messageId,
256
- reactionKey: event.reactionKey,
257
- resolveReactionTargetJids: params.resolveReactionTargetJids,
258
- logVerboseMessage: params.logVerboseMessage
259
- });
260
- if (!target) return false;
261
- const actorId = await params.resolveInboundJid(event.actorJid);
262
- if (!actorId) {
263
- params.logVerboseMessage?.(`whatsapp: approval reaction ignored for ${target.approvalId}; missing actor identity`);
264
- return true;
265
- }
266
- const approvalKind = target.approvalId.startsWith("plugin:") ? "plugin" : "exec";
267
- if (getWhatsAppApprovalApprovers({
268
- cfg: params.cfg,
269
- accountId: params.accountId
270
- }).length === 0) {
271
- params.logVerboseMessage?.(`whatsapp: approval reaction denied id=${target.approvalId}; reactions require explicit approvers`);
272
- return true;
273
- }
274
- if (!whatsappApprovalAuth.authorizeActorAction({
275
- cfg: params.cfg,
276
- accountId: params.accountId,
277
- senderId: actorId,
278
- action: "approve",
279
- approvalKind
280
- }).authorized) {
281
- params.logVerboseMessage?.(`whatsapp: approval reaction denied id=${target.approvalId} sender=${actorId}`);
282
- return true;
283
- }
284
- const { isApprovalNotFoundError, resolveWhatsAppApproval } = await loadApprovalResolver();
285
- try {
286
- await resolveWhatsAppApproval({
287
- cfg: params.cfg,
288
- approvalId: target.approvalId,
289
- decision: target.decision,
290
- senderId: actorId,
291
- gatewayUrl: params.gatewayUrl
292
- });
293
- params.logVerboseMessage?.(`whatsapp: approval reaction resolved id=${target.approvalId} sender=${actorId} decision=${target.decision}`);
294
- return true;
295
- } catch (error) {
296
- if (isApprovalNotFoundError(error)) {
297
- unregisterWhatsAppApprovalReactionTarget({
298
- accountId: params.accountId,
299
- remoteJid: target.remoteJid,
300
- messageId: event.messageId
301
- });
302
- params.logVerboseMessage?.(`whatsapp: approval reaction ignored for expired approval id=${target.approvalId} sender=${actorId}`);
303
- return true;
304
- }
305
- params.logVerboseMessage?.(`whatsapp: approval reaction failed id=${target.approvalId} sender=${actorId}: ${String(error)}`);
306
- return true;
307
- }
308
- }
309
- //#endregion
310
40
  //#region extensions/whatsapp/src/document-filename.ts
311
41
  const WHATSAPP_DEFAULT_DOCUMENT_FILE_NAME = "file";
312
42
  function resolveWhatsAppDefaultDocumentFileName(mimetype) {
@@ -347,11 +77,15 @@ function normalizeWhatsAppPayloadTextPreservingIndentation(text) {
347
77
  const normalized = stripLeadingBlankLines(finalizeWhatsAppVisibleText(sanitizeAssistantVisibleTextWithProfile(stripLeadingBlankLines(text ?? ""), "history")));
348
78
  return normalized.trim() ? normalized : "";
349
79
  }
350
- function resolveWhatsAppOutboundMediaUrls(payload) {
351
- return uniqueStrings([payload.mediaUrl?.trim(), ...(payload.mediaUrls ? [...payload.mediaUrls] : []).map((entry) => entry.trim()).filter((entry) => Boolean(entry))].filter((entry) => Boolean(entry)));
80
+ function resolveAdditiveWhatsAppMediaUrls(payload) {
81
+ return normalizeUniqueStringEntries([...payload.mediaUrl ? [payload.mediaUrl] : [], ...payload.mediaUrls ?? []]);
352
82
  }
353
83
  function normalizeWhatsAppOutboundPayload(payload, options) {
354
- const mediaUrls = resolveWhatsAppOutboundMediaUrls(payload);
84
+ const preferredMediaUrls = normalizeUniqueStringEntries(payload.mediaUrls);
85
+ const mediaUrls = normalizeUniqueStringEntries(resolveOutboundMediaUrls({
86
+ mediaUrl: payload.mediaUrl,
87
+ mediaUrls: preferredMediaUrls
88
+ }));
355
89
  const normalizeText = options?.normalizeText ?? normalizeWhatsAppPayloadText;
356
90
  return {
357
91
  ...payload,
@@ -463,32 +197,6 @@ function deriveWhatsAppDocumentFileName(mediaUrl) {
463
197
  return (mediaUrl.split(/[?#]/, 1)[0] ?? "").split(/[\\/]/).pop() || void 0;
464
198
  }
465
199
  }
466
- function isRetryableWhatsAppOutboundError(error) {
467
- if (isWhatsAppSocketOperationTimeoutError(error)) return false;
468
- return /closed|reset|timed\s*out|disconnect/i.test(formatError(error));
469
- }
470
- async function sendWhatsAppOutboundWithRetry(params) {
471
- const maxAttempts = params.maxAttempts ?? 3;
472
- let lastError;
473
- for (let attempt = 1; attempt <= maxAttempts; attempt += 1) try {
474
- return await params.send();
475
- } catch (error) {
476
- lastError = error;
477
- const errorText = formatError(error);
478
- const isLastAttempt = attempt === maxAttempts;
479
- if (!isRetryableWhatsAppOutboundError(error) || isLastAttempt) throw error;
480
- const backoffMs = 500 * attempt;
481
- await params.onRetry?.({
482
- attempt,
483
- maxAttempts,
484
- backoffMs,
485
- error,
486
- errorText
487
- });
488
- await sleep(backoffMs);
489
- }
490
- throw lastError;
491
- }
492
200
  //#endregion
493
201
  //#region extensions/whatsapp/src/outbound-media.runtime.ts
494
202
  async function loadOutboundMediaFromUrl(mediaUrl, options = {}) {
@@ -544,8 +252,11 @@ function resolveOutboundWhatsAppAccountId(params) {
544
252
  }
545
253
  function requireOutboundActiveWebListener(params) {
546
254
  const resolvedAccountId = resolveOutboundWhatsAppAccountId(params) ?? resolveDefaultWhatsAppAccountId(params.cfg);
547
- const listener = getRegisteredWhatsAppConnectionController(resolvedAccountId)?.getActiveListener() ?? null;
548
- if (!listener) throw new Error(`No active WhatsApp Web listener (account: ${resolvedAccountId}). Start the gateway, then link WhatsApp with: ${formatCliCommand(`openclaw channels login --channel whatsapp --account ${resolvedAccountId}`)}.`);
255
+ const listener = getWhatsAppConnectionController(resolvedAccountId)?.getActiveListener() ?? null;
256
+ if (!listener) {
257
+ const cause = /* @__PURE__ */ new Error(`No active WhatsApp Web listener (account: ${resolvedAccountId}). Start the gateway, then link WhatsApp with: ${formatCliCommand(`openclaw channels login --channel whatsapp --account ${resolvedAccountId}`)}.`);
258
+ throw new PlatformMessageNotDispatchedError(cause.message, { cause });
259
+ }
549
260
  return {
550
261
  accountId: resolvedAccountId,
551
262
  listener
@@ -561,7 +272,7 @@ function resolveActualSentRemoteJid(result, fallbackJid) {
561
272
  async function sendMessageWhatsApp(to, body, options) {
562
273
  let text = options.preserveLeadingWhitespace ? body : normalizeWhatsAppPayloadText(body);
563
274
  const jid = toWhatsappJid(to);
564
- const mediaUrls = resolveWhatsAppOutboundMediaUrls(options);
275
+ const mediaUrls = resolveAdditiveWhatsAppMediaUrls(options);
565
276
  const mediaPayload = options.mediaPayload;
566
277
  const primaryMediaUrl = mediaUrls[0] ?? mediaPayload?.fileName;
567
278
  const hasMedia = Boolean(mediaPayload || primaryMediaUrl);
@@ -653,12 +364,6 @@ async function sendMessageWhatsApp(to, body, options) {
653
364
  toJid: resolveActualSentRemoteJid(captionResult, jid)
654
365
  });
655
366
  }
656
- if (messageId && messageId !== "unknown" && text) registerWhatsAppApprovalReactionTargetForOutboundMessage({
657
- accountId: resolvedAccountId,
658
- remoteJid: sentRemoteJid,
659
- messageId,
660
- text
661
- });
662
367
  const durationMs = Date.now() - startedAt;
663
368
  outboundLog.info(`Sent message ${messageId} -> ${redactedJid}${hasMedia ? " (media)" : ""} (${durationMs}ms)`);
664
369
  logger.info({
@@ -770,4 +475,4 @@ async function sendPollWhatsApp(to, poll, options) {
770
475
  }
771
476
  }
772
477
  //#endregion
773
- export { normalizeWhatsAppOutboundPayload as a, prepareWhatsAppOutboundMedia as c, maybeResolveWhatsAppApprovalReaction as d, registerWhatsAppApprovalReactionTarget as f, resolveWhatsAppReactionLevel as g, whatsappApprovalAuth as h, sendTypingWhatsApp as i, sendWhatsAppOutboundWithRetry as l, getWhatsAppApprovalApprovers as m, sendPollWhatsApp as n, normalizeWhatsAppPayloadText as o, unregisterWhatsAppApprovalReactionTarget as p, sendReactionWhatsApp as r, normalizeWhatsAppPayloadTextPreservingIndentation as s, sendMessageWhatsApp as t, resolveWhatsAppDocumentFileName as u };
478
+ export { normalizeWhatsAppOutboundPayload as a, prepareWhatsAppOutboundMedia as c, sendTypingWhatsApp as i, resolveWhatsAppDocumentFileName as l, sendPollWhatsApp as n, normalizeWhatsAppPayloadText as o, sendReactionWhatsApp as r, normalizeWhatsAppPayloadTextPreservingIndentation as s, sendMessageWhatsApp as t, resolveWhatsAppReactionLevel as u };
@@ -1,17 +1,16 @@
1
- import { n as isWhatsAppNewsletterJid } from "./normalize-target-bVWjgftN.js";
2
- import { u as resolveWhatsAppDocumentFileName } from "./send-C5CpFcBG.js";
3
- import "./normalize-Bxwqo-bW.js";
4
- import { c as toWhatsappJidWithLid, r as jidToE164, s as toWhatsappJid } from "./targets-runtime-C-GiVn6Y.js";
5
- import "./text-runtime-DdX6-mC_.js";
6
- import { i as buildQuotedMessageOptions } from "./group-session-key-BhC1RQOE.js";
7
- import { c as resolveComparableIdentity } from "./identity-Dqft3mFA.js";
1
+ import { n as isWhatsAppNewsletterJid } from "./normalize-target-DSZnHkKF.js";
2
+ import { l as resolveWhatsAppDocumentFileName } from "./send-D9Ydnn4o.js";
3
+ import "./normalize-C-Z16y7Q.js";
4
+ import { c as toWhatsappJidWithLid, r as jidToE164, s as toWhatsappJid } from "./targets-runtime-Bsh0HR9y.js";
5
+ import "./text-runtime-BTGkMN0o.js";
6
+ import { i as buildQuotedMessageOptions } from "./group-session-key-CLTZeH_F.js";
7
+ import { c as resolveComparableIdentity } from "./identity-D7L8LCuH.js";
8
8
  import { normalizeLowercaseStringOrEmpty, normalizeStringEntries, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
9
- import { createMessageReceiptFromOutboundResults, listMessageReceiptPlatformIds } from "openclaw/plugin-sdk/channel-outbound";
10
9
  import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
10
+ import { createMessageReceiptFromOutboundResults, listMessageReceiptPlatformIds } from "openclaw/plugin-sdk/channel-outbound";
11
11
  import { getImageMetadata, resizeToJpeg } from "openclaw/plugin-sdk/media-runtime";
12
12
  import { formatLocationText } from "openclaw/plugin-sdk/channel-inbound";
13
13
  import { DisconnectReason, downloadMediaMessage, extractMessageContent, getContentType, isJidGroup, normalizeMessageContent, normalizeMessageContent as normalizeMessageContent$1 } from "baileys";
14
- import "openclaw/plugin-sdk/media-store";
15
14
  import { recordChannelActivity } from "openclaw/plugin-sdk/channel-activity-runtime";
16
15
  //#region extensions/whatsapp/src/vcard.ts
17
16
  const ALLOWED_VCARD_KEYS = /* @__PURE__ */ new Set([
@@ -75,85 +74,20 @@ function normalizeVcardPhone(value) {
75
74
  }
76
75
  //#endregion
77
76
  //#region extensions/whatsapp/src/inbound/extract.ts
78
- const MESSAGE_WRAPPER_KEYS = [
79
- "botInvokeMessage",
80
- "ephemeralMessage",
81
- "viewOnceMessage",
82
- "viewOnceMessageV2",
83
- "viewOnceMessageV2Extension",
84
- "documentWithCaptionMessage",
85
- "groupMentionedMessage"
86
- ];
87
- const MESSAGE_CONTENT_KEYS = [
88
- "conversation",
89
- "extendedTextMessage",
90
- "imageMessage",
91
- "videoMessage",
92
- "audioMessage",
93
- "documentMessage",
94
- "stickerMessage",
95
- "locationMessage",
96
- "liveLocationMessage",
97
- "contactMessage",
98
- "contactsArrayMessage",
99
- "buttonsResponseMessage",
100
- "listResponseMessage",
101
- "templateButtonReplyMessage",
102
- "interactiveResponseMessage",
103
- "buttonsMessage",
104
- "listMessage"
105
- ];
106
- function fallbackNormalizeMessageContent(message) {
107
- let current = message;
108
- while (current && typeof current === "object") {
109
- let unwrapped = false;
110
- for (const key of MESSAGE_WRAPPER_KEYS) {
111
- const candidate = current[key];
112
- if (candidate && typeof candidate === "object" && "message" in candidate && candidate.message) {
113
- current = candidate.message;
114
- unwrapped = true;
115
- break;
116
- }
117
- }
118
- if (!unwrapped) break;
119
- }
120
- return current;
121
- }
122
- function normalizeMessage(message) {
123
- if (typeof normalizeMessageContent === "function") return normalizeMessageContent(message);
124
- return fallbackNormalizeMessageContent(message);
125
- }
126
- function fallbackGetContentType(message) {
127
- const normalized = fallbackNormalizeMessageContent(message);
128
- if (!normalized || typeof normalized !== "object") return;
129
- for (const key of MESSAGE_CONTENT_KEYS) if (normalized[key] != null) return key;
130
- }
131
- function getMessageContentType(message) {
132
- if (typeof getContentType === "function") return getContentType(message);
133
- return fallbackGetContentType(message);
134
- }
135
- function extractMessage(message) {
136
- if (typeof extractMessageContent === "function") return extractMessageContent(message);
137
- const normalized = fallbackNormalizeMessageContent(message);
138
- const contentType = fallbackGetContentType(normalized);
139
- if (!normalized || !contentType || contentType === "conversation") return normalized;
140
- const candidate = normalized[contentType];
141
- return candidate && typeof candidate === "object" ? candidate : normalized;
142
- }
143
77
  function getFutureProofInnerMessage(message) {
144
- const contentType = getMessageContentType(message);
78
+ const contentType = getContentType(message);
145
79
  const candidate = contentType ? message[contentType] : void 0;
146
80
  if (candidate && typeof candidate === "object" && "message" in candidate && candidate.message && typeof candidate.message === "object") {
147
- const inner = normalizeMessage(candidate.message);
81
+ const inner = normalizeMessageContent(candidate.message);
148
82
  if (inner) {
149
- const innerType = getMessageContentType(inner);
83
+ const innerType = getContentType(inner);
150
84
  if (innerType && innerType !== contentType) return inner;
151
85
  }
152
86
  }
153
87
  }
154
88
  function buildMessageChain(message) {
155
89
  const chain = [];
156
- let current = normalizeMessage(message);
90
+ let current = normalizeMessageContent(message);
157
91
  while (current && chain.length < 4) {
158
92
  chain.push(current);
159
93
  current = getFutureProofInnerMessage(current);
@@ -164,7 +98,7 @@ function unwrapMessage(message) {
164
98
  return buildMessageChain(message).at(-1);
165
99
  }
166
100
  function extractContextInfoFromMessage(message) {
167
- const contentType = getMessageContentType(message);
101
+ const contentType = getContentType(message);
168
102
  const candidate = contentType ? message[contentType] : void 0;
169
103
  const contextInfo = candidate && typeof candidate === "object" && "contextInfo" in candidate ? candidate.contextInfo : void 0;
170
104
  if (contextInfo) return contextInfo;
@@ -210,7 +144,7 @@ function extractMentionedJids(rawMessage) {
210
144
  function extractText(rawMessage) {
211
145
  const message = unwrapMessage(rawMessage);
212
146
  if (!message) return;
213
- const extracted = extractMessage(message);
147
+ const extracted = extractMessageContent(message);
214
148
  const candidates = [message, extracted && extracted !== message ? extracted : void 0];
215
149
  for (const candidate of candidates) {
216
150
  if (!candidate) continue;
@@ -337,14 +271,14 @@ function describeReplyContext(rawMessage) {
337
271
  const message = unwrapMessage(rawMessage);
338
272
  if (!message) return null;
339
273
  const contextInfo = extractContextInfo(message);
340
- const quoted = normalizeMessage(contextInfo?.quotedMessage);
274
+ const quoted = normalizeMessageContent(contextInfo?.quotedMessage);
341
275
  if (!quoted) return null;
342
276
  const location = extractLocationData(quoted);
343
277
  const locationText = location ? formatLocationText(location) : void 0;
344
278
  let body = [extractText(quoted), locationText].filter(Boolean).join("\n").trim();
345
279
  if (!body) body = extractMediaPlaceholder(quoted);
346
280
  if (!body) {
347
- const quotedType = quoted ? getMessageContentType(quoted) : void 0;
281
+ const quotedType = quoted ? getContentType(quoted) : void 0;
348
282
  logVerbose(`Quoted message missing extractable body${quotedType ? ` (type ${quotedType})` : ""}`);
349
283
  return null;
350
284
  }
@@ -457,8 +391,10 @@ function normalizeKnownUserJid(value) {
457
391
  const trimmed = value.replace(/^whatsapp:/i, "").trim();
458
392
  const jidMatch = trimmed.match(KNOWN_USER_JID_RE);
459
393
  if (jidMatch) {
460
- const domain = jidMatch[2].toLowerCase() === "c.us" ? "s.whatsapp.net" : jidMatch[2].toLowerCase();
461
- return `${jidMatch[1]}@${domain}`;
394
+ const user = jidMatch[1];
395
+ const rawDomain = jidMatch[2];
396
+ if (!user || !rawDomain) return null;
397
+ return `${user}@${rawDomain.toLowerCase() === "c.us" ? "s.whatsapp.net" : rawDomain.toLowerCase()}`;
462
398
  }
463
399
  const digits = trimmed.startsWith("+") ? trimmed.replace(/\D/g, "") : /^\d+$/.test(trimmed) ? trimmed : "";
464
400
  return digits ? `${digits}@s.whatsapp.net` : null;
@@ -467,9 +403,11 @@ function extractKnownJidParts(value) {
467
403
  const normalized = normalizeKnownUserJid(value);
468
404
  if (!normalized) return null;
469
405
  const match = normalized.match(/^(\d+)@(.+)$/);
470
- return match ? {
471
- user: match[1],
472
- domain: match[2]
406
+ const user = match?.[1];
407
+ const domain = match?.[2];
408
+ return user && domain ? {
409
+ user,
410
+ domain
473
411
  } : null;
474
412
  }
475
413
  function extractPhoneDigits(value) {
@@ -555,7 +493,9 @@ function resolveWhatsAppOutboundMentions(params) {
555
493
  const start = match.index;
556
494
  const token = match[0];
557
495
  if (shouldSkipMentionAt(params.text, start, start + token.length, codeRanges)) continue;
558
- const digits = match[1].replace(/\D/g, "");
496
+ const rawDigits = match[1];
497
+ if (!rawDigits) continue;
498
+ const digits = rawDigits.replace(/\D/g, "");
559
499
  const target = token.startsWith("@+") ? byPhone.get(digits) ?? byLid.get(digits) : byLid.get(digits) ?? byPhone.get(digits);
560
500
  if (!target) continue;
561
501
  if (!seenMentionJids.has(target.mentionJid)) {
@@ -1,3 +1,4 @@
1
+ import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
1
2
  //#region extensions/whatsapp/src/session-errors.ts
2
3
  function safeStringify(value, limit = 800) {
3
4
  try {
@@ -15,7 +16,7 @@ function safeStringify(value, limit = 800) {
15
16
  return v;
16
17
  }, 2);
17
18
  if (!raw) return String(value);
18
- return raw.length > limit ? `${raw.slice(0, limit)}…` : raw;
19
+ return raw.length > limit ? `${truncateUtf16Safe(raw, limit)}…` : raw;
19
20
  } catch {
20
21
  return String(value);
21
22
  }