@openclaw/whatsapp 2026.5.28-beta.4 → 2026.5.30-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 (27) hide show
  1. package/dist/{action-runtime-BdhkGtaP.js → action-runtime-BbUDQ78g.js} +1 -1
  2. package/dist/action-runtime-api.js +1 -1
  3. package/dist/action-runtime.runtime.js +1 -1
  4. package/dist/api.js +6 -6
  5. package/dist/{approval-handler.runtime-C25wPeBf.js → approval-handler.runtime-BIZgAkfR.js} +1 -1
  6. package/dist/{auth-store-BrKb0mwT.js → auth-store-CZ22aNcV.js} +4 -2
  7. package/dist/{channel-CLOhkP85.js → channel-dHRyqWut.js} +16 -63
  8. package/dist/channel-plugin-api.js +1 -1
  9. package/dist/{channel-react-action-Cd2qkLqp.js → channel-react-action-CYx128FS.js} +2 -2
  10. package/dist/{channel.runtime-CcGhK_F2.js → channel.runtime-3WElbRZG.js} +4 -4
  11. package/dist/{channel.setup-COV8culQ.js → channel.setup-BuSd1d1D.js} +2 -2
  12. package/dist/{connection-controller-BZuzYCGM.js → connection-controller-Bnm4INld.js} +21 -7
  13. package/dist/light-runtime-api.js +1 -1
  14. package/dist/{login-1yyBrXTL.js → login-DygDn79y.js} +3 -3
  15. package/dist/{login-qr-6DdwGlkz.js → login-qr-nPxKvdjP.js} +31 -6
  16. package/dist/login-qr-runtime.js +1 -1
  17. package/dist/{monitor-D4R-fcMW.js → monitor-NKzAEWeJ.js} +21 -11
  18. package/dist/runtime-api.js +7 -7
  19. package/dist/{send-C4LG-Cl6.js → send-DjMBLgiv.js} +43 -39
  20. package/dist/{send-api-C66vkRl9.js → send-api-Cx2qeYqj.js} +1 -1
  21. package/dist/{session-D8UW2Vbn.js → session-DyGWNClj.js} +1 -1
  22. package/dist/{setup-core-DAgAB2WU.js → setup-core-B9CAuPOB.js} +2 -2
  23. package/dist/{setup-finalize-CDPy4WyU.js → setup-finalize-f95kxYvv.js} +2 -2
  24. package/dist/setup-plugin-api.js +1 -1
  25. package/dist/{setup-surface-Bt5mdv4D.js → setup-surface-_Cid6xIf.js} +2 -2
  26. package/npm-shrinkwrap.json +3 -3
  27. package/package.json +4 -4
@@ -1,6 +1,6 @@
1
1
  import { a as resolveWhatsAppAccount } from "./accounts-BMGM1RtF.js";
2
2
  import { t as resolveWhatsAppOutboundTarget } from "./resolve-outbound-target-CcdugbDf.js";
3
- import { g as resolveWhatsAppReactionLevel, r as sendReactionWhatsApp } from "./send-C4LG-Cl6.js";
3
+ import { g as resolveWhatsAppReactionLevel, r as sendReactionWhatsApp } from "./send-DjMBLgiv.js";
4
4
  import { ToolAuthorizationError, createActionGate, jsonResult, readReactionParams, readStringParam } from "openclaw/plugin-sdk/channel-actions";
5
5
  //#region extensions/whatsapp/src/action-runtime-target-auth.ts
