@openclaw/whatsapp 2026.5.18-beta.1 → 2026.5.19-alpha.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.
Files changed (34) hide show
  1. package/dist/{access-control-CTFVk322.js → access-control-Blo69-dW.js} +3 -3
  2. package/dist/{account-config-CNQ33oav.js → account-config-D3OXPtpW.js} +2 -2
  3. package/dist/{accounts-Dn7MUPTZ.js → accounts-CJNZl-3e.js} +1 -1
  4. package/dist/action-runtime-api.js +1 -1
  5. package/dist/{action-runtime-CnXRJ7y1.js → action-runtime-cZLWNUXF.js} +4 -4
  6. package/dist/action-runtime.runtime.js +1 -1
  7. package/dist/api.js +11 -11
  8. package/dist/{channel-DVEvLLA0.js → channel-CHsR8MoG.js} +15 -11
  9. package/dist/channel-plugin-api.js +1 -1
  10. package/dist/channel-react-action-6n63NhGY.js +129 -0
  11. package/dist/{channel.runtime-Bahb-X2a.js → channel.runtime-n14SNsjm.js} +3 -3
  12. package/dist/{channel.setup-BLFtofME.js → channel.setup-BiuhxbjG.js} +1 -1
  13. package/dist/contract-api.js +3 -3
  14. package/dist/{directory-config-BfyInQuH.js → directory-config-QH8Oe8bc.js} +1 -1
  15. package/dist/directory-contract-api.js +1 -1
  16. package/dist/{login-CDwsln_y.js → login-DJYp3l4Z.js} +1 -1
  17. package/dist/{login-qr-B63JLtJG.js → login-qr-CipY7q23.js} +1 -1
  18. package/dist/login-qr-runtime.js +1 -1
  19. package/dist/{monitor-DSBROC8j.js → monitor-oXSnOpto.js} +47 -9
  20. package/dist/{outbound-adapter-pW4J6iz-.js → outbound-adapter-BT7Dkqni.js} +3 -3
  21. package/dist/{outbound-base-Dfj1SAyO.js → outbound-base-ARCS45ql.js} +1 -1
  22. package/dist/{outbound-media-contract-CQnjZqsm.js → outbound-media-contract-ItL7G0Az.js} +9 -1
  23. package/dist/outbound-payload-test-api.js +1 -1
  24. package/dist/{reaction-level-2m9sWGCw.js → reaction-level-DeO7ktWb.js} +1 -1
  25. package/dist/runtime-api.js +5 -5
  26. package/dist/{send-Cn2WKdPM.js → send-BtGELs96.js} +29 -9
  27. package/dist/{send-api-CwheV1Iq.js → send-api-BvUGZEIA.js} +1 -1
  28. package/dist/{setup-core-Dm2jMZHy.js → setup-core-P6dnz4Ur.js} +3 -3
  29. package/dist/{setup-finalize-B16VRsDw.js → setup-finalize-DYm-2hSc.js} +3 -3
  30. package/dist/setup-plugin-api.js +1 -1
  31. package/dist/{setup-surface-Dy9RdlqN.js → setup-surface-Bq3gnUCD.js} +2 -2
  32. package/dist/test-api.js +1 -1
  33. package/package.json +4 -4
  34. package/dist/channel-react-action-UYINADWb.js +0 -42
@@ -1,4 +1,4 @@
1
- import { a as resolveWhatsAppAccount } from "./accounts-Dn7MUPTZ.js";
1
+ import { a as resolveWhatsAppAccount } from "./accounts-CJNZl-3e.js";
2
2
  import { l as isSelfChatMode, n as normalizeE164 } from "./text-runtime-DyR0XOJ4.js";
3
3
  import { a as getSelfIdentity, o as getSenderIdentity } from "./identity-CVFJuB0Q.js";
4
4
  import { t as resolveWhatsAppRuntimeGroupPolicy } from "./runtime-group-policy-BH_U23qp.js";
@@ -238,6 +238,6 @@ async function checkInboundAccessControl(params) {
238
238
  resolvedAccountId: policy.account.accountId
239
239
  };
240
240
  }
241
- const __testing = { resolveWhatsAppInboundPolicy };
241
+ const testing = { resolveWhatsAppInboundPolicy };
242
242
  //#endregion
243
- export { resolveWhatsAppInboundPolicy as i, checkInboundAccessControl as n, resolveWhatsAppCommandAuthorized as r, __testing as t };
243
+ export { resolveWhatsAppInboundPolicy as i, testing as n, resolveWhatsAppCommandAuthorized as r, checkInboundAccessControl as t };
@@ -7,12 +7,12 @@ function resolveWhatsAppDefaultAccountSharedConfig(cfg) {
7
7
  const { enabled: _ignoredEnabled, name: _ignoredName, authDir: _ignoredAuthDir, selfChatMode: _ignoredSelfChatMode, ...sharedDefaults } = defaultAccount;
8
8
  return sharedDefaults;
9
9
  }
