@openclaw/whatsapp 2026.10.1 → 2026.10.5-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/.setup/{action-runtime-CE3zGstN.mjs → action-runtime-DUSkWTiZ.mjs} +2 -2
  2. package/dist/.setup/{agent-tools-login-B7VEvJO7.mjs → agent-tools-login-CB7OQbli.mjs} +5 -15
  3. package/dist/.setup/{approval-handler.runtime-CKposl6w.mjs → approval-handler.runtime-BEaAKSoU.mjs} +3 -3
  4. package/dist/.setup/{approval-reactions-CD6CDF9k.mjs → approval-reactions-CWkZ_ham.mjs} +7 -16
  5. package/dist/.setup/audio-preflight.runtime-Dg8oZgre.mjs +2 -0
  6. package/dist/.setup/{auth-store-D2rN-hP5.mjs → auth-store-DOBi5BPe.mjs} +10 -11
  7. package/dist/.setup/{channel-DNgKHMCz.mjs → channel-DcHw3Up2.mjs} +136 -135
  8. package/dist/.setup/{channel-react-action-BaBV9X6M.mjs → channel-react-action-C5E8_iDk.mjs} +3 -3
  9. package/dist/.setup/{channel.runtime-BniF8Swm.mjs → channel.runtime-DTj-wkEP.mjs} +5 -11
  10. package/dist/.setup/channel.setup-BJWEyQlF.mjs +5 -0
  11. package/dist/.setup/{connection-controller-COkcq48K.mjs → connection-controller-CejM7bhn.mjs} +50 -84
  12. package/dist/.setup/{directory-config-RYQomHyB.mjs → directory-config-DPLTUAqy.mjs} +22 -29
  13. package/dist/.setup/{group-session-key-BV8Le9r8.mjs → group-session-key-BbTPosdy.mjs} +12 -18
  14. package/dist/.setup/{login-CV_4V021.mjs → login-DUx5JYuW.mjs} +3 -3
  15. package/dist/.setup/{login-qr-DFhGc5yH.mjs → login-qr-BAWbPonj.mjs} +24 -45
  16. package/dist/.setup/{monitor-B5DS4PDV.mjs → monitor-CmXEQad9.mjs} +218 -367
  17. package/dist/.setup/{normalize-target-BGra1ZnM.mjs → normalize-target-D67Kc3g6.mjs} +5 -8
  18. package/dist/.setup/{question-reactions-LMeijbaq.mjs → question-reactions-DywNaX8m.mjs} +3 -10
  19. package/dist/.setup/reaction-target-CSPO7gtu.mjs +11 -0
  20. package/dist/.setup/{resolve-outbound-target-CzyNKmrl.mjs → resolve-outbound-target-qikGL4r0.mjs} +3 -4
  21. package/dist/.setup/{send-CGUsUdoX.mjs → send-CLBfAzd6.mjs} +34 -42
  22. package/dist/.setup/{send-api-B03VDwZ1.mjs → send-api-COzRvqXx.mjs} +28 -60
  23. package/dist/.setup/{setup-finalize-GtBmrO8p.mjs → setup-finalize-DSiP_-wa.mjs} +53 -69
  24. package/dist/.setup/setup-plugin-api-8WdNCjRW.mjs +3 -0
  25. package/dist/.setup/{setup-surface-BuA39k6K.mjs → setup-surface-C_flQyHy.mjs} +2 -2
  26. package/dist/.setup/{shared-CP_zs2U7.mjs → shared-SqcOkt51.mjs} +4 -4
  27. package/dist/.setup/{socket-close-DU7eerAa.mjs → socket-close-C9OU9mVN.mjs} +67 -86
  28. package/dist/.setup/{targets-runtime-Dls-Xh4F.mjs → targets-runtime-D5ryyPxh.mjs} +16 -25
  29. package/dist/action-runtime-api.js +1 -1
  30. package/dist/action-runtime.runtime.js +1 -1
  31. package/dist/agent-tools-api.js +4 -8
  32. package/dist/api.js +13 -15
  33. package/dist/channel-plugin-api.js +1 -1
  34. package/dist/contract-api.js +1 -1
  35. package/dist/directory-contract-api.js +1 -1
  36. package/dist/doctor-contract-api.js +12 -32
  37. package/dist/light-runtime-api.js +2 -2
  38. package/dist/login-qr-runtime.js +2 -4
  39. package/dist/runtime-api.js +8 -8
  40. package/dist/setup-entry.js +1 -1
  41. package/dist/setup-plugin-api.js +1 -1
  42. package/node_modules/baileys/lib/Utils/messages-media.js +7 -11
  43. package/node_modules/baileys/node_modules/ws/lib/websocket.js +17 -3
  44. package/node_modules/baileys/node_modules/ws/package.json +1 -1
  45. package/package.json +4 -4
  46. package/dist/.setup/audio-preflight.runtime-C_glQhZY.mjs +0 -7
  47. package/dist/.setup/channel.setup-CsS_NAKQ.mjs +0 -5
  48. package/dist/.setup/setup-plugin-api-Bsp7jI-r.mjs +0 -3