6
6
  function resolveAuthorizedWhatsAppOutboundTarget(params) {
@@ -1,2 +1,2 @@
1
- import { t as handleWhatsAppAction } from "./action-runtime-BdhkGtaP.js";
1
+ import { t as handleWhatsAppAction } from "./action-runtime-BbUDQ78g.js";
2
2
  export { handleWhatsAppAction };
@@ -1,2 +1,2 @@
1
- import { t as handleWhatsAppAction } from "./action-runtime-BdhkGtaP.js";
1
+ import { t as handleWhatsAppAction } from "./action-runtime-BbUDQ78g.js";
2
2
  export { handleWhatsAppAction };
package/dist/api.js CHANGED
@@ -2,18 +2,18 @@ import { r as resolveDefaultWhatsAppAccountId, t as listAccountIds } from "./acc
2
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-BMGM1RtF.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-bVWjgftN.js";
4
4
  import { t as resolveWhatsAppOutboundTarget } from "./resolve-outbound-target-CcdugbDf.js";
5
- import "./send-C4LG-Cl6.js";
5
+ import "./send-DjMBLgiv.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-Dk37KYHj.js";
7
- import { n as WHATSAPP_LEGACY_OUTBOUND_SEND_DEP_KEYS, t as whatsappPlugin } from "./channel-CLOhkP85.js";
7
+ import { n as WHATSAPP_LEGACY_OUTBOUND_SEND_DEP_KEYS, t as whatsappPlugin } from "./channel-dHRyqWut.js";
8
8
  import { t as whatsappCommandPolicy } from "./command-policy-BIOSHySD.js";
9
- import { a as resolveWhatsAppGroupRequireMention, o as resolveWhatsAppGroupToolPolicy, s as resolveWhatsAppGroupIntroHint } from "./setup-core-DAgAB2WU.js";
9
+ import { a as resolveWhatsAppGroupRequireMention, o as resolveWhatsAppGroupToolPolicy, s as resolveWhatsAppGroupIntroHint } from "./setup-core-B9CAuPOB.js";
10
10
  import "./config-schema-CsNDlDpL.js";
11
- import { t as whatsappSetupPlugin } from "./channel.setup-COV8culQ.js";
11
+ import { t as whatsappSetupPlugin } from "./channel.setup-BuSd1d1D.js";
12
12
  import { t as DEFAULT_WEB_MEDIA_BYTES } from "./constants-HU41RHGI.js";
13
13
  import { n as listWhatsAppDirectoryGroupsFromConfig, r as listWhatsAppDirectoryPeersFromConfig } from "./directory-config-Dijefxc3.js";
14
14
  import { n as testing } from "./access-control-Z0fYaWrx.js";
15
- import { m as extractText, t as createWebSendApi } from "./send-api-C66vkRl9.js";
16
- import { r as waitForWaConnection, t as createWaSocket } from "./session-D8UW2Vbn.js";
15
+ import { m as extractText, t as createWebSendApi } from "./send-api-Cx2qeYqj.js";
16
+ import { r as waitForWaConnection, t as createWaSocket } from "./session-DyGWNClj.js";
17
17
  import "openclaw/plugin-sdk/channel-actions";
18
18
  import "openclaw/plugin-sdk/account-resolution";
19
19
  import "openclaw/plugin-sdk/core";
@@ -1,5 +1,5 @@
1
1
  import { s as normalizeWhatsAppMessagingTarget } from "./normalize-target-bVWjgftN.js";
2
- import { f as registerWhatsAppApprovalReactionTarget, i as sendTypingWhatsApp, p as unregisterWhatsAppApprovalReactionTarget, t as sendMessageWhatsApp } from "./send-C4LG-Cl6.js";
2
+ import { f as registerWhatsAppApprovalReactionTarget, i as sendTypingWhatsApp, p as unregisterWhatsAppApprovalReactionTarget, t as sendMessageWhatsApp } from "./send-DjMBLgiv.js";
3
3
  import "./normalize-Bxwqo-bW.js";
4
4
  import { n as getWhatsAppRuntime } from "./runtime-BfAdAEYT.js";
5
5
  import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
@@ -7,8 +7,9 @@ import { resolveOAuthDir as resolveOAuthDir$1 } from "openclaw/plugin-sdk/state-
7
7
  import { replaceFileAtomic } from "openclaw/plugin-sdk/security-runtime";
8
8
  import { formatCliCommand } from "openclaw/plugin-sdk/cli-runtime";
9
9
  import { defaultRuntime, getChildLogger, info, success } from "openclaw/plugin-sdk/runtime-env";
10
- import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/routing";
11
10
  import fs from "node:fs/promises";
11
+ import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/routing";
12
+ import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
12
13
  //#region extensions/whatsapp/src/creds-persistence.ts
13
14
  const CREDS_FILE_MODE = 384;
14
15
  const CREDS_SAVE_FLUSH_TIMEOUT_MS = 15e3;
@@ -52,9 +53,10 @@ function waitForCredsSaveQueue(authDir) {
52
53
  return Promise.all(credsSaveQueues.values()).then(() => {});
53
54
  }
54
55
  async function waitForCredsSaveQueueWithTimeout(authDir, timeoutMs = CREDS_SAVE_FLUSH_TIMEOUT_MS) {
56
+ const boundedTimeoutMs = resolveTimerTimeoutMs(timeoutMs, CREDS_SAVE_FLUSH_TIMEOUT_MS, 0);
55
57
  let flushTimeout;
56
58
  return await Promise.race([waitForCredsSaveQueue(authDir).then(() => "drained"), new Promise((resolve) => {
57
- flushTimeout = setTimeout(() => resolve("timed_out"), timeoutMs);
59
+ flushTimeout = setTimeout(() => resolve("timed_out"), boundedTimeoutMs);
58
60
  })]).finally(() => {
59
61
  if (flushTimeout) clearTimeout(flushTimeout);
60
62
  });
@@ -2,15 +2,15 @@ import { r as resolveDefaultWhatsAppAccountId, t as listAccountIds } from "./acc
2
2
  import { a as resolveWhatsAppAccount } from "./accounts-BMGM1RtF.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-bVWjgftN.js";
4
4
  import { t as resolveWhatsAppOutboundTarget } from "./resolve-outbound-target-CcdugbDf.js";
5
- import { a as normalizeWhatsAppOutboundPayload, g as resolveWhatsAppReactionLevel, h as whatsappApprovalAuth, i as sendTypingWhatsApp, m as getWhatsAppApprovalApprovers, n as sendPollWhatsApp, o as normalizeWhatsAppPayloadText, s as normalizeWhatsAppPayloadTextPreservingIndentation, t as sendMessageWhatsApp } from "./send-C4LG-Cl6.js";
5
+ import { a as normalizeWhatsAppOutboundPayload, g as resolveWhatsAppReactionLevel, h as whatsappApprovalAuth, i as sendTypingWhatsApp, m as getWhatsAppApprovalApprovers, n as sendPollWhatsApp, o as normalizeWhatsAppPayloadText, s as normalizeWhatsAppPayloadTextPreservingIndentation, t as sendMessageWhatsApp } from "./send-DjMBLgiv.js";
6
6
  import "./normalize-Bxwqo-bW.js";
7
7
  import { n as getWhatsAppRuntime } from "./runtime-BfAdAEYT.js";
8
8
  import { p as toWhatsappJid } from "./text-runtime-Dk37KYHj.js";
9
9
  import { t as createWhatsAppLoginTool } from "./agent-tools-login-BX7eHgDm.js";
10
10
  import { i as lookupInboundMessageMetaForTarget } from "./quoted-message-CveINB35.js";
11
11
  import { t as whatsappCommandPolicy } from "./command-policy-BIOSHySD.js";
12
- 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-DAgAB2WU.js";
13
- import { f as readWebAuthExistsForDecision, n as WHATSAPP_AUTH_UNSTABLE_CODE } from "./auth-store-BrKb0mwT.js";
12
+ 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-B9CAuPOB.js";
13
+ import { f as readWebAuthExistsForDecision, n as WHATSAPP_AUTH_UNSTABLE_CODE } from "./auth-store-CZ22aNcV.js";
14
14
  import { t as detectWhatsAppLegacyStateMigrations } from "./state-migrations-D_BmQUR9.js";
15
15
  import { createActionGate as createActionGate$1 } from "openclaw/plugin-sdk/channel-actions";
16
16
  import { DEFAULT_ACCOUNT_ID, listCombinedAccountIds, normalizeOptionalAccountId, resolveListedDefaultAccountId } from "openclaw/plugin-sdk/account-core";
@@ -26,31 +26,18 @@ import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
26
26
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
27
27
  import { createChannelApprovalCapability, splitChannelApprovalCapability } from "openclaw/plugin-sdk/approval-delivery-runtime";
28
28
  import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-adapter-runtime";
29
- import { createChannelApprovalForwardingEvaluator, createChannelApproverDmTargetResolver, createChannelNativeOriginTargetResolver, createNativeApprovalForwardingFallbackSuppressor, nativeApprovalTargetsMatch, resolveApprovalRequestSessionTarget } from "openclaw/plugin-sdk/approval-native-runtime";
30
- import { normalizeAccountId as normalizeAccountId$2 } from "openclaw/plugin-sdk/routing";
29
+ import { createChannelApproverDmTargetResolver, createChannelNativeOriginTargetResolver, createNativeApprovalChannelRouteGates, createNativeApprovalForwardingFallbackSuppressor } from "openclaw/plugin-sdk/approval-native-runtime";
31
30
  import { chunkText } from "openclaw/plugin-sdk/reply-chunking";
32
31
  import { createAttachedChannelResultAdapter } from "openclaw/plugin-sdk/channel-send-result";
33
32
  import { sendTextMediaPayload } from "openclaw/plugin-sdk/reply-payload";
34
33
  //#region extensions/whatsapp/src/approval-native.ts
34
+ const DEFAULT_APPROVAL_FORWARDING_MODE = "session";
35
35
  function isWhatsAppApprovalTransportEnabled(params) {
36
36
  return resolveWhatsAppAccount({
37
37
  cfg: params.cfg,
38
38
  accountId: params.accountId
39
39
  }).enabled;
40
40
  }
41
- function targetAccountMatchesWhatsAppAccount(params) {
42
- const targetAccountId = normalizeOptionalString(params.targetAccountId);
43
- const accountId = normalizeOptionalString(params.accountId);
44
- if (targetAccountId) return !accountId || normalizeAccountId$2(targetAccountId) === normalizeAccountId$2(accountId);
45
- if (!accountId) return true;
46
- const normalizedAccountId = normalizeAccountId$2(accountId);
47
- if (normalizedAccountId === normalizeAccountId$2(resolveDefaultWhatsAppAccountId(params.cfg))) return true;
48
- const enabledAccountIds = listAccountIds(params.cfg).filter((candidateAccountId) => isWhatsAppApprovalTransportEnabled({
49
- cfg: params.cfg,
50
- accountId: candidateAccountId
51
- })).map((candidateAccountId) => normalizeAccountId$2(candidateAccountId));
52
- return enabledAccountIds.length === 1 && enabledAccountIds[0] === normalizedAccountId;
53
- }
54
41
  function normalizeWhatsAppForwardTarget(target) {
55
42
  if (normalizeLowercaseStringOrEmpty(target.channel) !== "whatsapp") return null;
56
43
  const to = normalizeWhatsAppMessagingTarget(target.to);
@@ -61,46 +48,6 @@ function normalizeWhatsAppForwardTarget(target) {
61
48
  threadId: target.threadId ?? null
62
49
  };
63
50
  }
64
- function hasMatchingWhatsAppTarget(params) {
65
- const candidateTarget = params.target ? normalizeWhatsAppForwardTarget(params.target) : null;
66
- return (params.config.targets ?? []).some((target) => {
67
- const configuredTarget = normalizeWhatsAppForwardTarget(target);
68
- if (!configuredTarget) return false;
69
- if (!targetAccountMatchesWhatsAppAccount({
70
- cfg: params.cfg,
71
- targetAccountId: configuredTarget.accountId,
72
- accountId: params.accountId
73
- })) return false;
74
- if (!candidateTarget) return true;
75
- return nativeApprovalTargetsMatch({
76
- channel: "whatsapp",
77
- left: configuredTarget,
78
- right: candidateTarget
79
- });
80
- });
81
- }
82
- function hasWhatsAppOriginOrSessionTarget(params) {
83
- if (resolveTurnSourceWhatsAppOriginTarget(params.request)) return true;
84
- const sessionTarget = resolveApprovalRequestSessionTarget({
85
- cfg: params.cfg,
86
- request: params.request
87
- });
88
- return normalizeLowercaseStringOrEmpty(sessionTarget?.channel) === "whatsapp" && targetAccountMatchesWhatsAppAccount({
89
- cfg: params.cfg,
90
- targetAccountId: sessionTarget?.accountId,
91
- accountId: params.accountId
92
- });
93
- }
94
- const whatsappApprovalForwarding = createChannelApprovalForwardingEvaluator({
95
- channel: "whatsapp",
96
- isTransportEnabled: isWhatsAppApprovalTransportEnabled,
97
- hasMatchingTarget: hasMatchingWhatsAppTarget,
98
- hasOriginOrSessionTarget: hasWhatsAppOriginOrSessionTarget
99
- });
100
- const canApprovalPotentiallyRouteToWhatsApp = whatsappApprovalForwarding.isPotentialRoute;
101
- const canAnyApprovalPotentiallyRouteToWhatsApp = whatsappApprovalForwarding.canAnyPotentiallyRoute;
102
- const isWhatsAppSessionApprovalEligible = whatsappApprovalForwarding.isSessionEligible;
103
- const isWhatsAppExplicitTargetEligible = whatsappApprovalForwarding.isExplicitTargetEligible;
104
51
  function resolveTurnSourceWhatsAppOriginTarget(request) {
105
52
  if (normalizeLowercaseStringOrEmpty(request.request.turnSourceChannel) !== "whatsapp") return null;
106
53
  const to = normalizeWhatsAppMessagingTarget(request.request.turnSourceTo ?? "");
@@ -117,9 +64,15 @@ function resolveSessionWhatsAppOriginTarget(sessionTarget) {
117
64
  accountId: normalizeOptionalString(sessionTarget.accountId)
118
65
  } : null;
119
66
  }
120
- function shouldHandleWhatsAppApprovalRequest(params) {
121
- return whatsappApprovalForwarding.shouldHandleRequest(params);
122
- }
67
+ const { canApprovalPotentiallyRouteToChannel: canApprovalPotentiallyRouteToWhatsApp, canAnyApprovalPotentiallyRouteToChannel: canAnyApprovalPotentiallyRouteToWhatsApp, isSessionApprovalEligible: isWhatsAppSessionApprovalEligible, isExplicitTargetEligible: isWhatsAppExplicitTargetEligible, shouldHandleApprovalRequest: shouldHandleWhatsAppApprovalRequest } = createNativeApprovalChannelRouteGates({
68
+ channel: "whatsapp",
69
+ defaultForwardingMode: DEFAULT_APPROVAL_FORWARDING_MODE,
70
+ isTransportEnabled: isWhatsAppApprovalTransportEnabled,
71
+ listAccountIds,
72
+ resolveDefaultAccountId: resolveDefaultWhatsAppAccountId,
73
+ normalizeForwardTarget: normalizeWhatsAppForwardTarget,
74
+ resolveTurnSourceTarget: resolveTurnSourceWhatsAppOriginTarget
75
+ });
123
76
  const resolveWhatsAppOriginTargetBase = createChannelNativeOriginTargetResolver({
124
77
  channel: "whatsapp",
125
78
  shouldHandleRequest: shouldHandleWhatsAppApprovalRequest,
@@ -252,7 +205,7 @@ const whatsappApprovalCapability = createChannelApprovalCapability({
252
205
  accountId,
253
206
  request
254
207
  }),
255
- load: async () => (await import("./approval-handler.runtime-C25wPeBf.js")).whatsappApprovalNativeRuntime
208
+ load: async () => (await import("./approval-handler.runtime-BIZgAkfR.js")).whatsappApprovalNativeRuntime
256
209
  })
257
210
  });