10
- function _resolveWhatsAppAccountConfig(cfg, accountId) {
10
+ function resolveWhatsAppAccountConfigForTest(cfg, accountId) {
11
11
  return resolveAccountEntry(cfg.channels?.whatsapp?.accounts, accountId);
12
12
  }
13
13
  function resolveMergedNamedWhatsAppAccountConfig(params) {
14
14
  const rootCfg = params.cfg.channels?.whatsapp;
15
- const accountConfig = _resolveWhatsAppAccountConfig(params.cfg, params.accountId);
15
+ const accountConfig = resolveWhatsAppAccountConfigForTest(params.cfg, params.accountId);
16
16
  return {
17
17
  ...mergeAccountConfig({
18
18
  channelConfig: rootCfg,
@@ -1,4 +1,4 @@
1
- import { t as resolveMergedWhatsAppAccountConfig } from "./account-config-CNQ33oav.js";
1
+ import { t as resolveMergedWhatsAppAccountConfig } from "./account-config-D3OXPtpW.js";
2
2
  import { n as listConfiguredAccountIds, r as resolveDefaultWhatsAppAccountId, t as listAccountIds } from "./account-ids-DgtV_RiP.js";
3
3
  import { t as hasWebCredsSync } from "./creds-files-_2V8jzQa.js";
4
4
  import fs from "node:fs";
@@ -1,2 +1,2 @@
1
- import { t as handleWhatsAppAction } from "./action-runtime-CnXRJ7y1.js";
1
+ import { t as handleWhatsAppAction } from "./action-runtime-cZLWNUXF.js";
2
2
  export { handleWhatsAppAction };
@@ -1,7 +1,7 @@
1
- import { a as resolveWhatsAppAccount } from "./accounts-Dn7MUPTZ.js";
1
+ import { a as resolveWhatsAppAccount } from "./accounts-CJNZl-3e.js";
2
2
  import { t as resolveWhatsAppOutboundTarget } from "./resolve-outbound-target-Ba7sH80H.js";
3
- import { t as resolveWhatsAppReactionLevel } from "./reaction-level-2m9sWGCw.js";
4
- import { r as sendReactionWhatsApp } from "./send-Cn2WKdPM.js";
3
+ import { t as resolveWhatsAppReactionLevel } from "./reaction-level-DeO7ktWb.js";
4
+ import { r as sendReactionWhatsApp } from "./send-BtGELs96.js";
5
5
  import { ToolAuthorizationError, createActionGate, jsonResult, readReactionParams, readStringParam } from "openclaw/plugin-sdk/channel-actions";
6
6
  //#region extensions/whatsapp/src/action-runtime-target-auth.ts
7
7
  function resolveAuthorizedWhatsAppOutboundTarget(params) {
@@ -71,4 +71,4 @@ async function handleWhatsAppAction(params, cfg) {
71
71
  throw new Error(`Unsupported WhatsApp action: ${action}`);
72
72
  }
73
73
  //#endregion
74
- export { whatsAppActionRuntime as n, handleWhatsAppAction as t };
74
+ export { whatsAppActionRuntime as n, resolveAuthorizedWhatsAppOutboundTarget as r, handleWhatsAppAction as t };
@@ -1,2 +1,2 @@
1
- import { t as handleWhatsAppAction } from "./action-runtime-CnXRJ7y1.js";
1
+ import { t as handleWhatsAppAction } from "./action-runtime-cZLWNUXF.js";
2
2
  export { handleWhatsAppAction };
package/dist/api.js CHANGED
@@ -1,20 +1,20 @@
1
1
  import { r as resolveDefaultWhatsAppAccountId, t as listAccountIds } from "./account-ids-DgtV_RiP.js";
2
- import { a as resolveWhatsAppAccount, i as listWhatsAppAuthDirs, n as hasAnyWhatsAppAuth, o as resolveWhatsAppAuthDir, r as listEnabledWhatsAppAccounts, s as resolveWhatsAppMediaMaxBytes, t as DEFAULT_WHATSAPP_MEDIA_MAX_MB } from "./accounts-Dn7MUPTZ.js";
2
+ import { a as resolveWhatsAppAccount, i as listWhatsAppAuthDirs, n as hasAnyWhatsAppAuth, o as resolveWhatsAppAuthDir, r as listEnabledWhatsAppAccounts, s as resolveWhatsAppMediaMaxBytes, t as DEFAULT_WHATSAPP_MEDIA_MAX_MB } from "./accounts-CJNZl-3e.js";
3
3
  import { a as normalizeWhatsAppAllowFromEntries, c as normalizeWhatsAppTarget, i as looksLikeWhatsAppTargetId, r as isWhatsAppUserTarget, s as normalizeWhatsAppMessagingTarget, t as isWhatsAppGroupJid } from "./normalize-target-MB6Z_4Bn.js";
4
4
  import { t as resolveWhatsAppOutboundTarget } from "./resolve-outbound-target-Ba7sH80H.js";
5
- import "./reaction-level-2m9sWGCw.js";
5
+ import "./reaction-level-DeO7ktWb.js";
6
6
  import { c as assertWebChannel, d as markdownToWhatsApp, f as resolveJidToE164, l as isSelfChatMode, m as toWhatsappJidWithLid, n as normalizeE164, p as toWhatsappJid, r as resolveUserPath, u as jidToE164 } from "./text-runtime-DyR0XOJ4.js";
7
- import "./send-Cn2WKdPM.js";
8
- import { t as whatsappPlugin } from "./channel-DVEvLLA0.js";
9
- import { n as WHATSAPP_LEGACY_OUTBOUND_SEND_DEP_KEYS } from "./outbound-base-Dfj1SAyO.js";
7
+ import "./send-BtGELs96.js";
8
+ import { t as whatsappPlugin } from "./channel-CHsR8MoG.js";
9
+ import { n as WHATSAPP_LEGACY_OUTBOUND_SEND_DEP_KEYS } from "./outbound-base-ARCS45ql.js";
10
10
  import { t as whatsappCommandPolicy } from "./command-policy-O8sRnqUV.js";
11
- import { a as resolveWhatsAppGroupRequireMention, o as resolveWhatsAppGroupToolPolicy, s as resolveWhatsAppGroupIntroHint } from "./setup-core-Dm2jMZHy.js";
11
+ import { a as resolveWhatsAppGroupRequireMention, o as resolveWhatsAppGroupToolPolicy, s as resolveWhatsAppGroupIntroHint } from "./setup-core-P6dnz4Ur.js";
12
12
  import "./config-schema-Dmo66Ubb.js";
13
- import { t as whatsappSetupPlugin } from "./channel.setup-BLFtofME.js";
13
+ import { t as whatsappSetupPlugin } from "./channel.setup-BiuhxbjG.js";
14
14
  import { t as DEFAULT_WEB_MEDIA_BYTES } from "./constants-yKXGCGU9.js";
15
- import { n as listWhatsAppDirectoryGroupsFromConfig, r as listWhatsAppDirectoryPeersFromConfig } from "./directory-config-BfyInQuH.js";
16
- import { t as __testing } from "./access-control-CTFVk322.js";
17
- import { p as extractText, t as createWebSendApi } from "./send-api-CwheV1Iq.js";
15
+ import { n as listWhatsAppDirectoryGroupsFromConfig, r as listWhatsAppDirectoryPeersFromConfig } from "./directory-config-QH8Oe8bc.js";
16
+ import { n as testing } from "./access-control-Blo69-dW.js";
17
+ import { p as extractText, t as createWebSendApi } from "./send-api-BvUGZEIA.js";
18
18
  import { r as waitForWaConnection, t as createWaSocket } from "./session-DqDc1usL.js";
19
19
  import "openclaw/plugin-sdk/channel-actions";
20
20
  import "openclaw/plugin-sdk/account-resolution";
@@ -126,4 +126,4 @@ async function startWhatsAppQaDriverSession(params) {
126
126
  };
127
127
  }
128
128
  //#endregion
129
- export { DEFAULT_WEB_MEDIA_BYTES, DEFAULT_WHATSAPP_MEDIA_MAX_MB, WHATSAPP_LEGACY_OUTBOUND_SEND_DEP_KEYS, assertWebChannel, hasAnyWhatsAppAuth, isSelfChatMode, isWhatsAppGroupJid, isWhatsAppUserTarget, jidToE164, listEnabledWhatsAppAccounts, listAccountIds as listWhatsAppAccountIds, listWhatsAppAuthDirs, listWhatsAppDirectoryGroupsFromConfig, listWhatsAppDirectoryPeersFromConfig, looksLikeWhatsAppTargetId, markdownToWhatsApp, normalizeE164, normalizeWhatsAppAllowFromEntries, normalizeWhatsAppMessagingTarget, normalizeWhatsAppTarget, resolveDefaultWhatsAppAccountId, resolveJidToE164, resolveUserPath, resolveWhatsAppAccount, resolveWhatsAppAuthDir, resolveWhatsAppGroupIntroHint, resolveWhatsAppGroupRequireMention, resolveWhatsAppGroupToolPolicy, resolveWhatsAppMediaMaxBytes, resolveWhatsAppOutboundTarget, startWhatsAppQaDriverSession, toWhatsappJid, toWhatsappJidWithLid, __testing as whatsappAccessControlTesting, whatsappCommandPolicy, whatsappPlugin, whatsappSetupPlugin };
129
+ export { DEFAULT_WEB_MEDIA_BYTES, DEFAULT_WHATSAPP_MEDIA_MAX_MB, WHATSAPP_LEGACY_OUTBOUND_SEND_DEP_KEYS, assertWebChannel, hasAnyWhatsAppAuth, isSelfChatMode, isWhatsAppGroupJid, isWhatsAppUserTarget, jidToE164, listEnabledWhatsAppAccounts, listAccountIds as listWhatsAppAccountIds, listWhatsAppAuthDirs, listWhatsAppDirectoryGroupsFromConfig, listWhatsAppDirectoryPeersFromConfig, looksLikeWhatsAppTargetId, markdownToWhatsApp, normalizeE164, normalizeWhatsAppAllowFromEntries, normalizeWhatsAppMessagingTarget, normalizeWhatsAppTarget, resolveDefaultWhatsAppAccountId, resolveJidToE164, resolveUserPath, resolveWhatsAppAccount, resolveWhatsAppAuthDir, resolveWhatsAppGroupIntroHint, resolveWhatsAppGroupRequireMention, resolveWhatsAppGroupToolPolicy, resolveWhatsAppMediaMaxBytes, resolveWhatsAppOutboundTarget, startWhatsAppQaDriverSession, toWhatsappJid, toWhatsappJidWithLid, testing as whatsappAccessControlTesting, whatsappCommandPolicy, whatsappPlugin, whatsappSetupPlugin };
@@ -1,16 +1,16 @@
1
1
  import { t as listAccountIds } from "./account-ids-DgtV_RiP.js";
2
- import { a as resolveWhatsAppAccount } from "./accounts-Dn7MUPTZ.js";
2
+ import { a as resolveWhatsAppAccount } from "./accounts-CJNZl-3e.js";
3
3
  import { c as normalizeWhatsAppTarget, i as looksLikeWhatsAppTargetId, n as isWhatsAppNewsletterJid, o as normalizeWhatsAppAllowFromEntry, s as normalizeWhatsAppMessagingTarget, t as isWhatsAppGroupJid } from "./normalize-target-MB6Z_4Bn.js";
4
4
  import { t as resolveWhatsAppOutboundTarget } from "./resolve-outbound-target-Ba7sH80H.js";
5
- import { t as resolveWhatsAppReactionLevel } from "./reaction-level-2m9sWGCw.js";
6
- import { r as normalizeWhatsAppPayloadTextPreservingIndentation } from "./outbound-media-contract-CQnjZqsm.js";
5
+ import { t as resolveWhatsAppReactionLevel } from "./reaction-level-DeO7ktWb.js";
6
+ import { r as normalizeWhatsAppPayloadTextPreservingIndentation } from "./outbound-media-contract-ItL7G0Az.js";
7
7
  import "./normalize-LMXvL6w0.js";
8
- import { i as sendTypingWhatsApp, n as sendPollWhatsApp, t as sendMessageWhatsApp } from "./send-Cn2WKdPM.js";
8
+ import { i as sendTypingWhatsApp, n as sendPollWhatsApp, t as sendMessageWhatsApp } from "./send-BtGELs96.js";
9
9
  import { t as createWhatsAppLoginTool } from "./agent-tools-login-DpRxLNRB.js";
10
- import { t as createWhatsAppOutboundBase } from "./outbound-base-Dfj1SAyO.js";
10
+ import { t as createWhatsAppOutboundBase } from "./outbound-base-ARCS45ql.js";
11
11
  import { t as getWhatsAppRuntime } from "./runtime-6fZ67abR.js";
12
12
  import { t as whatsappCommandPolicy } from "./command-policy-O8sRnqUV.js";
13
- import { a as resolveWhatsAppGroupRequireMention, c as resolveWhatsAppMentionStripRegexes, i as whatsappSetupWizardProxy, l as formatWhatsAppConfigAllowFromEntries, n as createWhatsAppPluginBase, o as resolveWhatsAppGroupToolPolicy, r as loadWhatsAppChannelRuntime, s as resolveWhatsAppGroupIntroHint, t as whatsappSetupAdapter } from "./setup-core-Dm2jMZHy.js";
13
+ import { a as resolveWhatsAppGroupRequireMention, c as resolveWhatsAppMentionStripRegexes, i as whatsappSetupWizardProxy, l as formatWhatsAppConfigAllowFromEntries, n as createWhatsAppPluginBase, o as resolveWhatsAppGroupToolPolicy, r as loadWhatsAppChannelRuntime, s as resolveWhatsAppGroupIntroHint, t as whatsappSetupAdapter } from "./setup-core-P6dnz4Ur.js";
14
14
  import { f as readWebAuthExistsForDecision, n as WHATSAPP_AUTH_UNSTABLE_CODE } from "./auth-store-BLGYDyCH.js";
15
15
  import { t as detectWhatsAppLegacyStateMigrations } from "./state-migrations-CtdIArlK.js";
16
16
  import { createActionGate as createActionGate$1 } from "openclaw/plugin-sdk/channel-actions";
@@ -87,6 +87,7 @@ function describeWhatsAppMessageActions(params) {
87
87
  accountId: params.accountId ?? void 0
88
88
  }) : hasAnyWhatsAppAccountWithAgentReactionsEnabled(params.cfg)) actions.add("react");
89
89
  if (gate("polls")) actions.add("poll");
90
+ actions.add("upload-file");
90
91
  return { actions: Array.from(actions) };
91
92
  }
92
93
  //#endregion
@@ -321,8 +322,8 @@ function collectWhatsAppStatusIssues(accounts) {
321
322
  }
322
323
  //#endregion
323
324
  //#region extensions/whatsapp/src/channel.ts
324
- const loadWhatsAppDirectoryConfig = createLazyRuntimeModule(() => import("./directory-config-BfyInQuH.js").then((n) => n.t));
325
- const loadWhatsAppChannelReactAction = createLazyRuntimeModule(() => import("./channel-react-action-UYINADWb.js"));
325
+ const loadWhatsAppDirectoryConfig = createLazyRuntimeModule(() => import("./directory-config-QH8Oe8bc.js").then((n) => n.t));
326
+ const loadWhatsAppChannelReactAction = createLazyRuntimeModule(() => import("./channel-react-action-6n63NhGY.js"));
326
327
  function parseWhatsAppExplicitTarget(raw) {
327
328
  const normalized = normalizeWhatsAppTarget(raw);
328
329
  if (!normalized) return null;
@@ -418,14 +419,17 @@ const whatsappPlugin = createChatChannelPlugin({
418
419
  cfg,
419
420
  accountId
420
421
  }),
421
- supportsAction: ({ action }) => action === "react",
422
- resolveExecutionMode: ({ action }) => action === "react" ? "gateway" : "local",
423
- handleAction: async ({ action, params, cfg, accountId, requesterSenderId, toolContext }) => await (await loadWhatsAppChannelReactAction()).handleWhatsAppReactAction({
422
+ supportsAction: ({ action }) => action === "react" || action === "upload-file",
423
+ resolveExecutionMode: ({ action }) => action === "react" || action === "upload-file" ? "gateway" : "local",
424
+ handleAction: async ({ action, params, cfg, accountId, requesterSenderId, mediaAccess, mediaLocalRoots, mediaReadFile, toolContext }) => await (await loadWhatsAppChannelReactAction()).handleWhatsAppMessageAction({
424
425
  action,
425
426
  params,
426
427
  cfg,
427
428
  accountId,
428
429
  requesterSenderId,
430
+ mediaAccess,
431
+ mediaLocalRoots,
432
+ mediaReadFile,
429
433
  toolContext
430
434
  })
431
435
  },
@@ -1,2 +1,2 @@
1
- import { t as whatsappPlugin } from "./channel-DVEvLLA0.js";
1
+ import { t as whatsappPlugin } from "./channel-CHsR8MoG.js";
2
2
  export { whatsappPlugin };
@@ -0,0 +1,129 @@
1
+ import { a as resolveWhatsAppAccount, s as resolveWhatsAppMediaMaxBytes } from "./accounts-CJNZl-3e.js";
2
+ import { c as normalizeWhatsAppTarget, t as isWhatsAppGroupJid } from "./normalize-target-MB6Z_4Bn.js";
3
+ import { r as resolveAuthorizedWhatsAppOutboundTarget, t as handleWhatsAppAction } from "./action-runtime-cZLWNUXF.js";
4
+ import "./normalize-LMXvL6w0.js";
5
+ import { t as sendMessageWhatsApp } from "./send-BtGELs96.js";
6
+ import { jsonResult, readStringOrNumberParam, readStringParam as readStringParam$1, resolveReactionMessageId } from "openclaw/plugin-sdk/channel-actions";
7
+ //#region extensions/whatsapp/src/channel-react-action.ts
8
+ const WHATSAPP_CHANNEL = "whatsapp";
9
+ function readUploadFileMediaSource(args) {
10
+ return readStringParam$1(args, "media", { trim: false }) ?? readStringParam$1(args, "mediaUrl", { trim: false }) ?? readStringParam$1(args, "filePath", { trim: false }) ?? readStringParam$1(args, "path", { trim: false }) ?? readStringParam$1(args, "fileUrl", { trim: false });
11
+ }
12
+ function readUploadFileCaptionText(args) {
13
+ return readStringParam$1(args, "message", { allowEmpty: true }) ?? readStringParam$1(args, "content", { allowEmpty: true }) ?? readStringParam$1(args, "caption", { allowEmpty: true }) ?? "";
14
+ }
15
+ function readBooleanParam(args, key) {
16
+ const value = args[key];
17
+ if (typeof value === "boolean") return value;
18
+ if (typeof value !== "string") return;
19
+ const normalized = value.trim().toLowerCase();
20
+ if (normalized === "true") return true;
21
+ if (normalized === "false") return false;
22
+ }
23
+ function hasUploadFileBufferPayload(args) {
24
+ return readStringParam$1(args, "buffer", { trim: false }) !== void 0;
25
+ }
26
+ function extractBase64Payload(encoded) {
27
+ const match = /^data:[^;]+;base64,(.*)$/i.exec(encoded.trim());
28
+ return match ? match[1] : encoded;
29
+ }
30
+ function estimateBase64DecodedBytes(encoded) {
31
+ const compact = extractBase64Payload(encoded).replace(/\s/g, "");
32
+ if (!compact) return 0;
33
+ const padding = compact.endsWith("==") ? 2 : compact.endsWith("=") ? 1 : 0;
34
+ return Math.max(0, Math.floor(compact.length * 3 / 4) - padding);
35
+ }
36
+ function decodeUploadFileMediaPayload(params) {
37
+ if (params.maxBytes !== void 0) {
38
+ const estimatedBytes = estimateBase64DecodedBytes(params.encoded);
39
+ if (estimatedBytes > params.maxBytes) throw new Error(`WhatsApp upload-file buffer exceeds configured media limit (${estimatedBytes} bytes > ${params.maxBytes} bytes).`);
40
+ }
41
+ const contentType = readStringParam$1(params.args, "contentType") ?? readStringParam$1(params.args, "mimeType");
42
+ const fileName = readStringParam$1(params.args, "filename") ?? readStringParam$1(params.args, "fileName");
43
+ const buffer = Buffer.from(extractBase64Payload(params.encoded), "base64");
44
+ if (params.maxBytes !== void 0 && buffer.byteLength > params.maxBytes) throw new Error(`WhatsApp upload-file buffer exceeds configured media limit (${buffer.byteLength} bytes > ${params.maxBytes} bytes).`);
45
+ return {
46
+ buffer,
47
+ ...contentType ? { contentType } : {},
48
+ ...fileName ? { fileName } : {}
49
+ };
50
+ }
51
+ async function handleWhatsAppUploadFileAction(params) {
52
+ const mediaUrl = readUploadFileMediaSource(params.params);
53
+ const encodedPayload = readStringParam$1(params.params, "buffer", { trim: false });
54
+ if (!mediaUrl && !hasUploadFileBufferPayload(params.params)) throw new Error("WhatsApp upload-file requires media, mediaUrl, filePath, path, fileUrl, or buffer.");
55
+ const to = readStringParam$1(params.params, "to", { required: true });
56
+ const resolved = resolveAuthorizedWhatsAppOutboundTarget({
57
+ cfg: params.cfg,
58
+ chatJid: to,
59
+ accountId: params.accountId ?? void 0,
60
+ actionLabel: "upload-file"
61
+ });
62
+ const account = resolveWhatsAppAccount({
63
+ cfg: params.cfg,
64
+ accountId: resolved.accountId
65
+ });
66
+ const mediaPayload = encodedPayload ? decodeUploadFileMediaPayload({
67
+ args: params.params,
68
+ encoded: encodedPayload,
69
+ maxBytes: resolveWhatsAppMediaMaxBytes(account)
70
+ }) : void 0;
71
+ const result = await sendMessageWhatsApp(resolved.to, readUploadFileCaptionText(params.params), {
72
+ verbose: false,
73
+ cfg: params.cfg,
74
+ ...mediaUrl && !mediaPayload ? { mediaUrl } : {},
75
+ ...mediaPayload ? { mediaPayload } : {},
76
+ mediaAccess: params.mediaAccess,
77
+ mediaLocalRoots: params.mediaLocalRoots,
78
+ mediaReadFile: params.mediaReadFile,
79
+ gifPlayback: readBooleanParam(params.params, "gifPlayback") ?? void 0,
80
+ audioAsVoice: readBooleanParam(params.params, "asVoice") ?? readBooleanParam(params.params, "audioAsVoice") ?? void 0,
81
+ forceDocument: readBooleanParam(params.params, "forceDocument") ?? readBooleanParam(params.params, "asDocument") ?? void 0,
82
+ accountId: resolved.accountId
83
+ });
84
+ return jsonResult({
85
+ ok: true,
86
+ channel: WHATSAPP_CHANNEL,
87
+ action: "upload-file",
88
+ messageId: result.messageId,
89
+ toJid: result.toJid
90
+ });
91
+ }
92
+ async function handleWhatsAppMessageAction(params) {
93
+ if (params.action === "upload-file") return await handleWhatsAppUploadFileAction(params);
94
+ if (params.action !== "react") throw new Error(`Action ${params.action} is not supported for provider ${WHATSAPP_CHANNEL}.`);
95
+ const isWhatsAppSource = params.toolContext?.currentChannelProvider === WHATSAPP_CHANNEL;
96
+ const explicitTarget = readStringParam$1(params.params, "chatJid") ?? readStringParam$1(params.params, "to");
97
+ const normalizedTarget = explicitTarget ? normalizeWhatsAppTarget(explicitTarget) : null;
98
+ const normalizedCurrent = isWhatsAppSource && params.toolContext?.currentChannelId ? normalizeWhatsAppTarget(params.toolContext.currentChannelId) : null;
99
+ const isCrossChat = normalizedTarget != null && (normalizedCurrent == null || normalizedTarget !== normalizedCurrent);
100
+ const scopedContext = !isWhatsAppSource || isCrossChat || !params.toolContext ? void 0 : {
101
+ currentChannelId: params.toolContext.currentChannelId ?? void 0,
102
+ currentChannelProvider: params.toolContext.currentChannelProvider ?? void 0,
103
+ currentMessageId: params.toolContext.currentMessageId ?? void 0
104
+ };
105
+ const messageIdRaw = resolveReactionMessageId({
106
+ args: params.params,
107
+ toolContext: scopedContext
108
+ });
109
+ if (messageIdRaw == null) readStringParam$1(params.params, "messageId", { required: true });
110
+ const messageId = String(messageIdRaw);
111
+ const explicitMessageId = readStringOrNumberParam(params.params, "messageId");
112
+ const emoji = readStringParam$1(params.params, "emoji", { allowEmpty: true });
113
+ const remove = typeof params.params.remove === "boolean" ? params.params.remove : void 0;
114
+ const explicitParticipant = readStringParam$1(params.params, "participant");
115
+ const inferredParticipant = explicitParticipant || explicitMessageId != null || !isWhatsAppSource || isCrossChat || !isWhatsAppGroupJid(explicitTarget ?? params.toolContext?.currentChannelId ?? "") ? void 0 : typeof params.requesterSenderId === "string" && params.requesterSenderId.trim().length > 0 ? params.requesterSenderId.trim() : void 0;
116
+ return await handleWhatsAppAction({
117
+ action: "react",
118
+ chatJid: readStringParam$1(params.params, "chatJid") ?? readStringParam$1(params.params, "to", { required: true }),
119
+ messageId,
120
+ emoji,
121
+ remove,
122
+ participant: explicitParticipant ?? inferredParticipant,
123
+ accountId: params.accountId ?? void 0,
124
+ fromMe: typeof params.params.fromMe === "boolean" ? params.params.fromMe : void 0
125
+ }, params.cfg);
126
+ }
127
+ const handleWhatsAppReactAction = handleWhatsAppMessageAction;
128
+ //#endregion
129
+ export { handleWhatsAppMessageAction, handleWhatsAppReactAction };
@@ -1,9 +1,9 @@
1
1
  import { startWebLoginWithQr as startWebLoginWithQr$1, waitForWebLogin as waitForWebLogin$1 } from "./login-qr-runtime.js";
2
2
  import { c as logoutWeb$1, d as readWebAuthExistsBestEffort$1, f as readWebAuthExistsForDecision$1, g as readWebSelfId$1, h as readWebAuthState$1, m as readWebAuthSnapshotBestEffort$1, o as getWebAuthAgeMs$1, p as readWebAuthSnapshot$1, s as logWebSelfId$1, x as webAuthExists$1 } from "./auth-store-BLGYDyCH.js";
3
3
  import { t as getActiveWebListener$1 } from "./active-listener-C4ClVut4.js";
4
- import { t as monitorWebChannel$1 } from "./monitor-DSBROC8j.js";
5
- import { t as loginWeb$1 } from "./login-CDwsln_y.js";
6
- import { whatsappSetupWizard as whatsappSetupWizard$1 } from "./setup-surface-Dy9RdlqN.js";
4
+ import { t as monitorWebChannel$1 } from "./monitor-oXSnOpto.js";
5
+ import { t as loginWeb$1 } from "./login-DJYp3l4Z.js";
6
+ import { whatsappSetupWizard as whatsappSetupWizard$1 } from "./setup-surface-Bq3gnUCD.js";
7
7
  //#region extensions/whatsapp/src/channel.runtime.ts
8
8
  function getActiveWebListener(...args) {
9
9
  return getActiveWebListener$1(...args);
@@ -1,4 +1,4 @@
1
- import { a as resolveWhatsAppGroupRequireMention, i as whatsappSetupWizardProxy, n as createWhatsAppPluginBase, o as resolveWhatsAppGroupToolPolicy, s as resolveWhatsAppGroupIntroHint, t as whatsappSetupAdapter } from "./setup-core-Dm2jMZHy.js";
1
+ import { a as resolveWhatsAppGroupRequireMention, i as whatsappSetupWizardProxy, n as createWhatsAppPluginBase, o as resolveWhatsAppGroupToolPolicy, s as resolveWhatsAppGroupIntroHint, t as whatsappSetupAdapter } from "./setup-core-P6dnz4Ur.js";
2
2
  import { t as detectWhatsAppLegacyStateMigrations } from "./state-migrations-CtdIArlK.js";
3
3
  //#region extensions/whatsapp/src/channel.setup.ts
4
4
  async function isWhatsAppAuthConfigured(account) {
@@ -3,9 +3,9 @@ import { t as whatsappCommandPolicy$1 } from "./command-policy-O8sRnqUV.js";
3
3
  import { t as resolveLegacyGroupSessionKey$1 } from "./group-session-contract-DdqigLJl.js";
4
4
  import { n as unsupportedSecretRefSurfacePatterns, t as collectUnsupportedSecretRefConfigCandidates } from "./security-contract-CvfWex9e.js";
5
5
  import { r as isLegacyGroupSessionKey$1, t as canonicalizeLegacySessionKey$1 } from "./session-contract-B0efQf9P.js";
6
- import { n as listWhatsAppDirectoryGroupsFromConfig, r as listWhatsAppDirectoryPeersFromConfig } from "./directory-config-BfyInQuH.js";
6
+ import { n as listWhatsAppDirectoryGroupsFromConfig, r as listWhatsAppDirectoryPeersFromConfig } from "./directory-config-QH8Oe8bc.js";
7
7
  import { t as resolveWhatsAppRuntimeGroupPolicy$1 } from "./runtime-group-policy-BH_U23qp.js";
8
- import { t as __testing } from "./access-control-CTFVk322.js";
8
+ import { n as testing } from "./access-control-Blo69-dW.js";
9
9
  //#region extensions/whatsapp/contract-api.ts
10
10
  const canonicalizeLegacySessionKey = canonicalizeLegacySessionKey$1;
11
11
  const isLegacyGroupSessionKey = isLegacyGroupSessionKey$1;
@@ -13,7 +13,7 @@ const isWhatsAppGroupJid = isWhatsAppGroupJid$1;
13
13
  const normalizeWhatsAppTarget = normalizeWhatsAppTarget$1;
14
14
  const resolveLegacyGroupSessionKey = resolveLegacyGroupSessionKey$1;
15
15
  const resolveWhatsAppRuntimeGroupPolicy = resolveWhatsAppRuntimeGroupPolicy$1;
16
- const whatsappAccessControlTesting = __testing;
16
+ const whatsappAccessControlTesting = testing;
17
17
  const whatsappCommandPolicy = whatsappCommandPolicy$1;
18
18
  //#endregion
19
19
  export { canonicalizeLegacySessionKey, collectUnsupportedSecretRefConfigCandidates, isLegacyGroupSessionKey, isWhatsAppGroupJid, listWhatsAppDirectoryGroupsFromConfig, listWhatsAppDirectoryPeersFromConfig, normalizeWhatsAppTarget, resolveLegacyGroupSessionKey, resolveWhatsAppRuntimeGroupPolicy, unsupportedSecretRefSurfacePatterns, whatsappAccessControlTesting, whatsappCommandPolicy };
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-CiIaOW0V.js";
2
- import { t as resolveMergedWhatsAppAccountConfig } from "./account-config-CNQ33oav.js";
2
+ import { t as resolveMergedWhatsAppAccountConfig } from "./account-config-D3OXPtpW.js";
3
3
  import { c as normalizeWhatsAppTarget, t as isWhatsAppGroupJid } from "./normalize-target-MB6Z_4Bn.js";
4
4
  import "./normalize-LMXvL6w0.js";
5
5
  import { listResolvedDirectoryGroupEntriesFromMapKeys, listResolvedDirectoryUserEntriesFromAllowFrom } from "openclaw/plugin-sdk/directory-config-runtime";
@@ -1,2 +1,2 @@
1
- import { n as listWhatsAppDirectoryGroupsFromConfig, r as listWhatsAppDirectoryPeersFromConfig } from "./directory-config-BfyInQuH.js";
1
+ import { n as listWhatsAppDirectoryGroupsFromConfig, r as listWhatsAppDirectoryPeersFromConfig } from "./directory-config-QH8Oe8bc.js";
2
2
  export { listWhatsAppDirectoryGroupsFromConfig, listWhatsAppDirectoryPeersFromConfig };
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-CiIaOW0V.js";
2
- import { a as resolveWhatsAppAccount } from "./accounts-Dn7MUPTZ.js";
2
+ import { a as resolveWhatsAppAccount } from "./accounts-CJNZl-3e.js";
3
3
  import { b as restoreCredsFromBackupIfNeeded } from "./auth-store-BLGYDyCH.js";
4
4
  import { a as renderQrTerminal, i as resolveWhatsAppSocketTiming, t as createWaSocket } from "./session-DqDc1usL.js";
5
5
  import { a as closeWaSocketSoon, o as waitForWhatsAppLoginResult } from "./connection-controller-Cq6sY2mA.js";
@@ -1,4 +1,4 @@
1
- import { a as resolveWhatsAppAccount } from "./accounts-Dn7MUPTZ.js";
1
+ import { a as resolveWhatsAppAccount } from "./accounts-CJNZl-3e.js";
2
2
  import { f as readWebAuthExistsForDecision, g as readWebSelfId, n as WHATSAPP_AUTH_UNSTABLE_CODE } from "./auth-store-BLGYDyCH.js";
3
3
  import { i as resolveWhatsAppSocketTiming, t as createWaSocket } from "./session-DqDc1usL.js";
4
4
  import { i as closeWaSocket, o as waitForWhatsAppLoginResult, t as WHATSAPP_LOGGED_OUT_QR_MESSAGE } from "./connection-controller-Cq6sY2mA.js";
@@ -1,7 +1,7 @@
1
1
  //#region extensions/whatsapp/login-qr-runtime.ts
2
2
  let loginQrModulePromise = null;
3
3
  function loadLoginQrModule() {
4
- loginQrModulePromise ??= import("./login-qr-B63JLtJG.js");
4
+ loginQrModulePromise ??= import("./login-qr-CipY7q23.js");
5
5
  return loginQrModulePromise;
6
6
  }
7
7
  async function startWebLoginWithQr(...args) {
@@ -1,15 +1,15 @@
1
- import { a as resolveWhatsAppAccount, s as resolveWhatsAppMediaMaxBytes } from "./accounts-Dn7MUPTZ.js";
1
+ import { a as resolveWhatsAppAccount, s as resolveWhatsAppMediaMaxBytes } from "./accounts-CJNZl-3e.js";
2
2
  import { t as isWhatsAppGroupJid } from "./normalize-target-MB6Z_4Bn.js";
3
- import { t as resolveWhatsAppReactionLevel } from "./reaction-level-2m9sWGCw.js";
4
- import { i as prepareWhatsAppOutboundMedia, o as sendWhatsAppOutboundWithRetry, r as normalizeWhatsAppPayloadTextPreservingIndentation, t as normalizeWhatsAppOutboundPayload } from "./outbound-media-contract-CQnjZqsm.js";
3
+ import { t as resolveWhatsAppReactionLevel } from "./reaction-level-DeO7ktWb.js";
4
+ import { i as prepareWhatsAppOutboundMedia, o as sendWhatsAppOutboundWithRetry, r as normalizeWhatsAppPayloadTextPreservingIndentation, t as normalizeWhatsAppOutboundPayload } from "./outbound-media-contract-ItL7G0Az.js";
5
5
  import { n as getStatusCode, t as formatError } from "./session-errors-KYQIoX8M.js";
6
6
  import { d as markdownToWhatsApp, f as resolveJidToE164, l as isSelfChatMode, n as normalizeE164, t as convertMarkdownTables$1, u as jidToE164 } from "./text-runtime-DyR0XOJ4.js";
7
- import { r as sendReactionWhatsApp } from "./send-Cn2WKdPM.js";
7
+ import { r as sendReactionWhatsApp } from "./send-BtGELs96.js";
8
8
  import { n as cacheInboundMessageMeta, r as lookupInboundMessageMeta, t as buildQuotedMessageOptions } from "./quoted-message-C5vX90mp.js";
9
9
  import { c as logoutWeb, g as readWebSelfId, o as getWebAuthAgeMs, r as WhatsAppAuthUnstableError, v as readWebSelfIdentityForDecision } from "./auth-store-BLGYDyCH.js";
10
10
  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-CVFJuB0Q.js";
11
- import { i as resolveWhatsAppInboundPolicy, n as checkInboundAccessControl, r as resolveWhatsAppCommandAuthorized } from "./access-control-CTFVk322.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-CwheV1Iq.js";
11
+ import { i as resolveWhatsAppInboundPolicy, r as resolveWhatsAppCommandAuthorized, t as checkInboundAccessControl } from "./access-control-Blo69-dW.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-BvUGZEIA.js";
13
13
  import { i as resolveWhatsAppSocketTiming, r as waitForWaConnection, t as createWaSocket } from "./session-DqDc1usL.js";
14
14
  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-Cq6sY2mA.js";
15
15
  import { resolveAccountEntry } from "openclaw/plugin-sdk/account-core";
@@ -1020,6 +1020,17 @@ function createEchoTracker(params) {
1020
1020
  };
1021
1021
  }
1022
1022
  //#endregion
1023
+ //#region extensions/whatsapp/src/auto-reply/monitor/listener-log.ts
1024
+ function formatWhatsAppInboundListeningLog(account) {
1025
+ if (account.groupPolicy === "disabled") return "Listening for WhatsApp inbound messages (DM + groups disabled by groupPolicy).";
1026
+ if (account.groupPolicy === "allowlist" && !account.hasGroupAllowFrom) return "Listening for WhatsApp inbound messages (DM + group inbound blocked by empty groupPolicy allowlist).";
1027
+ const groups = account.groups ?? {};
1028
+ if (Object.keys(groups).length === 0) return `Listening for WhatsApp inbound messages (DM + all groups; ${account.groupPolicy === "allowlist" ? "sender allowlist configured" : "no group allowlist configured"}).`;
1029
+ if (Object.hasOwn(groups, "*")) return "Listening for WhatsApp inbound messages (DM + all groups; wildcard configured).";
1030
+ const explicitGroupCount = Object.keys(groups).length;
1031
+ return `Listening for WhatsApp inbound messages (DM + ${explicitGroupCount} configured ${explicitGroupCount === 1 ? "group" : "groups"}).`;
1032
+ }
1033
+ //#endregion
1023
1034
  //#region extensions/whatsapp/src/group-session-key.ts
1024
1035
  function resolveWhatsAppGroupAccountThreadId(accountId) {
1025
1036
  return `whatsapp-account-${normalizeAccountId$1(accountId)}`;
@@ -1298,7 +1309,7 @@ async function applyGroupGating(params) {
1298
1309
  });
1299
1310
  const conversationGroupPolicy = inboundPolicy.resolveConversationGroupPolicy(params.conversationId);
1300
1311
  if (conversationGroupPolicy.allowlistEnabled && !conversationGroupPolicy.allowed) {
1301
- params.logVerbose(`Skipping group message ${params.conversationId} (not in allowlist)`);
1312
+ params.logVerbose(`Dropping message from unregistered WhatsApp group ${params.conversationId}. Add the group JID to channels.whatsapp.groups, or add "*" there to admit all groups. Sender authorization still applies.`);
1302
1313
  return { shouldProcess: false };
1303
1314
  }
1304
1315
  noteGroupMember(params.groupMemberNames, params.groupHistoryKey, sender.e164 ?? void 0, sender.name ?? void 0);
@@ -3083,13 +3094,40 @@ async function monitorWebChannel(verbose, listenerFactory = attachWebInboxToSock
3083
3094
  error: String(err)
3084
3095
  }, "reconnect drain failed");
3085
3096
  });
3086
- whatsappLog.info("Listening for personal WhatsApp inbound messages.");
3097
+ const periodicDrainInterval = setInterval(() => {
3098
+ drainPendingDeliveries({
3099
+ drainKey: `whatsapp:${normalizedAccountId}`,
3100
+ logLabel: "WhatsApp periodic drain",
3101
+ cfg,
3102
+ log: reconnectLogger,
3103
+ selectEntry: (entry) => ({
3104
+ match: entry.channel === "whatsapp" && normalizeReconnectAccountId(entry.accountId) === normalizedAccountId,
3105
+ bypassBackoff: false
3106
+ })
3107
+ }).catch((err) => {
3108
+ reconnectLogger.warn({
3109
+ connectionId: connection.connectionId,
3110
+ error: String(err)
3111
+ }, "periodic drain failed");
3112
+ });
3113
+ }, 3e4);
3114
+ const inboundPolicy = resolveWhatsAppInboundPolicy({
3115
+ cfg,
3116
+ accountId: account.accountId,
3117
+ selfE164: selfE164 ?? null
3118
+ });
3119
+ whatsappLog.info(formatWhatsAppInboundListeningLog({
3120
+ groups: inboundPolicy.account.groups,
3121
+ groupPolicy: inboundPolicy.groupPolicy,
3122
+ hasGroupAllowFrom: inboundPolicy.groupAllowFrom.length > 0
3123
+ }));
3087
3124
  if (process.stdout.isTTY || process.stderr.isTTY) whatsappLog.raw("Ctrl+C to stop.");
3088
3125
  if (!keepAlive) {
3126
+ clearInterval(periodicDrainInterval);
3089
3127
  await controller.shutdown();
3090
3128
  return;
3091
3129
  }
3092
- const reason = await controller.waitForClose();
3130
+ const reason = await controller.waitForClose().finally(() => clearInterval(periodicDrainInterval));
3093
3131
  if (stopRequested() || sigintStop || reason === "aborted") {
3094
3132
  await controller.shutdown();
3095
3133
  break;
@@ -1,12 +1,12 @@
1
1
  import { t as resolveWhatsAppOutboundTarget } from "./resolve-outbound-target-Ba7sH80H.js";
2
- import { n as normalizeWhatsAppPayloadText } from "./outbound-media-contract-CQnjZqsm.js";
3
- import { t as createWhatsAppOutboundBase } from "./outbound-base-Dfj1SAyO.js";
2
+ import { n as normalizeWhatsAppPayloadText } from "./outbound-media-contract-ItL7G0Az.js";
3
+ import { t as createWhatsAppOutboundBase } from "./outbound-base-ARCS45ql.js";
4
4
  import { shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env";
5
5
  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-Cn2WKdPM.js").then((n) => n.a);
9
+ whatsAppSendModulePromise ??= import("./send-BtGELs96.js").then((n) => n.a);
10
10
  return whatsAppSendModulePromise;
11
11
  }
12
12
  function normalizeOutboundText(text) {
@@ -1,4 +1,4 @@
1
- import { n as normalizeWhatsAppPayloadText, t as normalizeWhatsAppOutboundPayload } from "./outbound-media-contract-CQnjZqsm.js";
1
+ import { n as normalizeWhatsAppPayloadText, t as normalizeWhatsAppOutboundPayload } from "./outbound-media-contract-ItL7G0Az.js";
2
2
  import { p as toWhatsappJid } from "./text-runtime-DyR0XOJ4.js";
3
3
  import { i as lookupInboundMessageMetaForTarget } from "./quoted-message-C5vX90mp.js";
4
4
  import { DEFAULT_ACCOUNT_ID, listCombinedAccountIds, normalizeOptionalAccountId, resolveListedDefaultAccountId } from "openclaw/plugin-sdk/account-core";
@@ -51,8 +51,16 @@ function normalizeWhatsAppOutboundPayload(payload, options) {
51
51
  mediaUrls: mediaUrls.length > 0 ? mediaUrls : void 0
52
52
  };
53
53
  }
54
+ function inferWhatsAppMediaKind(media) {
55
+ if (media.kind === "image" || media.kind === "audio" || media.kind === "video" || media.kind === "document") return media.kind;
56
+ const contentType = normalizeContentType(media.contentType);
57
+ if (contentType.startsWith("image/")) return "image";
58
+ if (contentType.startsWith("audio/")) return "audio";
59
+ if (contentType.startsWith("video/")) return "video";
60
+ return "document";
61
+ }
54
62
  function normalizeWhatsAppLoadedMedia(media, mediaUrl) {
55
- const kind = media.kind === "image" || media.kind === "audio" || media.kind === "video" ? media.kind : "document";
63
+ const kind = inferWhatsAppMediaKind(media);
56
64
  const mimetype = kind === "audio" && isWhatsAppNativeVoiceAudio({
57
65
  contentType: media.contentType,
58
66
  mediaUrl
@@ -1,2 +1,2 @@
1
- import { t as whatsappOutbound } from "./outbound-adapter-pW4J6iz-.js";
1
+ import { t as whatsappOutbound } from "./outbound-adapter-BT7Dkqni.js";
2
2
  export { whatsappOutbound };
@@ -1,4 +1,4 @@
1
- import { t as resolveMergedWhatsAppAccountConfig } from "./account-config-CNQ33oav.js";
1
+ import { t as resolveMergedWhatsAppAccountConfig } from "./account-config-D3OXPtpW.js";
2
2
  import { resolveReactionLevel } from "openclaw/plugin-sdk/status-helpers";
3
3
  //#region extensions/whatsapp/src/reaction-level.ts
4
4
  /** Resolve the effective reaction level and its implications for WhatsApp. */
@@ -1,16 +1,16 @@
1
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-CnXRJ7y1.js";
2
+ import { n as whatsAppActionRuntime, t as handleWhatsAppAction } from "./action-runtime-cZLWNUXF.js";
3
3
  import { n as getStatusCode, t as formatError } from "./session-errors-KYQIoX8M.js";
4
- import { i as sendTypingWhatsApp, n as sendPollWhatsApp, r as sendReactionWhatsApp, t as sendMessageWhatsApp } from "./send-Cn2WKdPM.js";
4
+ import { i as sendTypingWhatsApp, n as sendPollWhatsApp, r as sendReactionWhatsApp, t as sendMessageWhatsApp } from "./send-BtGELs96.js";
5
5
  import { startWebLoginWithQr, waitForWebLogin } from "./login-qr-runtime.js";
6
6
  import { t as createWhatsAppLoginTool } from "./agent-tools-login-DpRxLNRB.js";
7
7
  import { n as setWhatsAppRuntime } from "./runtime-6fZ67abR.js";
8
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-BLGYDyCH.js";
9
9
  import { t as DEFAULT_WEB_MEDIA_BYTES } from "./constants-yKXGCGU9.js";
10
- import { c as extractContactContext, d as extractMediaPlaceholder, p as extractText, u as extractLocationData } from "./send-api-CwheV1Iq.js";
10
+ import { c as extractContactContext, d as extractMediaPlaceholder, p as extractText, u as extractLocationData } from "./send-api-BvUGZEIA.js";
11
11
  import { n as newConnectionId, r as waitForWaConnection, t as createWaSocket } from "./session-DqDc1usL.js";
12
12
  import { n as resolveWebAccountId, t as getActiveWebListener } from "./active-listener-C4ClVut4.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-DSBROC8j.js";
14
- import { t as loginWeb } from "./login-CDwsln_y.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-oXSnOpto.js";
14
+ import { t as loginWeb } from "./login-DJYp3l4Z.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,9 +1,9 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-CiIaOW0V.js";
2
2
  import { r as resolveDefaultWhatsAppAccountId } from "./account-ids-DgtV_RiP.js";
3
- import { a as resolveWhatsAppAccount, s as resolveWhatsAppMediaMaxBytes } from "./accounts-Dn7MUPTZ.js";
3
+ import { a as resolveWhatsAppAccount, s as resolveWhatsAppMediaMaxBytes } from "./accounts-CJNZl-3e.js";
4
4
  import { n as isWhatsAppNewsletterJid } from "./normalize-target-MB6Z_4Bn.js";
5
5
  import { t as getRegisteredWhatsAppConnectionController } from "./connection-controller-registry-D_iIGz5m.js";
6
- import { a as resolveWhatsAppOutboundMediaUrls, i as prepareWhatsAppOutboundMedia, n as normalizeWhatsAppPayloadText, s as resolveWhatsAppDocumentFileName } from "./outbound-media-contract-CQnjZqsm.js";
6
+ import { a as resolveWhatsAppOutboundMediaUrls, i as prepareWhatsAppOutboundMedia, n as normalizeWhatsAppPayloadText, s as resolveWhatsAppDocumentFileName } from "./outbound-media-contract-ItL7G0Az.js";
7
7
  import "./normalize-LMXvL6w0.js";
8
8
  import { d as markdownToWhatsApp, p as toWhatsappJid } from "./text-runtime-DyR0XOJ4.js";
9
9
  import { formatCliCommand } from "openclaw/plugin-sdk/cli-runtime";
@@ -61,8 +61,11 @@ function requireOutboundActiveWebListener(params) {
61
61
  async function sendMessageWhatsApp(to, body, options) {
62
62
  let text = options.preserveLeadingWhitespace ? body : normalizeWhatsAppPayloadText(body);
63
63
  const jid = toWhatsappJid(to);
64
- const primaryMediaUrl = resolveWhatsAppOutboundMediaUrls(options)[0];
65
- if (!text && !primaryMediaUrl) return {
64
+ const mediaUrls = resolveWhatsAppOutboundMediaUrls(options);
65
+ const mediaPayload = options.mediaPayload;
66
+ const primaryMediaUrl = mediaUrls[0] ?? mediaPayload?.fileName;
67
+ const hasMedia = Boolean(mediaPayload || primaryMediaUrl);
68
+ if (!text && !hasMedia) return {
66
69
  messageId: "",
67
70
  toJid: jid
68
71
  };
@@ -97,7 +100,24 @@ async function sendMessageWhatsApp(to, body, options) {
97
100
  let documentFileName;
98
101
  let visibleTextAfterVoice;
99
102
  let forceDocumentDelivery = false;
100
- if (primaryMediaUrl) {
103
+ if (mediaPayload) {
104
+ const media = await prepareWhatsAppOutboundMedia(mediaPayload, primaryMediaUrl);
105
+ const caption = text || void 0;
106
+ mediaBuffer = media.buffer;
107
+ mediaType = media.mimetype;
108
+ forceDocumentDelivery = Boolean(options.forceDocument && supportsForcedDocumentDelivery(media.kind));
109
+ if (media.kind === "audio" && caption) {
110
+ visibleTextAfterVoice = caption;
111
+ text = "";
112
+ } else if (media.kind === "document") {
113
+ text = caption ?? "";
114
+ documentFileName = media.fileName;
115
+ } else text = caption ?? "";
116
+ if (forceDocumentDelivery) documentFileName ??= resolveWhatsAppDocumentFileName({
117
+ fileName: media.fileName,
118
+ mimetype: media.mimetype
119
+ });
120
+ } else if (primaryMediaUrl) {
101
121
  const media = await prepareWhatsAppOutboundMedia(await loadOutboundMediaFromUrl(primaryMediaUrl, {
102
122
  maxBytes: resolveWhatsAppMediaMaxBytes(account),
103
123
  optimizeImages: options.forceDocument ? false : void 0,
@@ -121,10 +141,10 @@ async function sendMessageWhatsApp(to, body, options) {
121
141
  mimetype: media.mimetype
122
142
  });
123
143
  }
124
- outboundLog.info(`Sending message -> ${redactedJid}${primaryMediaUrl ? " (media)" : ""}`);
144
+ outboundLog.info(`Sending message -> ${redactedJid}${hasMedia ? " (media)" : ""}`);
125
145
  logger.info({
126
146
  jid: redactedJid,
127
- hasMedia: Boolean(primaryMediaUrl)
147
+ hasMedia
128
148
  }, "sending message");
129
149
  if (!isWhatsAppNewsletterJid(jid)) await active.sendComposingTo(to);
130
150
  const accountId = Boolean(options.accountId?.trim()) ? resolvedAccountId : void 0;
@@ -140,7 +160,7 @@ async function sendMessageWhatsApp(to, body, options) {
140
160
  else await active.sendMessage(to, visibleTextAfterVoice, void 0, void 0);
141
161
  const messageId = result?.messageId ?? "unknown";
142
162
  const durationMs = Date.now() - startedAt;
143
- outboundLog.info(`Sent message ${messageId} -> ${redactedJid}${primaryMediaUrl ? " (media)" : ""} (${durationMs}ms)`);
163
+ outboundLog.info(`Sent message ${messageId} -> ${redactedJid}${hasMedia ? " (media)" : ""} (${durationMs}ms)`);
144
164
  logger.info({
145
165
  jid: redactedJid,
146
166
  messageId
@@ -153,7 +173,7 @@ async function sendMessageWhatsApp(to, body, options) {
153
173
  logger.error({
154
174
  err: String(err),
155
175
  to: redactedTo,
156
- hasMedia: Boolean(primaryMediaUrl)
176
+ hasMedia
157
177
  }, "failed to send via web session");
158
178
  throw err;
159
179
  }
@@ -1,5 +1,5 @@
1
1
  import { n as isWhatsAppNewsletterJid } from "./normalize-target-MB6Z_4Bn.js";
2
- import { s as resolveWhatsAppDocumentFileName } from "./outbound-media-contract-CQnjZqsm.js";
2
+ import { s as resolveWhatsAppDocumentFileName } from "./outbound-media-contract-ItL7G0Az.js";
3
3
  import "./normalize-LMXvL6w0.js";
4
4
  import { m as toWhatsappJidWithLid, p as toWhatsappJid, u as jidToE164 } from "./text-runtime-DyR0XOJ4.js";
5
5
  import { t as buildQuotedMessageOptions } from "./quoted-message-C5vX90mp.js";
@@ -1,5 +1,5 @@
1
1
  import { r as resolveDefaultWhatsAppAccountId, t as listAccountIds } from "./account-ids-DgtV_RiP.js";
2
- import { a as resolveWhatsAppAccount, n as hasAnyWhatsAppAuth } from "./accounts-Dn7MUPTZ.js";
2
+ import { a as resolveWhatsAppAccount, n as hasAnyWhatsAppAuth } from "./accounts-CJNZl-3e.js";
3
3
  import { a as normalizeWhatsAppAllowFromEntries } from "./normalize-target-MB6Z_4Bn.js";
4
4
  import { t as WhatsAppChannelConfigSchema } from "./config-schema-Dmo66Ubb.js";
5
5
  import { n as whatsappDoctor } from "./doctor-A9tXm9Om.js";
@@ -125,10 +125,10 @@ function resolveWhatsAppConfigPath(params) {
125
125
  return `${resolveWhatsAppGroupScopeBasePath(params)}.${params.field}`;
126
126
  }
127
127
  async function loadWhatsAppChannelRuntime() {
128
- return await import("./channel.runtime-Bahb-X2a.js");
128
+ return await import("./channel.runtime-n14SNsjm.js");
129
129
  }
130
130
  async function loadWhatsAppSetupSurface() {
131
- return await import("./setup-surface-Dy9RdlqN.js");
131
+ return await import("./setup-surface-Bq3gnUCD.js");
132
132
  }
133
133
  const whatsappSetupWizardProxy = createWhatsAppSetupWizardProxy(async () => (await loadWhatsAppSetupSurface()).whatsappSetupWizard);
134
134
  const whatsappConfigAdapter = createScopedChannelConfigAdapter({
@@ -1,7 +1,7 @@
1
1
  import { r as resolveDefaultWhatsAppAccountId } from "./account-ids-DgtV_RiP.js";
2
- import { a as resolveWhatsAppAccount, o as resolveWhatsAppAuthDir } from "./accounts-Dn7MUPTZ.js";
2
+ import { a as resolveWhatsAppAccount, o as resolveWhatsAppAuthDir } from "./accounts-CJNZl-3e.js";
3
3
  import { a as normalizeWhatsAppAllowFromEntries, o as normalizeWhatsAppAllowFromEntry } from "./normalize-target-MB6Z_4Bn.js";
4
- import { t as whatsappSetupAdapter } from "./setup-core-Dm2jMZHy.js";
4
+ import { t as whatsappSetupAdapter } from "./setup-core-P6dnz4Ur.js";
5
5
  import path from "node:path";
6
6
  import { DEFAULT_ACCOUNT_ID, createSetupTranslator, pathExists, splitSetupEntries } from "openclaw/plugin-sdk/setup";
7
7
  import { formatCliCommand, formatDocsLink } from "openclaw/plugin-sdk/setup-tools";
@@ -280,7 +280,7 @@ async function finalizeWhatsAppSetup(params) {
280
280
  message: linked ? t("wizard.whatsapp.relinkPrompt") : t("wizard.whatsapp.linkNowPrompt"),
281
281
  initialValue: !linked
282
282
  })) try {
283
- const { loginWeb } = await import("./login-CDwsln_y.js").then((n) => n.n);
283
+ const { loginWeb } = await import("./login-DJYp3l4Z.js").then((n) => n.n);
284
284
  await loginWeb(false, void 0, params.runtime, accountId);
285
285
  } catch (error) {
286
286
  params.runtime.error(`WhatsApp login failed: ${String(error)}`);
@@ -1,2 +1,2 @@
1
- import { t as whatsappSetupPlugin } from "./channel.setup-BLFtofME.js";
1
+ import { t as whatsappSetupPlugin } from "./channel.setup-BiuhxbjG.js";
2
2
  export { whatsappSetupPlugin };
@@ -1,5 +1,5 @@
1
1
  import { t as listAccountIds } from "./account-ids-DgtV_RiP.js";
2
- import { o as resolveWhatsAppAuthDir } from "./accounts-Dn7MUPTZ.js";
2
+ import { o as resolveWhatsAppAuthDir } from "./accounts-CJNZl-3e.js";
3
3
  import { a as formatWhatsAppWebAuthStatusState, h as readWebAuthState } from "./auth-store-BLGYDyCH.js";
4
4
  import { DEFAULT_ACCOUNT_ID, createSetupTranslator, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup";
5
5
  //#region extensions/whatsapp/src/setup-surface.ts
@@ -36,7 +36,7 @@ const whatsappSetupWizard = {
36
36
  },
37
37
  resolveShouldPromptAccountIds: ({ shouldPromptAccountIds }) => shouldPromptAccountIds,
38
38
  credentials: [],
39
- finalize: async (params) => await (await import("./setup-finalize-B16VRsDw.js")).finalizeWhatsAppSetup(params),
39
+ finalize: async (params) => await (await import("./setup-finalize-DYm-2hSc.js")).finalizeWhatsAppSetup(params),
40
40
  disable: (cfg) => setSetupChannelEnabled(cfg, channel, false),
41
41
  onAccountRecorded: (accountId, options) => {
42
42
  options?.onAccountId?.(channel, accountId);
package/dist/test-api.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import { t as resolveWhatsAppRuntimeGroupPolicy } from "./runtime-group-policy-BH_U23qp.js";
2
- import { t as whatsappOutbound } from "./outbound-adapter-pW4J6iz-.js";
2
+ import { t as whatsappOutbound } from "./outbound-adapter-BT7Dkqni.js";
3
3
  export { resolveWhatsAppRuntimeGroupPolicy, whatsappOutbound };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/whatsapp",
3
- "version": "2026.5.18-beta.1",
3
+ "version": "2026.5.19-alpha.1",
4
4
  "description": "OpenClaw WhatsApp channel plugin",
5
5
  "repository": {
6
6
  "type": "git",
@@ -19,7 +19,7 @@
19
19
  "openclaw": "workspace:*"
20
20
  },
21
21
  "peerDependencies": {
22
- "openclaw": ">=2026.5.18-beta.1"
22
+ "openclaw": ">=2026.5.19-alpha.1"
23
23
  },
24
24
  "peerDependenciesMeta": {
25
25
  "openclaw": {
@@ -62,10 +62,10 @@
62
62
  "minHostVersion": ">=2026.4.25"
63
63
  },
64
64
  "compat": {
65
- "pluginApi": ">=2026.5.18-beta.1"
65
+ "pluginApi": ">=2026.5.19-alpha.1"
66
66
  },
67
67
  "build": {
68
- "openclawVersion": "2026.5.18-beta.1"
68
+ "openclawVersion": "2026.5.19-alpha.1"
69
69
  },
70
70
  "release": {
71
71
  "publishToClawHub": true,
@@ -1,42 +0,0 @@
1
- import { c as normalizeWhatsAppTarget, t as isWhatsAppGroupJid } from "./normalize-target-MB6Z_4Bn.js";
2
- import { t as handleWhatsAppAction } from "./action-runtime-CnXRJ7y1.js";
3
- import "./normalize-LMXvL6w0.js";
4
- import { readStringOrNumberParam, readStringParam as readStringParam$1, resolveReactionMessageId } from "openclaw/plugin-sdk/channel-actions";
5
- //#region extensions/whatsapp/src/channel-react-action.ts
6
- const WHATSAPP_CHANNEL = "whatsapp";
7
- async function handleWhatsAppReactAction(params) {
8
- if (params.action !== "react") throw new Error(`Action ${params.action} is not supported for provider ${WHATSAPP_CHANNEL}.`);
9
- const isWhatsAppSource = params.toolContext?.currentChannelProvider === WHATSAPP_CHANNEL;
10
- const explicitTarget = readStringParam$1(params.params, "chatJid") ?? readStringParam$1(params.params, "to");
11
- const normalizedTarget = explicitTarget ? normalizeWhatsAppTarget(explicitTarget) : null;
12
- const normalizedCurrent = isWhatsAppSource && params.toolContext?.currentChannelId ? normalizeWhatsAppTarget(params.toolContext.currentChannelId) : null;
13
- const isCrossChat = normalizedTarget != null && (normalizedCurrent == null || normalizedTarget !== normalizedCurrent);
14
- const scopedContext = !isWhatsAppSource || isCrossChat || !params.toolContext ? void 0 : {
15
- currentChannelId: params.toolContext.currentChannelId ?? void 0,
16
- currentChannelProvider: params.toolContext.currentChannelProvider ?? void 0,
17
- currentMessageId: params.toolContext.currentMessageId ?? void 0
18
- };
19
- const messageIdRaw = resolveReactionMessageId({
20
- args: params.params,
21
- toolContext: scopedContext
22
- });
23
- if (messageIdRaw == null) readStringParam$1(params.params, "messageId", { required: true });
24
- const messageId = String(messageIdRaw);
25
- const explicitMessageId = readStringOrNumberParam(params.params, "messageId");
26
- const emoji = readStringParam$1(params.params, "emoji", { allowEmpty: true });
27
- const remove = typeof params.params.remove === "boolean" ? params.params.remove : void 0;
28
- const explicitParticipant = readStringParam$1(params.params, "participant");
29
- const inferredParticipant = explicitParticipant || explicitMessageId != null || !isWhatsAppSource || isCrossChat || !isWhatsAppGroupJid(explicitTarget ?? params.toolContext?.currentChannelId ?? "") ? void 0 : typeof params.requesterSenderId === "string" && params.requesterSenderId.trim().length > 0 ? params.requesterSenderId.trim() : void 0;
30
- return await handleWhatsAppAction({
31
- action: "react",
32
- chatJid: readStringParam$1(params.params, "chatJid") ?? readStringParam$1(params.params, "to", { required: true }),
33
- messageId,
34
- emoji,
35
- remove,
36
- participant: explicitParticipant ?? inferredParticipant,
37
- accountId: params.accountId ?? void 0,
38
- fromMe: typeof params.params.fromMe === "boolean" ? params.params.fromMe : void 0
39
- }, params.cfg);
40
- }
41
- //#endregion
42
- export { handleWhatsAppReactAction };