@@ -1,4 +1,4 @@
1
- import { normalizeLowercaseStringOrEmpty, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
1
+ import { uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
2
2
  import { normalizeE164 } from "openclaw/plugin-sdk/account-resolution";
3
3
  import { formatNormalizedAllowFromEntries } from "openclaw/plugin-sdk/allow-from";
4
4
  //#region extensions/whatsapp/src/normalize-target.ts
@@ -15,15 +15,12 @@ function stripWhatsAppTargetPrefixes(value) {
15
15
  if (candidate === before) return candidate;
16
16
  }
17
17
  }
18
- function normalizeWhatsAppGroupJid(value) {
19
- const candidate = stripWhatsAppTargetPrefixes(value).replace(/^group:/i, "").trim();
20
- if (!normalizeLowercaseStringOrEmpty(candidate).endsWith("@g.us")) return null;
21
- const localPart = candidate.slice(0, candidate.length - 5);
22
- if (!localPart || localPart.includes("@")) return null;
23
- return /^[0-9]+(-[0-9]+)*$/.test(localPart) ? `${localPart}@g.us` : null;
18
+ function normalizeWhatsAppGroupJid(candidate) {
19
+ const match = /^(\d+(?:-\d+)*)@g\.us$/i.exec(candidate.replace(/^group:/i, "").trim());
20
+ return match ? `${match[1]}@g.us` : null;
24
21
  }
25
22
  function isWhatsAppGroupJid(value) {
26
- return normalizeWhatsAppGroupJid(value) !== null;
23
+ return normalizeWhatsAppGroupJid(stripWhatsAppTargetPrefixes(value)) !== null;
27
24
  }
28
25
  function isWhatsAppNewsletterJid(value) {
29
26
  const candidate = stripWhatsAppTargetPrefixes(value);
@@ -1,6 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-BBjsoOtd.mjs";
2
2
  import { a as resolveWhatsAppAccount } from "./accounts-F0vHuze2.mjs";
3
- import { d as listWhatsAppDeliveredMessageIdentities } from "./send-CGUsUdoX.mjs";
3
+ import { u as listWhatsAppDeliveredMessageIdentities } from "./send-CLBfAzd6.mjs";
4
+ import { t as buildWhatsAppReactionTargetKey } from "./reaction-target-CSPO7gtu.mjs";
4
5
  import { normalizeUniqueTrimmedStringList } from "openclaw/plugin-sdk/string-coerce-runtime";
5
6
  import { createQuestionReactionTargetStore, questionGatewayRuntime } from "openclaw/plugin-sdk/question-gateway-runtime";
6
7
  //#region extensions/whatsapp/src/question-reactions.ts
@@ -8,18 +9,10 @@ var question_reactions_exports = /* @__PURE__ */ __exportAll({
8
9
  maybeResolveWhatsAppQuestionReaction: () => maybeResolveWhatsAppQuestionReaction,
9
10
  registerWhatsAppQuestionReactionTargetForDeliveredPayload: () => registerWhatsAppQuestionReactionTargetForDeliveredPayload
10
11
  });
11
- function buildKey(identity) {
12
- const parts = [
13
- identity.accountId,
14
- identity.remoteJid,
15
- identity.messageId
16
- ].map((part) => part.trim());
17
- return parts.every(Boolean) ? parts.join(":") : void 0;
18
- }
19
12
  const questionReactionTargets = createQuestionReactionTargetStore({
20
13
  channel: "whatsapp",
21
14
  channelDisplayName: "WhatsApp",
22
- buildKey,
15
+ buildKey: buildWhatsAppReactionTargetKey,
23
16
  registerChannelDelivery: questionGatewayRuntime.registerChannelDelivery,
24
17
  resolveReaction: questionGatewayRuntime.resolveReaction
25
18
  });
@@ -0,0 +1,11 @@
1
+ //#region extensions/whatsapp/src/reaction-target.ts
2
+ function buildWhatsAppReactionTargetKey(identity) {
3
+ const parts = [
4
+ identity.accountId,
5
+ identity.remoteJid,
6
+ identity.messageId
7
+ ].map((part) => part.trim());
8
+ return parts.every(Boolean) ? parts.join(":") : void 0;
9
+ }
10
+ //#endregion
11
+ export { buildWhatsAppReactionTargetKey as t };
@@ -1,15 +1,14 @@
1
- import { c as normalizeWhatsAppTarget, n as isWhatsAppNewsletterJid, t as isWhatsAppGroupJid } from "./normalize-target-BGra1ZnM.mjs";
1
+ import { c as normalizeWhatsAppTarget } from "./normalize-target-D67Kc3g6.mjs";
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
5
5
  function resolveWhatsAppOutboundTarget(params) {
6
- const trimmed = params.to?.trim() ?? "";
7
- const normalizedTo = normalizeWhatsAppTarget(trimmed);
6
+ const normalizedTo = normalizeWhatsAppTarget(params.to ?? "");
8
7
  if (!normalizedTo) return {
9
8
  ok: false,
10
9
  error: missingTargetError("WhatsApp", "<E.164|group JID|newsletter JID>")
11
10
  };
12
- if (isWhatsAppGroupJid(normalizedTo) || isWhatsAppNewsletterJid(normalizedTo)) return {
11
+ if (normalizedTo.endsWith("@g.us") || normalizedTo.endsWith("@newsletter")) return {
13
12
  ok: true,
14
13
  to: normalizedTo
15
14
  };
@@ -1,8 +1,8 @@
1
1
  import { a as resolveWhatsAppAccount, c as resolveMergedWhatsAppAccountConfig, s as resolveWhatsAppMediaMaxBytes } from "./accounts-F0vHuze2.mjs";
2
2
  import { r as resolveDefaultWhatsAppAccountId } from "./account-ids-CB5SOWjc.mjs";
3
- import { n as isWhatsAppNewsletterJid } from "./normalize-target-BGra1ZnM.mjs";
3
+ import { n as isWhatsAppNewsletterJid } from "./normalize-target-D67Kc3g6.mjs";
4
4
  import { r as getWhatsAppConnectionController } from "./connection-controller-runtime-context-hgLJoRc8.mjs";
5
- import { a as markdownToWhatsAppChunks, c as toWhatsappJid } from "./targets-runtime-Dls-Xh4F.mjs";
5
+ import { a as markdownToWhatsAppChunks, c as toWhatsappJid } from "./targets-runtime-D5ryyPxh.mjs";
6
6
  import path from "node:path";
7
7
  import { normalizeStringEntries, normalizeUniqueStringEntries, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
8
8
  import { resolveReactionLevel } from "openclaw/plugin-sdk/status-helpers";
@@ -210,26 +210,34 @@ function rememberWhatsAppAcceptedSend(params) {
210
210
  }
211
211
  return accepted;
212
212
  }
213
- /** Nested owners already attempted activity accounting before exposing accepted delivery. */
214
- function rememberWhatsAppPartialSend(params) {
215
- if (!isChannelPartialDeliveryError(params.error)) return false;
216
- const delivery = params.error.deliveryResult;
217
- const messageIds = uniqueStrings([...delivery.receipt ? listMessageReceiptPlatformIds(delivery.receipt) : [], ...normalizeStringEntries(delivery.messageIds ?? [])]).filter((messageId) => messageId !== "unknown");
218
- const existingIds = new Set(params.results.flatMap(listWhatsAppSendResultMessageIds));
219
- const acceptedIds = messageIds.filter((messageId) => !existingIds.has(messageId));
213
+ function appendUnrecordedPartialReceipt(params) {
214
+ const receipt = params.delivery?.receipt;
215
+ const receiptIds = receipt ? listMessageReceiptPlatformIds(receipt) : [];
216
+ const acceptedIds = uniqueStrings([...receiptIds, ...normalizeStringEntries(params.delivery?.messageIds ?? [])]).filter((id) => id !== "unknown" && !params.recordedIds.has(id));
220
217
  const messageId = acceptedIds[0];
221
- if (!messageId) return false;
222
- const receiptSources = [];
223
- if (delivery.receipt) receiptSources.push({
218
+ if (receipt && messageId) params.sources.push({
224
219
  channel: "whatsapp",
225
220
  messageId,
226
- receipt: delivery.receipt
221
+ receipt
227
222
  });
228
- const receiptIds = new Set(delivery.receipt ? listMessageReceiptPlatformIds(delivery.receipt) : []);
229
- for (const acceptedId of acceptedIds) if (!receiptIds.has(acceptedId)) receiptSources.push({
223
+ const includedIds = new Set(receiptIds);
224
+ for (const acceptedId of acceptedIds) if (!includedIds.has(acceptedId)) params.sources.push({
230
225
  channel: "whatsapp",
231
226
  messageId: acceptedId
232
227
  });
228
+ return acceptedIds;
229
+ }
230
+ /** Nested owners already attempted activity accounting before exposing accepted delivery. */
231
+ function rememberWhatsAppPartialSend(params) {
232
+ if (!isChannelPartialDeliveryError(params.error)) return false;
233
+ const receiptSources = [];
234
+ const acceptedIds = appendUnrecordedPartialReceipt({
235
+ delivery: params.error.deliveryResult,
236
+ recordedIds: new Set(params.results.flatMap(listWhatsAppSendResultMessageIds)),
237
+ sources: receiptSources
238
+ });
239
+ const messageId = acceptedIds[0];
240
+ if (!messageId) return false;
233
241
  const receipt = createMessageReceiptFromOutboundResults({
234
242
  kind: resolveWhatsAppReceiptKind(params.kind),
235
243
  results: receiptSources
@@ -260,19 +268,10 @@ function mergeWhatsAppAcceptedSendError(params) {
260
268
  });
261
269
  for (const messageId of resultIds) recordedIds.add(messageId);
262
270
  }
263
- const unrecordedNestedIds = uniqueStrings([...nested?.receipt ? listMessageReceiptPlatformIds(nested.receipt) : [], ...normalizeStringEntries(nested?.messageIds ?? [])]).filter((messageId) => messageId !== "unknown").filter((messageId) => !recordedIds.has(messageId));
264
- const nestedMessageId = unrecordedNestedIds[0];
265
- if (nested?.receipt && nestedMessageId) {
266
- receiptSources.push({
267
- channel: "whatsapp",
268
- messageId: nestedMessageId,
269
- receipt: nested.receipt
270
- });
271
- for (const messageId of listMessageReceiptPlatformIds(nested.receipt)) recordedIds.add(messageId);
272
- }
273
- for (const messageId of unrecordedNestedIds) if (!recordedIds.has(messageId)) receiptSources.push({
274
- channel: "whatsapp",
275
- messageId
271
+ appendUnrecordedPartialReceipt({
272
+ delivery: nested,
273
+ recordedIds,
274
+ sources: receiptSources
276
275
  });
277
276
  const receipt = enrichWhatsAppDeliveryReceipt({
278
277
  receipt: createMessageReceiptFromOutboundResults({
@@ -357,35 +356,28 @@ function inferWhatsAppMediaKind(media, resolvedContentType) {
357
356
  const inferredKind = mediaKindFromMime(normalizeMimeType(resolvedContentType));
358
357
  return !inferredKind || inferredKind === "sticker" || inferredKind === "unknown" ? "document" : inferredKind;
359
358
  }
360
- function normalizeWhatsAppLoadedMedia(media, mediaUrl) {
359
+ async function prepareWhatsAppOutboundMedia(media, mediaUrl) {
361
360
  const filenameMimeType = mimeTypeFromFilePath(media.fileName);
362
361
  const normalizedContentType = normalizeMimeType(media.contentType);
363
362
  const resolvedContentType = !normalizedContentType || normalizedContentType === "application/octet-stream" ? filenameMimeType ?? normalizedContentType : normalizedContentType;
364
363
  const kind = inferWhatsAppMediaKind(media, resolvedContentType);
365
- const mimetype = kind === "audio" && isWhatsAppNativeVoiceAudio({
364
+ const nativeVoice = kind === "audio" && isWhatsAppNativeVoiceAudio({
366
365
  contentType: media.contentType,
367
366
  fileName: media.fileName,
368
367
  mediaUrl
369
- }) ? WHATSAPP_VOICE_MIMETYPE : resolvedContentType ?? "application/octet-stream";
368
+ });
369
+ const mimetype = nativeVoice ? WHATSAPP_VOICE_MIMETYPE : resolvedContentType ?? "application/octet-stream";
370
370
  const fileName = kind === "document" ? resolveWhatsAppDocumentFileName({
371
371
  fileName: media.fileName ?? deriveWhatsAppDocumentFileName(mediaUrl),
372
372
  mimetype
373
373
  }) : media.fileName;
374
- return {
374
+ const normalized = {
375
375
  buffer: media.buffer,
376
376
  kind,
377
377
  mimetype,
378
378
  ...fileName ? { fileName } : {}
379
379
  };
380
- }
381
- async function prepareWhatsAppOutboundMedia(media, mediaUrl) {
382
- const normalized = normalizeWhatsAppLoadedMedia(media, mediaUrl);
383
- if (normalized.kind !== "audio") return normalized;
384
- if (isWhatsAppNativeVoiceAudio({
385
- contentType: media.contentType,
386
- fileName: media.fileName,
387
- mediaUrl
388
- })) return normalized;
380
+ if (kind !== "audio" || nativeVoice) return normalized;
389
381
  return {
390
382
  buffer: await transcodeAudioBufferToOpus({
391
383
  audioBuffer: media.buffer,
@@ -709,4 +701,4 @@ async function sendPollWhatsApp(to, poll, options) {
709
701
  }
710
702
  }
711
703
  //#endregion
712
- export { withWhatsAppLogicalDeliveryActivity as _, sendWhatsAppUploadFile as a, normalizeWhatsAppPayloadTextPreservingIndentation as c, listWhatsAppDeliveredMessageIdentities as d, listWhatsAppSendResultMessageIds as f, rememberWhatsAppPartialSend as g, rememberWhatsAppAcceptedSend as h, sendTypingWhatsApp as i, prepareWhatsAppOutboundMedia as l, normalizeWhatsAppSendResult as m, sendPollWhatsApp as n, normalizeWhatsAppOutboundPayload as o, mergeWhatsAppAcceptedSendError as p, sendReactionWhatsApp as r, normalizeWhatsAppPayloadText as s, sendMessageWhatsApp as t, combineWhatsAppSendResults as u, resolveWhatsAppDocumentFileName as v, resolveWhatsAppReactionLevel as y };
704
+ export { resolveWhatsAppDocumentFileName as _, sendWhatsAppUploadFile as a, prepareWhatsAppOutboundMedia as c, listWhatsAppSendResultMessageIds as d, mergeWhatsAppAcceptedSendError as f, withWhatsAppLogicalDeliveryActivity as g, rememberWhatsAppPartialSend as h, sendTypingWhatsApp as i, combineWhatsAppSendResults as l, rememberWhatsAppAcceptedSend as m, sendPollWhatsApp as n, normalizeWhatsAppOutboundPayload as o, normalizeWhatsAppSendResult as p, sendReactionWhatsApp as r, normalizeWhatsAppPayloadTextPreservingIndentation as s, sendMessageWhatsApp as t, listWhatsAppDeliveredMessageIdentities as u, resolveWhatsAppReactionLevel as v };
@@ -1,9 +1,9 @@
1
- import { n as isWhatsAppNewsletterJid } from "./normalize-target-BGra1ZnM.mjs";
2
- import { h as rememberWhatsAppAcceptedSend, m as normalizeWhatsAppSendResult, p as mergeWhatsAppAcceptedSendError, u as combineWhatsAppSendResults, v as resolveWhatsAppDocumentFileName } from "./send-CGUsUdoX.mjs";
3
- import { c as toWhatsappJid, l as toWhatsappJidWithLid, r as jidToE164 } from "./targets-runtime-Dls-Xh4F.mjs";
4
- import { r as buildQuotedMessageOptions } from "./group-session-key-BV8Le9r8.mjs";
5
- import { O as resolveComparableIdentity } from "./auth-store-D2rN-hP5.mjs";
6
- import { isRecord, normalizeLowercaseStringOrEmpty, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
1
+ import { n as isWhatsAppNewsletterJid } from "./normalize-target-D67Kc3g6.mjs";
2
+ import { _ as resolveWhatsAppDocumentFileName, f as mergeWhatsAppAcceptedSendError, l as combineWhatsAppSendResults, m as rememberWhatsAppAcceptedSend, p as normalizeWhatsAppSendResult } from "./send-CLBfAzd6.mjs";
3
+ import { c as toWhatsappJid, l as toWhatsappJidWithLid, r as jidToE164 } from "./targets-runtime-D5ryyPxh.mjs";
4
+ import { r as buildQuotedMessageOptions } from "./group-session-key-BbTPosdy.mjs";
5
+ import { O as resolveComparableIdentity } from "./auth-store-DOBi5BPe.mjs";
6
+ import { isRecord, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
7
7
  import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
8
8
  import { formatLocationText } from "openclaw/plugin-sdk/channel-inbound";
9
9
  import { getImageMetadata, resizeToJpeg } from "openclaw/plugin-sdk/media-runtime";
@@ -64,10 +64,7 @@ function normalizeVcardName(value) {
64
64
  return value.replace(/;/g, " ").replace(/\s+/g, " ").trim();
65
65
  }
66
66
  function normalizeVcardPhone(value) {
67
- const trimmed = value.trim();
68
- if (!trimmed) return "";
69
- if (normalizeLowercaseStringOrEmpty(trimmed).startsWith("tel:")) return trimmed.slice(4).trim();
70
- return trimmed;
67
+ return value.toLowerCase().startsWith("tel:") ? value.slice(4).trim() : value;
71
68
  }
72
69
  //#endregion
73
70
  //#region extensions/whatsapp/src/inbound/media-mimetype.ts
@@ -233,17 +230,12 @@ function extractContactContext(source) {
233
230
  const message = unwrapMessage(source);
234
231
  if (!message) return;
235
232
  const contact = message.contactMessage ?? void 0;
236
- if (contact) return {
237
- kind: "contact",
238
- total: 1,
239
- contacts: [describeContact(contact)]
240
- };
241
- const contactsArray = message.contactsArrayMessage?.contacts ?? void 0;
242
- if (!contactsArray || contactsArray.length === 0) return;
233
+ const contacts = contact ? [contact] : message.contactsArrayMessage?.contacts;
234
+ if (!contacts?.length) return;
243
235
  return {
244
- kind: "contacts",
245
- total: contactsArray.length,
246
- contacts: contactsArray.map(describeContact)
236
+ kind: contact ? "contact" : "contacts",
237
+ total: contacts.length,
238
+ contacts: contacts.map(describeContact)
247
239
  };
248
240
  }
249
241
  function describeContact(input) {
@@ -366,9 +358,6 @@ const OUTBOUND_MENTION_RE = /@(\+?\d+)/g;
366
358
  const KNOWN_USER_JID_RE = /^(\d+)(?::\d+)?@(s\.whatsapp\.net|hosted|lid|hosted\.lid|c\.us)$/i;
367
359
  const PHONE_JID_DOMAIN_RE = /^(s\.whatsapp\.net|hosted|c\.us)$/i;
368
360
  const LID_JID_DOMAIN_RE = /^(lid|hosted\.lid)$/i;
369
- function isWhatsAppGroupJid(jid) {
370
- return jid.endsWith("@g.us");
371
- }
372
361
  function mayContainWhatsAppOutboundMention(text) {
373
362
  return /@\+?\d/.test(text);
374
363
  }
@@ -465,7 +454,7 @@ function shouldSkipMentionAt(text, index, end, codeRanges) {
465
454
  return Boolean(previous && /[\w@]/.test(previous) || next && /[\w@]/.test(next));
466
455
  }
467
456
  function resolveWhatsAppOutboundMentions(params) {
468
- if (!isWhatsAppGroupJid(params.chatJid) || !mayContainWhatsAppOutboundMention(params.text) || !params.participants?.length) return {
457
+ if (!params.chatJid.endsWith("@g.us") || !mayContainWhatsAppOutboundMention(params.text) || !params.participants?.length) return {
469
458
  text: params.text,
470
459
  mentionedJids: []
471
460
  };
@@ -475,38 +464,16 @@ function resolveWhatsAppOutboundMentions(params) {
475
464
  mentionedJids: []
476
465
  };
477
466
  const codeRanges = collectCodeRanges(params.text);
478
- const replacements = [];
479
467
  const mentionedJids = /* @__PURE__ */ new Set();
480
- for (const match of params.text.matchAll(OUTBOUND_MENTION_RE)) {
481
- const start = match.index;
482
- const token = match[0];
483
- if (shouldSkipMentionAt(params.text, start, start + token.length, codeRanges)) continue;
484
- const rawDigits = match[1];
485
- if (!rawDigits) continue;
486
- const digits = rawDigits.replace(/\D/g, "");
487
- const target = token.startsWith("@+") ? byPhone.get(digits) ?? byLid.get(digits) : byLid.get(digits) ?? byPhone.get(digits);
488
- if (!target) continue;
489
- mentionedJids.add(target.mentionJid);
490
- if (target.replacementText && target.replacementText !== token) replacements.push({
491
- start,
492
- end: start + token.length,
493
- text: target.replacementText
494
- });
495
- }
496
- if (replacements.length === 0) return {
497
- text: params.text,
498
- mentionedJids: [...mentionedJids]
499
- };
500
- let text = "";
501
- let cursor = 0;
502
- for (const replacement of replacements) {
503
- text += params.text.slice(cursor, replacement.start);
504
- text += replacement.text;
505
- cursor = replacement.end;
506
- }
507
- text += params.text.slice(cursor);
508
468
  return {
509
- text,
469
+ text: params.text.replace(OUTBOUND_MENTION_RE, (token, rawDigits, start) => {
470
+ if (shouldSkipMentionAt(params.text, start, start + token.length, codeRanges)) return token;
471
+ const digits = rawDigits.replace(/\D/g, "");
472
+ const target = token.startsWith("@+") ? byPhone.get(digits) ?? byLid.get(digits) : byLid.get(digits) ?? byPhone.get(digits);
473
+ if (!target) return token;
474
+ mentionedJids.add(target.mentionJid);
475
+ return target.replacementText ?? token;
476
+ }),
510
477
  mentionedJids: [...mentionedJids]
511
478
  };
512
479
  }
@@ -564,10 +531,13 @@ function createWebSendApi(params) {
564
531
  mentionedJids: []
565
532
  } : await resolveMentions(jid, text);
566
533
  if (mediaBuffer && mediaType) {
567
- if (mediaType.startsWith("image/") && sendOptions?.asDocument !== true) payload = await addWhatsAppImagePreviewFields({
568
- image: mediaBuffer,
534
+ const mediaFields = {
569
535
  caption: resolvedPayloadText.text || void 0,
570
536
  mimetype: mediaType
537
+ };
538
+ if (mediaType.startsWith("image/") && sendOptions?.asDocument !== true) payload = await addWhatsAppImagePreviewFields({
539
+ image: mediaBuffer,
540
+ ...mediaFields
571
541
  });
572
542
  else if (mediaType.startsWith("audio/")) payload = {
573
543
  audio: mediaBuffer,
@@ -578,8 +548,7 @@ function createWebSendApi(params) {
578
548
  const gifPlayback = sendOptions?.gifPlayback;
579
549
  payload = {
580
550
  video: mediaBuffer,
581
- caption: resolvedPayloadText.text || void 0,
582
- mimetype: mediaType,
551
+ ...mediaFields,
583
552
  ...gifPlayback ? { gifPlayback: true } : {}
584
553
  };
585
554
  } else payload = {
@@ -588,8 +557,7 @@ function createWebSendApi(params) {
588
557
  fileName: sendOptions?.fileName,
589
558
  mimetype: mediaType
590
559
  }),
591
- caption: resolvedPayloadText.text || void 0,
592
- mimetype: mediaType
560
+ ...mediaFields
593
561
  };
594
562
  } else payload = { text: resolvedPayloadText.text };
595
563
  payload = addWhatsAppOutboundMentionsToContent(payload, resolvedPayloadText.mentionedJids);
@@ -1,8 +1,8 @@
1
1
  import { a as resolveWhatsAppAccount, o as resolveWhatsAppAuthDir } from "./accounts-F0vHuze2.mjs";
2
2
  import { r as resolveDefaultWhatsAppAccountId } from "./account-ids-CB5SOWjc.mjs";
3
3
  import { n as hasWebCredsSync } from "./creds-files-B8WcOAmE.mjs";
4
- import { a as normalizeWhatsAppAllowFromEntries, o as normalizeWhatsAppAllowFromEntry } from "./normalize-target-BGra1ZnM.mjs";
5
- import { n as whatsappSetupAdapter } from "./shared-CP_zs2U7.mjs";
4
+ import { a as normalizeWhatsAppAllowFromEntries, o as normalizeWhatsAppAllowFromEntry } from "./normalize-target-D67Kc3g6.mjs";
5
+ import { n as whatsappSetupAdapter } from "./shared-SqcOkt51.mjs";
6
6
  import { formatCliCommand, formatDocsLink } from "openclaw/plugin-sdk/setup-tools";
7
7
  import { DEFAULT_ACCOUNT_ID, createSetupTranslator, splitSetupEntries } from "openclaw/plugin-sdk/setup";
8
8
  //#region extensions/whatsapp/src/setup-finalize.ts
@@ -13,24 +13,22 @@ function trimPromptText(value) {
13
13
  function isDefaultWhatsAppAccountKey(accountId) {
14
14
  return accountId.trim().toLowerCase() === DEFAULT_ACCOUNT_ID;
15
15
  }
16
- function shouldWriteDefaultWhatsAppAccountConfigAtAccountScope(cfg) {
16
+ function resolveWhatsAppAccountWriteKey(cfg, accountId) {
17
+ if (accountId !== DEFAULT_ACCOUNT_ID) return accountId;
17
18
  const accounts = cfg.channels?.whatsapp?.accounts;
18
- return Boolean(accounts && (accounts.default || Object.keys(accounts).some((accountId) => !isDefaultWhatsAppAccountKey(accountId))));
19
- }
20
- function resolveDefaultWhatsAppAccountWriteKey(cfg) {
21
- const accounts = cfg.channels?.whatsapp?.accounts;
22
- if (!accounts) return DEFAULT_ACCOUNT_ID;
23
- return Object.keys(accounts).find((accountId) => isDefaultWhatsAppAccountKey(accountId)) ?? DEFAULT_ACCOUNT_ID;
19
+ const keys = Object.keys(accounts ?? {});
20
+ if (!accounts?.default && !keys.some((key) => !isDefaultWhatsAppAccountKey(key))) return;
21
+ return keys.find(isDefaultWhatsAppAccountKey) ?? DEFAULT_ACCOUNT_ID;
24
22
  }
25
23
  function resolveWhatsAppConfigPathPrefix(cfg, accountId) {
26
- if (accountId === DEFAULT_ACCOUNT_ID && shouldWriteDefaultWhatsAppAccountConfigAtAccountScope(cfg)) return `channels.whatsapp.accounts.${resolveDefaultWhatsAppAccountWriteKey(cfg)}`;
27
- return accountId === DEFAULT_ACCOUNT_ID ? "channels.whatsapp" : `channels.whatsapp.accounts.${accountId}`;
24
+ const key = resolveWhatsAppAccountWriteKey(cfg, accountId);
25
+ return key === void 0 ? "channels.whatsapp" : `channels.whatsapp.accounts.${key}`;
28
26
  }
29
27
  function mergeWhatsAppConfig(cfg, accountId, patch, options) {
30
28
  const channelConfig = { ...cfg.channels?.whatsapp };
31
- const atRoot = resolveWhatsAppConfigPathPrefix(cfg, accountId) === "channels.whatsapp";
29
+ const targetAccountId = resolveWhatsAppAccountWriteKey(cfg, accountId);
30
+ const atRoot = targetAccountId === void 0;
32
31
  const accounts = { ...channelConfig.accounts };
33
- const targetAccountId = accountId === DEFAULT_ACCOUNT_ID ? resolveDefaultWhatsAppAccountWriteKey(cfg) : accountId;
34
32
  const lowerDefaultAccount = accountId === DEFAULT_ACCOUNT_ID && targetAccountId !== DEFAULT_ACCOUNT_ID ? accounts[DEFAULT_ACCOUNT_ID] : void 0;
35
33
  const target = atRoot ? channelConfig : {
36
34
  ...accounts[targetAccountId],
@@ -179,29 +177,22 @@ async function promptWhatsAppDmAccess(params) {
179
177
  });
180
178
  if (policy === "open") return setWhatsAppAllowFrom(next, accountId, normalizeWhatsAppAllowFromEntries(["*", ...existingAllowFrom]));
181
179
  if (policy === "disabled") return next;
182
- const allowOptions = existingAllowFrom.length > 0 ? [
183
- {
184
- value: "keep",
185
- label: t("wizard.whatsapp.keepCurrentAllowFrom")
186
- },
187
- {
188
- value: "unset",
189
- label: t("wizard.whatsapp.unsetAllowFromPairing")
190
- },
191
- {
192
- value: "list",
193
- label: t("wizard.whatsapp.setAllowFromNumbers")
194
- }
195
- ] : [{
196
- value: "unset",
197
- label: t("wizard.whatsapp.unsetAllowFromDefault")
198
- }, {
199
- value: "list",
200
- label: t("wizard.whatsapp.setAllowFromNumbers")
201
- }];
202
180
  const mode = await params.prompter.select({
203
181
  message: t("wizard.whatsapp.allowFromPrompt"),
204
- options: [...allowOptions]
182
+ options: [
183
+ ...existingAllowFrom.length > 0 ? [{
184
+ value: "keep",
185
+ label: t("wizard.whatsapp.keepCurrentAllowFrom")
186
+ }] : [],
187
+ {
188
+ value: "unset",
189
+ label: t(existingAllowFrom.length > 0 ? "wizard.whatsapp.unsetAllowFromPairing" : "wizard.whatsapp.unsetAllowFromDefault")
190
+ },
191
+ {
192
+ value: "list",
193
+ label: t("wizard.whatsapp.setAllowFromNumbers")
194
+ }
195
+ ]
205
196
  });
206
197
  if (mode === "keep") return next;
207
198
  if (mode === "unset") return setWhatsAppAllowFrom(next, accountId, void 0);
@@ -232,42 +223,35 @@ async function finalizeWhatsAppSetup(params) {
232
223
  accountId
233
224
  });
234
225
  const linked = hasWebCredsSync(authDir);
235
- if (params.options?.deferDeviceLinkToClient) {
236
- next = await promptWhatsAppDmAccess({
237
- cfg: next,
238
- accountId,
239
- forceAllowFrom: params.forceAllowFrom,
240
- prompter: params.prompter
241
- });
242
- return { cfg: next };
226
+ if (!params.options?.deferDeviceLinkToClient) {
227
+ if (!linked) await params.prompter.note([
228
+ t("wizard.whatsapp.scanQr"),
229
+ t("wizard.whatsapp.credentialsStored", { authDir }),
230
+ t("wizard.channels.docs", { link: formatDocsLink("/whatsapp", "whatsapp") })
231
+ ].join("\n"), t("wizard.whatsapp.linkingTitle"));
232
+ if (await params.prompter.confirm({
233
+ message: linked ? t("wizard.whatsapp.relinkPrompt") : t("wizard.whatsapp.linkNowPrompt"),
234
+ initialValue: !linked
235
+ })) {
236
+ let persistenceGuardFailure;
237
+ try {
238
+ const { loginWeb } = await import("./login-DUx5JYuW.mjs").then((n) => n.n);
239
+ const beforeCredentialPersistence = params.options?.beforePersistentEffect ? async () => {
240
+ try {
241
+ await params.options?.beforePersistentEffect?.();
242
+ } catch (error) {
243
+ persistenceGuardFailure = { error };
244
+ throw error;
245
+ }
246
+ } : void 0;
247
+ await loginWeb(false, void 0, params.runtime, accountId, { beforeCredentialPersistence });
248
+ } catch (error) {
249
+ if (persistenceGuardFailure) throw persistenceGuardFailure.error;
250
+ params.runtime.error(`WhatsApp login failed: ${String(error)}`);
251
+ await params.prompter.note(t("wizard.channels.docs", { link: formatDocsLink("/whatsapp", "whatsapp") }), t("wizard.whatsapp.helpTitle"));
252
+ }
253
+ } else if (!linked) await params.prompter.note(t("wizard.whatsapp.linkLater", { command: formatCliCommand("openclaw channels login") }), "WhatsApp");
243
254
  }
244
- if (!linked) await params.prompter.note([
245
- t("wizard.whatsapp.scanQr"),
246
- t("wizard.whatsapp.credentialsStored", { authDir }),
247
- t("wizard.channels.docs", { link: formatDocsLink("/whatsapp", "whatsapp") })
248
- ].join("\n"), t("wizard.whatsapp.linkingTitle"));
249
- if (await params.prompter.confirm({
250
- message: linked ? t("wizard.whatsapp.relinkPrompt") : t("wizard.whatsapp.linkNowPrompt"),
251
- initialValue: !linked
252
- })) {
253
- let persistenceGuardFailure;
254
- try {
255
- const { loginWeb } = await import("./login-CV_4V021.mjs").then((n) => n.n);
256
- const beforeCredentialPersistence = params.options?.beforePersistentEffect ? async () => {
257
- try {
258
- await params.options?.beforePersistentEffect?.();
259
- } catch (error) {
260
- persistenceGuardFailure = { error };
261
- throw error;
262
- }
263
- } : void 0;
264
- await loginWeb(false, void 0, params.runtime, accountId, { beforeCredentialPersistence });
265
- } catch (error) {
266
- if (persistenceGuardFailure) throw persistenceGuardFailure.error;
267
- params.runtime.error(`WhatsApp login failed: ${String(error)}`);
268
- await params.prompter.note(t("wizard.channels.docs", { link: formatDocsLink("/whatsapp", "whatsapp") }), t("wizard.whatsapp.helpTitle"));
269
- }
270
- } else if (!linked) await params.prompter.note(t("wizard.whatsapp.linkLater", { command: formatCliCommand("openclaw channels login") }), "WhatsApp");
271
255
  next = await promptWhatsAppDmAccess({
272
256
  cfg: next,
273
257
  accountId,
@@ -0,0 +1,3 @@
1
+ import { t as whatsappSetupPlugin } from "./channel.setup-BJWEyQlF.mjs";
2
+ import "../setup-plugin-api.js";
3
+ export { whatsappSetupPlugin };
@@ -1,6 +1,6 @@
1
1
  import { o as resolveWhatsAppAuthDir } from "./accounts-F0vHuze2.mjs";
2
2
  import { t as listAccountIds } from "./account-ids-CB5SOWjc.mjs";
3
- import { a as formatWhatsAppWebAuthStatusState, m as readWebAuthState } from "./auth-store-D2rN-hP5.mjs";
3
+ import { a as formatWhatsAppWebAuthStatusState, m as readWebAuthState } from "./auth-store-DOBi5BPe.mjs";
4
4
  import { DEFAULT_ACCOUNT_ID, createSetupTranslator, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup";
5
5
  //#region extensions/whatsapp/src/setup-surface.ts
6
6
  const t = createSetupTranslator();
@@ -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-GtBmrO8p.mjs")).finalizeWhatsAppSetup(params),
39
+ finalize: async (params) => await (await import("./setup-finalize-DSiP_-wa.mjs")).finalizeWhatsAppSetup(params),
40
40
  disable: (cfg) => setSetupChannelEnabled(cfg, channel, false),
41
41
  onAccountRecorded: (accountId, options) => {
42
42
  options?.onAccountId?.(channel, accountId);
@@ -1,6 +1,6 @@
1
1
  import { a as resolveWhatsAppAccount, n as hasAnyWhatsAppAuth } from "./accounts-F0vHuze2.mjs";
2
2
  import { r as resolveDefaultWhatsAppAccountId, t as listAccountIds } from "./account-ids-CB5SOWjc.mjs";
3
- import { a as normalizeWhatsAppAllowFromEntries } from "./normalize-target-BGra1ZnM.mjs";
3
+ import { a as normalizeWhatsAppAllowFromEntries } from "./normalize-target-D67Kc3g6.mjs";
4
4
  import { t as WhatsAppChannelConfigSchema } from "./config-schema-BYA6e_Ii.mjs";
5
5
  import { n as whatsappDoctor } from "./doctor-DKzeBEmH.mjs";
6
6
  import { t as resolveWhatsAppConfigPath } from "./group-config-path-BPrak_bJ.mjs";
@@ -20,14 +20,14 @@ import { readChannelAllowFromStore } from "openclaw/plugin-sdk/channel-pairing";
20
20
  import { defineChannelSetupContract } from "openclaw/plugin-sdk/channel-setup";
21
21
  import { createPatchedAccountSetupAdapter } from "openclaw/plugin-sdk/setup";
22
22
  //#region extensions/whatsapp/src/channel-runtime-loader.ts
23
- const loadWhatsAppAuthStore = createLazyRuntimeModule(() => import("./auth-store-D2rN-hP5.mjs").then((n) => n.i));
23
+ const loadWhatsAppAuthStore = createLazyRuntimeModule(() => import("./auth-store-DOBi5BPe.mjs").then((n) => n.i));
24
24
  async function readWhatsAppAccountLinkState(authDir) {
25
25
  const state = await (await loadWhatsAppAuthStore()).readWebAuthState(authDir);
26
26
  return state === "unstable" ? "unknown" : state;
27
27
  }
28
28
  const loadWhatsAppChannelRuntime = createLazyRuntimeModule(async () => {
29
29
  await loadWhatsAppAuthStore();
30
- return await import("./channel.runtime-BniF8Swm.mjs");
30
+ return await import("./channel.runtime-DTj-wkEP.mjs");
31
31
  });
32
32
  //#endregion
33
33
  //#region extensions/whatsapp/src/group-policy.ts
@@ -132,7 +132,7 @@ const whatsappResolveDmPolicy = createScopedDmSecurityResolver({
132
132
  });
133
133
  const whatsappSetupWizardProxy = createDelegatedSetupWizardProxy({
134
134
  channel: WHATSAPP_CHANNEL,
135
- loadWizard: async () => (await import("./setup-surface-BuA39k6K.mjs")).whatsappSetupWizard,
135
+ loadWizard: async () => (await import("./setup-surface-C_flQyHy.mjs")).whatsappSetupWizard,
136
136
  status: {
137
137
  configuredLabel: "linked",
138
138
  unconfiguredLabel: "not linked",