258
211
  splitChannelApprovalCapability(whatsappApprovalCapability);
@@ -651,7 +604,7 @@ function collectWhatsAppStatusIssues(accounts) {
651
604
  //#endregion
652
605
  //#region extensions/whatsapp/src/channel.ts
653
606
  const loadWhatsAppDirectoryConfig = createLazyRuntimeModule(() => import("./directory-config-Dijefxc3.js").then((n) => n.t));
654
- const loadWhatsAppChannelReactAction = createLazyRuntimeModule(() => import("./channel-react-action-Cd2qkLqp.js"));
607
+ const loadWhatsAppChannelReactAction = createLazyRuntimeModule(() => import("./channel-react-action-CYx128FS.js"));
655
608
  function resolveWhatsAppTargetInfo(raw) {
656
609
  const normalized = normalizeWhatsAppTarget(raw);
657
610
  if (!normalized) return null;
@@ -1,2 +1,2 @@
1
- import { t as whatsappPlugin } from "./channel-CLOhkP85.js";
1
+ import { t as whatsappPlugin } from "./channel-dHRyqWut.js";
2
2
  export { whatsappPlugin };
@@ -1,7 +1,7 @@
1
1
  import { a as resolveWhatsAppAccount, s as resolveWhatsAppMediaMaxBytes } from "./accounts-BMGM1RtF.js";
2
2
  import { c as normalizeWhatsAppTarget, t as isWhatsAppGroupJid } from "./normalize-target-bVWjgftN.js";
3
- import { r as resolveAuthorizedWhatsAppOutboundTarget, t as handleWhatsAppAction } from "./action-runtime-BdhkGtaP.js";
4
- import { t as sendMessageWhatsApp } from "./send-C4LG-Cl6.js";
3
+ import { r as resolveAuthorizedWhatsAppOutboundTarget, t as handleWhatsAppAction } from "./action-runtime-BbUDQ78g.js";
4
+ import { t as sendMessageWhatsApp } from "./send-DjMBLgiv.js";
5
5
  import "./normalize-Bxwqo-bW.js";
6
6
  import { jsonResult, readStringOrNumberParam, readStringParam as readStringParam$1, resolveReactionMessageId } from "openclaw/plugin-sdk/channel-actions";
7
7
  //#region extensions/whatsapp/src/channel-react-action.ts
@@ -1,9 +1,9 @@
1
1
  import { startWebLoginWithQr as startWebLoginWithQr$1, waitForWebLogin as waitForWebLogin$1 } from "./login-qr-runtime.js";
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-BrKb0mwT.js";
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-CZ22aNcV.js";
3
3
  import { t as getActiveWebListener$1 } from "./active-listener-CFwkn3ho.js";
4
- import { t as monitorWebChannel$1 } from "./monitor-D4R-fcMW.js";
5
- import { t as loginWeb$1 } from "./login-1yyBrXTL.js";
6
- import { whatsappSetupWizard as whatsappSetupWizard$1 } from "./setup-surface-Bt5mdv4D.js";
4
+ import { t as monitorWebChannel$1 } from "./monitor-NKzAEWeJ.js";
5
+ import { t as loginWeb$1 } from "./login-DygDn79y.js";
6
+ import { whatsappSetupWizard as whatsappSetupWizard$1 } from "./setup-surface-_Cid6xIf.js";
7
7
  //#region extensions/whatsapp/src/channel.runtime.ts
8
8
  function getActiveWebListener(...args) {
9
9
  return getActiveWebListener$1(...args);
@@ -1,9 +1,9 @@
1
1
  import "./accounts-BMGM1RtF.js";
2
- import { a as resolveWhatsAppGroupRequireMention, i as whatsappSetupWizardProxy, n as createWhatsAppPluginBase, o as resolveWhatsAppGroupToolPolicy, s as resolveWhatsAppGroupIntroHint, t as whatsappSetupAdapter } from "./setup-core-DAgAB2WU.js";
2
+ import { a as resolveWhatsAppGroupRequireMention, i as whatsappSetupWizardProxy, n as createWhatsAppPluginBase, o as resolveWhatsAppGroupToolPolicy, s as resolveWhatsAppGroupIntroHint, t as whatsappSetupAdapter } from "./setup-core-B9CAuPOB.js";
3
3
  import { t as detectWhatsAppLegacyStateMigrations } from "./state-migrations-D_BmQUR9.js";
4
4
  //#region extensions/whatsapp/src/channel.setup.ts
5
5
  async function isWhatsAppAuthConfigured(account) {
6
- const { readWebAuthState } = await import("./auth-store-BrKb0mwT.js").then((n) => n.i);
6
+ const { readWebAuthState } = await import("./auth-store-CZ22aNcV.js").then((n) => n.i);
7
7
  return await readWebAuthState(account.authDir) === "linked";
8
8
  }
9
9
  const whatsappSetupPlugin = {
@@ -1,6 +1,6 @@
1
1
  import { a as unregisterWhatsAppConnectionController, i as registerWhatsAppConnectionController, n as getStatusCode, t as formatError } from "./session-errors-CbsoQqoy.js";
2
- import { c as logoutWeb } from "./auth-store-BrKb0mwT.js";
3
- import { r as waitForWaConnection, t as createWaSocket } from "./session-D8UW2Vbn.js";
2
+ import { c as logoutWeb } from "./auth-store-CZ22aNcV.js";
3
+ import { r as waitForWaConnection, t as createWaSocket } from "./session-DyGWNClj.js";
4
4
  import { computeBackoff, info, sleepWithAbort } from "openclaw/plugin-sdk/runtime-env";
5
5
  import { clamp } from "openclaw/plugin-sdk/text-utility-runtime";
6
6
  import { DisconnectReason } from "baileys";
@@ -38,13 +38,24 @@ function newConnectionId() {
38
38
  //#endregion
39
39
  //#region extensions/whatsapp/src/connection-controller.ts
40
40
  const LOGGED_OUT_STATUS = DisconnectReason?.loggedOut ?? 401;
41
+ const POST_PAIRING_RESTART_STATUS = 515;
42
+ const TIMED_OUT_STATUS = DisconnectReason?.timedOut ?? 408;
41
43
  const WHATSAPP_LOGIN_RESTART_MESSAGE = "WhatsApp asked for a restart after pairing (code 515); waiting for creds to save…";
44
+ const WHATSAPP_LOGIN_TIMEOUT_RESTART_MESSAGE = "WhatsApp connection timed out before login; retrying with a fresh socket…";
42
45
  const WHATSAPP_LOGGED_OUT_RELINK_MESSAGE = "WhatsApp reported the session is logged out. Cleared cached web session; please rerun openclaw channels login and scan the QR again.";
43
46
  const WHATSAPP_LOGGED_OUT_QR_MESSAGE = "WhatsApp reported the session is logged out. Cleared cached web session; please scan a new QR.";
44
47
  const WHATSAPP_WATCHDOG_TIMEOUT_ERROR = "watchdog-timeout";
45
48
  function createNeverResolvePromise() {
46
49
  return new Promise(() => {});
47
50
  }
51
+ function getLoginSocketRestartKind(statusCode) {
52
+ if (statusCode === POST_PAIRING_RESTART_STATUS) return "post-pairing";
53
+ if (statusCode === TIMED_OUT_STATUS) return "timeout";
54
+ return null;
55
+ }
56
+ function getLoginSocketRestartMessage(kind) {
57
+ return kind === "timeout" ? WHATSAPP_LOGIN_TIMEOUT_RESTART_MESSAGE : WHATSAPP_LOGIN_RESTART_MESSAGE;
58
+ }
48
59
  function createLiveConnection(params) {
49
60
  let closeResolved = false;
50
61
  let resolveClosePromise = (_reason) => {};
@@ -91,19 +102,22 @@ async function waitForWhatsAppLoginResult(params) {
91
102
  const wait = params.waitForConnection ?? waitForWaConnection;
92
103
  const createSocket = params.createSocket ?? createWaSocket;
93
104
  let currentSock = params.sock;
94
- let restarted = false;
105
+ let postPairingRestarted = false;
106
+ let timeoutRestarted = false;
95
107
  while (true) try {
96
108
  await wait(currentSock);
97
109
  return {
98
110
  outcome: "connected",
99
- restarted,
111
+ restarted: postPairingRestarted || timeoutRestarted,
100
112
  sock: currentSock
101
113
  };
102
114
  } catch (err) {
103
115
  const statusCode = getStatusCode(err);
104
- if (statusCode === 515 && !restarted) {
105
- restarted = true;
106
- params.runtime.log(info(WHATSAPP_LOGIN_RESTART_MESSAGE));
116
+ const restartKind = getLoginSocketRestartKind(statusCode);
117
+ if (restartKind && (restartKind === "post-pairing" && !postPairingRestarted || restartKind === "timeout" && !timeoutRestarted)) {
118
+ if (restartKind === "post-pairing") postPairingRestarted = true;
119
+ else timeoutRestarted = true;
120
+ params.runtime.log(info(getLoginSocketRestartMessage(restartKind)));
107
121
  closeWaSocket(currentSock);
108
122
  try {
109
123
  currentSock = await createSocket(false, params.verbose, {
@@ -1,5 +1,5 @@
1
1
  import { n as getStatusCode, t as formatError } from "./session-errors-CbsoQqoy.js";
2
2
  import { t as createWhatsAppLoginTool } from "./agent-tools-login-BX7eHgDm.js";
3
- import { c as logoutWeb, g as readWebSelfId, l as pickWebChannel, o as getWebAuthAgeMs, s as logWebSelfId, t as WA_WEB_AUTH_DIR, x as webAuthExists, y as resolveDefaultWebAuthDir } from "./auth-store-BrKb0mwT.js";
3
+ import { c as logoutWeb, g as readWebSelfId, l as pickWebChannel, o as getWebAuthAgeMs, s as logWebSelfId, t as WA_WEB_AUTH_DIR, x as webAuthExists, y as resolveDefaultWebAuthDir } from "./auth-store-CZ22aNcV.js";
4
4
  import { t as getActiveWebListener } from "./active-listener-CFwkn3ho.js";
5
5
  export { WA_WEB_AUTH_DIR, createWhatsAppLoginTool, formatError, getActiveWebListener, getStatusCode, getWebAuthAgeMs, logWebSelfId, logoutWeb, pickWebChannel, readWebSelfId, resolveDefaultWebAuthDir, webAuthExists };
@@ -1,8 +1,8 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
2
  import { a as resolveWhatsAppAccount } from "./accounts-BMGM1RtF.js";
3
- import { b as restoreCredsFromBackupIfNeeded } from "./auth-store-BrKb0mwT.js";
4
- import { a as renderQrTerminal, i as resolveWhatsAppSocketTiming, t as createWaSocket } from "./session-D8UW2Vbn.js";
5
- import { a as closeWaSocketSoon, o as waitForWhatsAppLoginResult } from "./connection-controller-BZuzYCGM.js";
3
+ import { b as restoreCredsFromBackupIfNeeded } from "./auth-store-CZ22aNcV.js";
4
+ import { a as renderQrTerminal, i as resolveWhatsAppSocketTiming, t as createWaSocket } from "./session-DyGWNClj.js";
5
+ import { a as closeWaSocketSoon, o as waitForWhatsAppLoginResult } from "./connection-controller-Bnm4INld.js";
6
6
  import { formatCliCommand } from "openclaw/plugin-sdk/cli-runtime";
7
7
  import { logInfo } from "openclaw/plugin-sdk/logging-core";
8
8
  import { danger, defaultRuntime, success } from "openclaw/plugin-sdk/runtime-env";
@@ -1,10 +1,11 @@
1
1
  import { a as resolveWhatsAppAccount } from "./accounts-BMGM1RtF.js";
2
- import { f as readWebAuthExistsForDecision, g as readWebSelfId, n as WHATSAPP_AUTH_UNSTABLE_CODE } from "./auth-store-BrKb0mwT.js";
3
- import { i as resolveWhatsAppSocketTiming, t as createWaSocket } from "./session-D8UW2Vbn.js";
4
- import { i as closeWaSocket, o as waitForWhatsAppLoginResult, t as WHATSAPP_LOGGED_OUT_QR_MESSAGE } from "./connection-controller-BZuzYCGM.js";
2
+ import { f as readWebAuthExistsForDecision, g as readWebSelfId, n as WHATSAPP_AUTH_UNSTABLE_CODE } from "./auth-store-CZ22aNcV.js";
3
+ import { i as resolveWhatsAppSocketTiming, t as createWaSocket } from "./session-DyGWNClj.js";
4
+ import { i as closeWaSocket, o as waitForWhatsAppLoginResult, t as WHATSAPP_LOGGED_OUT_QR_MESSAGE } from "./connection-controller-Bnm4INld.js";
5
5
  import { logInfo } from "openclaw/plugin-sdk/logging-core";
6
6
  import { danger, defaultRuntime, info, success } from "openclaw/plugin-sdk/runtime-env";
7
7
  import { renderQrPngDataUrl } from "openclaw/plugin-sdk/media-runtime";
8
+ import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
8
9
  import { randomUUID } from "node:crypto";
9
10
  import { getRuntimeConfig } from "openclaw/plugin-sdk/runtime-config-snapshot";
10
11
  //#region extensions/whatsapp/src/login-qr.ts
@@ -14,6 +15,9 @@ function waitForNextTask() {
14
15
  const ACTIVE_LOGIN_TTL_MS = 3 * 6e4;
15
16
  const MAX_QR_RENDER_CHASES = 10;
16
17
  const activeLogins = /* @__PURE__ */ new Map();
18
+ function resolveWhatsAppLoginTimeoutMs(value, fallbackMs, minMs) {
19
+ return resolveTimerTimeoutMs(value, fallbackMs, minMs);
20
+ }
17
21
  function closeSocket(sock) {
18
22
  closeWaSocket(sock);
19
23
  }
@@ -90,6 +94,7 @@ function attachLoginWaiter(accountId, login) {
90
94
  const current = activeLogins.get(accountId);
91
95
  if (!current || current.id !== login.id) return;
92
96
  const qrVersion = updateLoginQrState(current, qr);
97
+ notifyQrUpdate(current);
93
98
  renderLatestQrDataUrlInBackground({
94
99
  accountId,
95
100
  loginId: login.id,
@@ -152,7 +157,27 @@ async function waitForQrOrRecoveredLogin(params) {
152
157
  message: latest.error ? `WhatsApp login failed: ${latest.error}` : "WhatsApp login failed."
153
158
  };
154
159
  });
155
- return await Promise.race([qrResult, loginResult]);
160
+ const qrUpdateResult = params.login.qrUpdatePromise.then(() => {
161
+ const current = activeLogins.get(params.accountId);
162
+ if (current?.id !== params.login.id) return {
163
+ outcome: "failed",
164
+ message: "WhatsApp login was replaced by a newer request."
165
+ };
166
+ if (current.qr) return {
167
+ outcome: "qr",
168
+ qr: current.qr
169
+ };
170
+ if (current.connected) return { outcome: "connected" };
171
+ return {
172
+ outcome: "failed",
173
+ message: current.error ? `WhatsApp login failed: ${current.error}` : "WhatsApp QR update ended without an active QR."
174
+ };
175
+ });
176
+ return await Promise.race([
177
+ qrResult,
178
+ loginResult,
179
+ qrUpdateResult
180
+ ]);
156
181
  }
157
182
  async function startWebLoginWithQr(opts = {}) {
158
183
  const runtime = opts.runtime ?? defaultRuntime;
@@ -185,7 +210,7 @@ async function startWebLoginWithQr(opts = {}) {
185
210
  });
186
211
  const qrTimer = setTimeout(() => {
187
212
  rejectQr?.(/* @__PURE__ */ new Error("Timed out waiting for WhatsApp QR"));
188
- }, Math.max(opts.timeoutMs ?? 3e4, 5e3));
213
+ }, resolveWhatsAppLoginTimeoutMs(opts.timeoutMs, 3e4, 5e3));
189
214
  let sock;
190
215
  let pendingQr = null;
191
216
  const loginId = randomUUID();
@@ -310,7 +335,7 @@ async function waitForWebLogin(opts = {}) {
310
335
  message: "The login QR expired. Ask me to generate a new one."
311
336
  };
312
337
  }
313
- const timeoutMs = Math.max(opts.timeoutMs ?? 12e4, 1e3);
338
+ const timeoutMs = resolveWhatsAppLoginTimeoutMs(opts.timeoutMs, 12e4, 1e3);
314
339
  const deadline = Date.now() + timeoutMs;
315
340
  const currentQrDataUrl = opts.currentQrDataUrl;
316
341
  while (true) {
@@ -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-6DdwGlkz.js");
4
+ loginQrModulePromise ??= import("./login-qr-nPxKvdjP.js");
5
5
  return loginQrModulePromise;
6
6
  }
7
7
  async function startWebLoginWithQr(...args) {
@@ -1,18 +1,18 @@
1
1
  import { a as resolveWhatsAppAccount, s as resolveWhatsAppMediaMaxBytes } from "./accounts-BMGM1RtF.js";
2
2
  import { t as isWhatsAppGroupJid } from "./normalize-target-bVWjgftN.js";
3
- import { a as normalizeWhatsAppOutboundPayload, c as prepareWhatsAppOutboundMedia, d as maybeResolveWhatsAppApprovalReaction, g as resolveWhatsAppReactionLevel, l as sendWhatsAppOutboundWithRetry, r as sendReactionWhatsApp, s as normalizeWhatsAppPayloadTextPreservingIndentation } from "./send-C4LG-Cl6.js";
3
+ import { a as normalizeWhatsAppOutboundPayload, c as prepareWhatsAppOutboundMedia, d as maybeResolveWhatsAppApprovalReaction, g as resolveWhatsAppReactionLevel, l as sendWhatsAppOutboundWithRetry, r as sendReactionWhatsApp, s as normalizeWhatsAppPayloadTextPreservingIndentation } from "./send-DjMBLgiv.js";
4
4
  import { n as getWhatsAppRuntime } from "./runtime-BfAdAEYT.js";
5
5
  import { n as getStatusCode, t as formatError } from "./session-errors-CbsoQqoy.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-Dk37KYHj.js";
7
7
  import { n as cacheInboundMessageMeta, r as lookupInboundMessageMeta, t as buildQuotedMessageOptions } from "./quoted-message-CveINB35.js";
8
- import { c as logoutWeb, g as readWebSelfId, o as getWebAuthAgeMs, r as WhatsAppAuthUnstableError, v as readWebSelfIdentityForDecision } from "./auth-store-BrKb0mwT.js";
8
+ import { c as logoutWeb, g as readWebSelfId, o as getWebAuthAgeMs, r as WhatsAppAuthUnstableError, v as readWebSelfIdentityForDecision } from "./auth-store-CZ22aNcV.js";
9
9
  import { a as getSelfIdentity, c as resolveComparableIdentity, i as getReplyContext, n as getMentionIdentities, o as getSenderIdentity, r as getPrimaryIdentityId, s as identitiesOverlap, t as getComparableIdentityValues } from "./identity-xoLLdqEv.js";
10
10
  import { n as resolveWhatsAppGroupsConfigPath } from "./group-config-path-BGyzT9Lg.js";
11
11
  import { i as resolveWhatsAppInboundPolicy, r as resolveWhatsAppCommandAuthorized, t as checkInboundAccessControl } from "./access-control-Z0fYaWrx.js";
12
- import { a as mayContainWhatsAppOutboundMention, c as describeReplyContext, d as extractLocationData, f as extractMediaPlaceholder, h as hasInboundUserContent, i as addWhatsAppOutboundMentionsToContent, l as extractContactContext, m as extractText, n as listWhatsAppSendResultMessageIds, o as resolveWhatsAppOutboundMentions, p as extractMentionedJids, r as normalizeWhatsAppSendResult, s as addWhatsAppImagePreviewFields, t as createWebSendApi, u as extractContextInfo } from "./send-api-C66vkRl9.js";
13
- import { i as resolveWhatsAppSocketTiming, r as waitForWaConnection, t as createWaSocket } from "./session-D8UW2Vbn.js";
12
+ import { a as mayContainWhatsAppOutboundMention, c as describeReplyContext, d as extractLocationData, f as extractMediaPlaceholder, h as hasInboundUserContent, i as addWhatsAppOutboundMentionsToContent, l as extractContactContext, m as extractText, n as listWhatsAppSendResultMessageIds, o as resolveWhatsAppOutboundMentions, p as extractMentionedJids, r as normalizeWhatsAppSendResult, s as addWhatsAppImagePreviewFields, t as createWebSendApi, u as extractContextInfo } from "./send-api-Cx2qeYqj.js";
13
+ import { i as resolveWhatsAppSocketTiming, r as waitForWaConnection, t as createWaSocket } from "./session-DyGWNClj.js";
14
14
  import { t as BufferJSON } from "./session.runtime-LZFdq3yb.js";
15
- 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-BZuzYCGM.js";
15
+ 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-Bnm4INld.js";
16
16
  import { resolveAccountEntry } from "openclaw/plugin-sdk/account-core";
17
17
  import { normalizeLowercaseStringOrEmpty, normalizeStringEntries, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
18
18
  import { createChannelMessageReplyPipeline, createDurableInboundReceiveJournal, createMessageReceiptFromOutboundResults, deliverInboundReplyWithMessageSendContext, resolveChannelMessageSourceReplyDeliveryMode } from "openclaw/plugin-sdk/channel-outbound";
@@ -24,9 +24,10 @@ import { resolveMarkdownTableMode as resolveMarkdownTableMode$1 } from "openclaw
24
24
  import { createSubsystemLogger, defaultRuntime, formatDurationPrecise, getChildLogger as getChildLogger$1, logVerbose, logVerbose as logVerbose$1, registerUnhandledRejectionHandler, shouldLogVerbose, shouldLogVerbose as shouldLogVerbose$1, warn } from "openclaw/plugin-sdk/runtime-env";
25
25
  import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime";
26
26
  import { LocalMediaAccessError, getDefaultLocalRoots, loadWebMedia as loadWebMedia$1, loadWebMediaRaw, optimizeImageToJpeg, optimizeImageToPng } from "openclaw/plugin-sdk/web-media";
27
- import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, DEFAULT_MAIN_KEY, buildAgentMainSessionKey, buildAgentSessionKey, buildGroupHistoryKey, deriveLastRoutePolicy, normalizeAccountId as normalizeAccountId$1, normalizeAgentId, resolveAgentRoute, resolveInboundLastRouteSessionKey, resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
28
27
  import { chunkMarkdownTextWithMode } from "openclaw/plugin-sdk/reply-chunking";
29
28
  import { isReasoningReplyPayload, resolveSendableOutboundReplyParts, sendMediaWithLeadingCaption } from "openclaw/plugin-sdk/reply-payload";
29
+ import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, DEFAULT_MAIN_KEY, buildAgentMainSessionKey, buildAgentSessionKey, buildGroupHistoryKey, deriveLastRoutePolicy, normalizeAccountId as normalizeAccountId$1, normalizeAgentId, resolveAgentRoute, resolveInboundLastRouteSessionKey, resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
30
+ import { asDateTimestampMs, parseStrictFiniteNumber, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
30
31
  import { recordInboundSession } from "openclaw/plugin-sdk/conversation-runtime";
31
32
  import { loadSessionStore, resolveStorePath, updateLastRoute, updateSessionStore } from "openclaw/plugin-sdk/session-store-runtime";
32
33
  import { DisconnectReason as DisconnectReason$1, downloadMediaMessage, isJidGroup, normalizeMessageContent as normalizeMessageContent$1 } from "baileys";
@@ -41,7 +42,6 @@ import { hasControlCommand, isControlCommandMessage, isControlCommandMessage as
41
42
  import { drainPendingDeliveries } from "openclaw/plugin-sdk/delivery-queue-runtime";
42
43
  import { DEFAULT_GROUP_HISTORY_LIMIT, buildHistoryContextFromEntries, buildInboundHistoryFromEntries, createChannelHistoryWindow } from "openclaw/plugin-sdk/reply-history";
43
44
  import { enqueueSystemEvent } from "openclaw/plugin-sdk/system-event-runtime";
44
- import { parseStrictFiniteNumber } from "openclaw/plugin-sdk/number-runtime";
45
45
  import { createClaimableDedupe } from "openclaw/plugin-sdk/persistent-dedupe";
46
46
  import { saveMediaStream } from "openclaw/plugin-sdk/media-store";
47
47
  import { getRuntimeConfig as getRuntimeConfig$1, getRuntimeConfigSourceSnapshot } from "openclaw/plugin-sdk/runtime-config-snapshot";
@@ -263,6 +263,10 @@ const LOGGED_OUT_STATUS = DisconnectReason$1?.loggedOut ?? 401;
263
263
  const RECONNECT_IN_PROGRESS_ERROR = "no active socket - reconnection in progress";
264
264
  const GROUP_META_TTL_MS = 300 * 1e3;
265
265
  const INBOUND_CLOSE_DRAIN_TIMEOUT_MS = 5e3;
266
+ function resolveGroupMetadataExpiresAt(nowRaw = Date.now()) {
267
+ const now = asDateTimestampMs(nowRaw);
268
+ return now === void 0 ? void 0 : resolveExpiresAtMsFromDurationMs(GROUP_META_TTL_MS, { nowMs: now });
269
+ }
266
270
  function parseWhatsAppTimestampSeconds(value) {
267
271
  if (value == null) return;
268
272
  if (typeof value === "string") return parseStrictFiniteNumber(value);
@@ -270,6 +274,10 @@ function parseWhatsAppTimestampSeconds(value) {
270
274
  return Number.isFinite(parsed) ? parsed : void 0;
271
275
  }
272
276
  function rememberGroupMetadataCacheEntry(cache, jid, entry) {
277
+ if (asDateTimestampMs(entry.expires) === void 0) {
278
+ cache.delete(jid);
279
+ return;
280
+ }
273
281
  if (cache.has(jid)) cache.delete(jid);
274
282
  cache.set(jid, entry);
275
283
  while (cache.size > 500) {
@@ -281,7 +289,9 @@ function rememberGroupMetadataCacheEntry(cache, jid, entry) {
281
289
  function readGroupMetadataCacheEntry(cache, jid) {
282
290
  const entry = cache.get(jid);
283
291
  if (!entry) return null;
284
- if (entry.expires <= Date.now()) {
292
+ const now = asDateTimestampMs(Date.now());
293
+ const expires = asDateTimestampMs(entry.expires);
294
+ if (now === void 0 || expires === void 0 || expires <= now) {
285
295
  cache.delete(jid);
286
296
  return null;
287
297
  }
@@ -477,12 +487,12 @@ async function attachWebInboxToSocket(options) {
477
487
  subject: meta.subject,
478
488
  participants,
479
489
  mentionParticipants,
480
- expires: Date.now() + GROUP_META_TTL_MS
490
+ expires: resolveGroupMetadataExpiresAt() ?? 0
481
491
  };
482
492
  };
483
493
  const summarizeGroupMetaForReconnectCache = (meta) => ({
484
494
  subject: meta.subject,
485
- expires: Date.now() + GROUP_META_TTL_MS
495
+ expires: resolveGroupMetadataExpiresAt() ?? NaN
486
496
  });
487
497
  const getGroupMeta = async (jid) => {
488
498
  const cached = readGroupMetadataCacheEntry(groupMetaCache, jid);
@@ -503,7 +513,7 @@ async function attachWebInboxToSocket(options) {
503
513
  return hydrated;
504
514
  }
505
515
  logWhatsAppVerbose(options.verbose, `Failed to fetch group metadata for ${jid}: ${String(err)}`);
506
- return { expires: Date.now() + GROUP_META_TTL_MS };
516
+ return { expires: resolveGroupMetadataExpiresAt() ?? 0 };
507
517
  }
508
518
  };
509
519
  const resolveOutboundMentionsForGroup = async (jid, text) => {
@@ -1,16 +1,16 @@
1
1
  import { o as resolveWebCredsBackupPath, r as hasWebCredsSync, s as resolveWebCredsPath } from "./creds-files-B1kSWtBg.js";
2
- import { n as whatsAppActionRuntime, t as handleWhatsAppAction } from "./action-runtime-BdhkGtaP.js";
3
- import { i as sendTypingWhatsApp, n as sendPollWhatsApp, r as sendReactionWhatsApp, t as sendMessageWhatsApp } from "./send-C4LG-Cl6.js";
2
+ import { n as whatsAppActionRuntime, t as handleWhatsAppAction } from "./action-runtime-BbUDQ78g.js";
3
+ import { i as sendTypingWhatsApp, n as sendPollWhatsApp, r as sendReactionWhatsApp, t as sendMessageWhatsApp } from "./send-DjMBLgiv.js";
4
4
  import { r as setWhatsAppRuntime } from "./runtime-BfAdAEYT.js";
5
5
  import { n as getStatusCode, t as formatError } from "./session-errors-CbsoQqoy.js";
6
6
  import { startWebLoginWithQr, waitForWebLogin } from "./login-qr-runtime.js";
7
7
  import { t as createWhatsAppLoginTool } from "./agent-tools-login-BX7eHgDm.js";
8
- import { C as waitForCredsSaveQueue, T as writeCredsJsonAtomically, _ as readWebSelfIdentity, a as formatWhatsAppWebAuthStatusState, b as restoreCredsFromBackupIfNeeded, c as logoutWeb, d as readWebAuthExistsBestEffort, f as readWebAuthExistsForDecision, g as readWebSelfId, h as readWebAuthState, l as pickWebChannel, m as readWebAuthSnapshotBestEffort, n as WHATSAPP_AUTH_UNSTABLE_CODE, o as getWebAuthAgeMs, p as readWebAuthSnapshot, r as WhatsAppAuthUnstableError, s as logWebSelfId, t as WA_WEB_AUTH_DIR, u as readCredsJsonRaw, v as readWebSelfIdentityForDecision, w as waitForCredsSaveQueueWithTimeout, x as webAuthExists, y as resolveDefaultWebAuthDir } from "./auth-store-BrKb0mwT.js";
8
+ import { C as waitForCredsSaveQueue, T as writeCredsJsonAtomically, _ as readWebSelfIdentity, a as formatWhatsAppWebAuthStatusState, b as restoreCredsFromBackupIfNeeded, c as logoutWeb, d as readWebAuthExistsBestEffort, f as readWebAuthExistsForDecision, g as readWebSelfId, h as readWebAuthState, l as pickWebChannel, m as readWebAuthSnapshotBestEffort, n as WHATSAPP_AUTH_UNSTABLE_CODE, o as getWebAuthAgeMs, p as readWebAuthSnapshot, r as WhatsAppAuthUnstableError, s as logWebSelfId, t as WA_WEB_AUTH_DIR, u as readCredsJsonRaw, v as readWebSelfIdentityForDecision, w as waitForCredsSaveQueueWithTimeout, x as webAuthExists, y as resolveDefaultWebAuthDir } from "./auth-store-CZ22aNcV.js";
9
9
  import { t as DEFAULT_WEB_MEDIA_BYTES } from "./constants-HU41RHGI.js";
10
- import { d as extractLocationData, f as extractMediaPlaceholder, l as extractContactContext, m as extractText } from "./send-api-C66vkRl9.js";
11
- import { n as newConnectionId, r as waitForWaConnection, t as createWaSocket } from "./session-D8UW2Vbn.js";
10
+ import { d as extractLocationData, f as extractMediaPlaceholder, l as extractContactContext, m as extractText } from "./send-api-Cx2qeYqj.js";
11
+ import { n as newConnectionId, r as waitForWaConnection, t as createWaSocket } from "./session-DyGWNClj.js";
12
12
  import { n as resolveWebAccountId, t as getActiveWebListener } from "./active-listener-CFwkn3ho.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-D4R-fcMW.js";
14
- import { t as loginWeb } from "./login-1yyBrXTL.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-NKzAEWeJ.js";
14
+ import { t as loginWeb } from "./login-DygDn79y.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 };
@@ -472,6 +472,29 @@ const outboundLog = createSubsystemLogger("gateway/channels/whatsapp").child("ou
472
472
  function supportsForcedDocumentDelivery(kind) {
473
473
  return kind === "image" || kind === "video";
474
474
  }
475
+ function buildWhatsAppMediaSendState(params) {
476
+ const { media, caption } = params;
477
+ const forceDocumentDelivery = Boolean(params.forceDocument && supportsForcedDocumentDelivery(media.kind));
478
+ let text = caption ?? "";
479
+ let documentFileName = media.kind === "document" ? media.fileName : void 0;
480
+ let visibleTextAfterVoice;
481
+ if (media.kind === "audio" && caption) {
482
+ visibleTextAfterVoice = caption;
483
+ text = "";
484
+ }
485
+ if (forceDocumentDelivery) documentFileName ??= resolveWhatsAppDocumentFileName({
486
+ fileName: media.fileName,
487
+ mimetype: media.mimetype
488
+ });
489
+ return {
490
+ mediaBuffer: media.buffer,
491
+ mediaType: media.mimetype,
492
+ text,
493
+ forceDocumentDelivery,
494
+ ...documentFileName ? { documentFileName } : {},
495
+ ...visibleTextAfterVoice ? { visibleTextAfterVoice } : {}
496
+ };
497
+ }
475
498
  function resolveOutboundWhatsAppAccountId(params) {
476
499
  const explicitAccountId = params.accountId?.trim();
477
500
  if (explicitAccountId) return explicitAccountId;
@@ -535,46 +558,27 @@ async function sendMessageWhatsApp(to, body, options) {
535
558
  let documentFileName;
536
559
  let visibleTextAfterVoice;
537
560
  let forceDocumentDelivery = false;
538
- if (mediaPayload) {
539
- const media = await prepareWhatsAppOutboundMedia(mediaPayload, primaryMediaUrl);
540
- const caption = text || void 0;
541
- mediaBuffer = media.buffer;
542
- mediaType = media.mimetype;
543
- forceDocumentDelivery = Boolean(options.forceDocument && supportsForcedDocumentDelivery(media.kind));
544
- if (media.kind === "audio" && caption) {
545
- visibleTextAfterVoice = caption;
546
- text = "";
547
- } else if (media.kind === "document") {
548
- text = caption ?? "";
549
- documentFileName = media.fileName;
550
- } else text = caption ?? "";
551
- if (forceDocumentDelivery) documentFileName ??= resolveWhatsAppDocumentFileName({
552
- fileName: media.fileName,
553
- mimetype: media.mimetype
554
- });
555
- } else if (primaryMediaUrl) {
556
- const media = await prepareWhatsAppOutboundMedia(await loadOutboundMediaFromUrl(primaryMediaUrl, {
557
- maxBytes: resolveWhatsAppMediaMaxBytes(account),
558
- optimizeImages: options.forceDocument ? false : void 0,
559
- mediaAccess: options.mediaAccess,
560
- mediaLocalRoots: options.mediaLocalRoots,
561
- mediaReadFile: options.mediaReadFile
562
- }), primaryMediaUrl);
563
- const caption = text || void 0;
564
- mediaBuffer = media.buffer;
565
- mediaType = media.mimetype;
566
- forceDocumentDelivery = Boolean(options.forceDocument && supportsForcedDocumentDelivery(media.kind));
567
- if (media.kind === "audio" && caption) {
568
- visibleTextAfterVoice = caption;
569
- text = "";
570
- } else if (media.kind === "document") {
571
- text = caption ?? "";
572
- documentFileName = media.fileName;
573
- } else text = caption ?? "";
574
- if (forceDocumentDelivery) documentFileName ??= resolveWhatsAppDocumentFileName({
575
- fileName: media.fileName,
576
- mimetype: media.mimetype
561
+ let media;
562
+ if (mediaPayload) media = await prepareWhatsAppOutboundMedia(mediaPayload, primaryMediaUrl);
563
+ else if (primaryMediaUrl) media = await prepareWhatsAppOutboundMedia(await loadOutboundMediaFromUrl(primaryMediaUrl, {
564
+ maxBytes: resolveWhatsAppMediaMaxBytes(account),
565
+ optimizeImages: options.forceDocument ? false : void 0,
566
+ mediaAccess: options.mediaAccess,
567
+ mediaLocalRoots: options.mediaLocalRoots,
568
+ mediaReadFile: options.mediaReadFile
569
+ }), primaryMediaUrl);
570
+ if (media) {
571
+ const mediaSendState = buildWhatsAppMediaSendState({
572
+ media,
573
+ caption: text || void 0,
574
+ forceDocument: options.forceDocument
577
575
  });
576
+ mediaBuffer = mediaSendState.mediaBuffer;
577
+ mediaType = mediaSendState.mediaType;
578
+ documentFileName = mediaSendState.documentFileName;
579
+ visibleTextAfterVoice = mediaSendState.visibleTextAfterVoice;
580
+ forceDocumentDelivery = mediaSendState.forceDocumentDelivery;
581
+ text = mediaSendState.text;
578
582
  }
579
583
  outboundLog.info(`Sending message -> ${redactedJid}${hasMedia ? " (media)" : ""}`);
580
584
  logger.info({
@@ -1,5 +1,5 @@
1
1
  import { n as isWhatsAppNewsletterJid } from "./normalize-target-bVWjgftN.js";
2
- import { u as resolveWhatsAppDocumentFileName } from "./send-C4LG-Cl6.js";
2
+ import { u as resolveWhatsAppDocumentFileName } from "./send-DjMBLgiv.js";
3
3
  import "./normalize-Bxwqo-bW.js";
4
4
  import { m as toWhatsappJidWithLid, p as toWhatsappJid, u as jidToE164 } from "./text-runtime-Dk37KYHj.js";
5
5
  import { t as buildQuotedMessageOptions } from "./quoted-message-CveINB35.js";
@@ -1,6 +1,6 @@
1
1
  import { o as resolveWebCredsBackupPath, s as resolveWebCredsPath, t as assertWebCredsPathRegularFileOrMissing } from "./creds-files-B1kSWtBg.js";
2
2
  import { n as getStatusCode } from "./session-errors-CbsoQqoy.js";
3
- import { E as writeWebCredsRawAtomically, S as enqueueCredsSave, T as writeCredsJsonAtomically, b as restoreCredsFromBackupIfNeeded, u as readCredsJsonRaw, w as waitForCredsSaveQueueWithTimeout, y as resolveDefaultWebAuthDir } from "./auth-store-BrKb0mwT.js";
3
+ import { E as writeWebCredsRawAtomically, S as enqueueCredsSave, T as writeCredsJsonAtomically, b as restoreCredsFromBackupIfNeeded, u as readCredsJsonRaw, w as waitForCredsSaveQueueWithTimeout, y as resolveDefaultWebAuthDir } from "./auth-store-CZ22aNcV.js";
4
4
  import { a as makeWASocket, i as makeCacheableSignalKeyStore, n as DisconnectReason, r as fetchLatestBaileysVersion, s as useMultiFileAuthState } from "./session.runtime-LZFdq3yb.js";
5
5
  import { VERSION, formatCliCommand } from "openclaw/plugin-sdk/cli-runtime";
6
6
  import { danger, getChildLogger, success, toPinoLikeLogger } from "openclaw/plugin-sdk/runtime-env";
@@ -99,10 +99,10 @@ async function applyWhatsAppSecurityConfigFixes(params) {
99
99
  //#region extensions/whatsapp/src/shared.ts
100
100
  const WHATSAPP_CHANNEL = "whatsapp";
101
101
  async function loadWhatsAppChannelRuntime() {
102
- return await import("./channel.runtime-CcGhK_F2.js");
102
+ return await import("./channel.runtime-3WElbRZG.js");
103
103
  }
104
104
  async function loadWhatsAppSetupSurface() {
105
- return await import("./setup-surface-Bt5mdv4D.js");
105
+ return await import("./setup-surface-_Cid6xIf.js");
106
106
  }
107
107
  const whatsappSetupWizardProxy = createWhatsAppSetupWizardProxy(async () => (await loadWhatsAppSetupSurface()).whatsappSetupWizard);
108
108
  const whatsappConfigAdapter = createScopedChannelConfigAdapter({
@@ -2,7 +2,7 @@ import { r as resolveDefaultWhatsAppAccountId } from "./account-ids-CB5SOWjc.js"
2
2
  import { r as hasWebCredsSync } from "./creds-files-B1kSWtBg.js";
3
3
  import { a as resolveWhatsAppAccount, o as resolveWhatsAppAuthDir } from "./accounts-BMGM1RtF.js";
4
4
  import { a as normalizeWhatsAppAllowFromEntries, o as normalizeWhatsAppAllowFromEntry } from "./normalize-target-bVWjgftN.js";
5
- import { t as whatsappSetupAdapter } from "./setup-core-DAgAB2WU.js";
5
+ import { t as whatsappSetupAdapter } from "./setup-core-B9CAuPOB.js";
6
6
  import { DEFAULT_ACCOUNT_ID, createSetupTranslator, splitSetupEntries } from "openclaw/plugin-sdk/setup";
7
7
  import { formatCliCommand, formatDocsLink } from "openclaw/plugin-sdk/setup-tools";
8
8
  //#region extensions/whatsapp/src/setup-finalize.ts
@@ -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-1yyBrXTL.js").then((n) => n.n);
283
+ const { loginWeb } = await import("./login-DygDn79y.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-COV8culQ.js";
1
+ import { t as whatsappSetupPlugin } from "./channel.setup-BuSd1d1D.js";
2
2
  export { whatsappSetupPlugin };
@@ -1,6 +1,6 @@
1
1
  import { t as listAccountIds } from "./account-ids-CB5SOWjc.js";
2
2
  import { o as resolveWhatsAppAuthDir } from "./accounts-BMGM1RtF.js";
3
- import { a as formatWhatsAppWebAuthStatusState, h as readWebAuthState } from "./auth-store-BrKb0mwT.js";
3
+ import { a as formatWhatsAppWebAuthStatusState, h as readWebAuthState } from "./auth-store-CZ22aNcV.js";
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-CDPy4WyU.js")).finalizeWhatsAppSetup(params),
39
+ finalize: async (params) => await (await import("./setup-finalize-f95kxYvv.js")).finalizeWhatsAppSetup(params),
40
40
  disable: (cfg) => setSetupChannelEnabled(cfg, channel, false),
41
41
  onAccountRecorded: (accountId, options) => {
42
42
  options?.onAccountId?.(channel, accountId);
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "@openclaw/whatsapp",
3
- "version": "2026.5.28-beta.4",
3
+ "version": "2026.5.30-beta.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@openclaw/whatsapp",
9
- "version": "2026.5.28-beta.4",
9
+ "version": "2026.5.30-beta.1",
10
10
  "dependencies": {
11
11
  "audio-decode": "2.2.3",
12
12
  "baileys": "7.0.0-rc13",
13
13
  "typebox": "1.1.38"
14
14
  },
15
15
  "peerDependencies": {
16
- "openclaw": ">=2026.5.28-beta.4"
16
+ "openclaw": ">=2026.5.30-beta.1"
17
17
  },
18
18
  "peerDependenciesMeta": {
19
19
  "openclaw": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/whatsapp",
3
- "version": "2026.5.28-beta.4",
3
+ "version": "2026.5.30-beta.1",
4
4
  "description": "OpenClaw WhatsApp channel plugin for WhatsApp Web chats.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -13,7 +13,7 @@
13
13
  "typebox": "1.1.38"
14
14
  },
15
15
  "peerDependencies": {
16
- "openclaw": ">=2026.5.28-beta.4"
16
+ "openclaw": ">=2026.5.30-beta.1"
17
17
  },
18
18
  "peerDependenciesMeta": {
19
19
  "openclaw": {
@@ -56,10 +56,10 @@
56
56
  "minHostVersion": ">=2026.4.25"
57
57
  },
58
58
  "compat": {
59
- "pluginApi": ">=2026.5.28-beta.4"
59
+ "pluginApi": ">=2026.5.30-beta.1"
60
60
  },
61
61
  "build": {
62
- "openclawVersion": "2026.5.28-beta.4"
62
+ "openclawVersion": "2026.5.30-beta.1"
63
63
  },
64
64
  "release": {
65
65
  "publishToClawHub": true,