@openclaw/whatsapp 2026.7.1 → 2026.7.2-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/{access-control-DYE5dXna.js → access-control-DazDX3RB.js} +4 -4
  2. package/dist/{account-config-6PTOSfaI.js → account-config-LiT9wWH9.js} +4 -8
  3. package/dist/{accounts-4YgwroRU.js → accounts-CKOFMPf-.js} +2 -3
  4. package/dist/{action-runtime-DPahAqxV.js → action-runtime-Bf-12TIH.js} +3 -3
  5. package/dist/action-runtime-api.js +1 -1
  6. package/dist/action-runtime.runtime.js +1 -1
  7. package/dist/{active-listener-B4SDebQ6.js → active-listener-5kHap439.js} +2 -2
  8. package/dist/{agent-tools-login-BX7eHgDm.js → agent-tools-login-DfyToBpG.js} +1 -4
  9. package/dist/api.js +17 -18
  10. package/dist/{approval-handler.runtime-DNWS4aYQ.js → approval-handler.runtime-CBiGQuZ5.js} +19 -13
  11. package/dist/approval-reactions-BGQoz25s.js +373 -0
  12. package/dist/{approval-resolver-DF-lu8k5.js → approval-resolver-DoeBBt22.js} +2 -1
  13. package/dist/{auth-store-Db-wfApd.js → auth-store-BQi9pZqQ.js} +31 -19
  14. package/dist/call-tool-api.js +6 -14
  15. package/dist/{channel-BWp7h1uY.js → channel-DbadDUDD.js} +84 -52
  16. package/dist/channel-config-api.js +1 -1
  17. package/dist/channel-plugin-api.js +1 -1
  18. package/dist/{channel-react-action-CKJHL_Wf.js → channel-react-action-PoRWfP9x.js} +7 -7
  19. package/dist/{channel.runtime-CAssfx9p.js → channel.runtime-BDDy4Lhz.js} +5 -5
  20. package/dist/{channel.setup-CURc5rEt.js → channel.setup-BZ-po8fg.js} +4 -5
  21. package/dist/config-schema-BZ8h1hWA.js +40 -0
  22. package/dist/{connection-controller-DkbrFSIn.js → connection-controller-C1rwfWb4.js} +52 -12
  23. package/dist/connection-controller-runtime-context-CbTsqmPT.js +14 -0
  24. package/dist/contract-api.js +2 -2
  25. package/dist/{directory-config-Dijefxc3.js → directory-config-CLBQrjtC.js} +3 -3
  26. package/dist/directory-contract-api.js +1 -1
  27. package/dist/doctor-contract-api.js +89 -4
  28. package/dist/{group-session-key-BhC1RQOE.js → group-session-key-CLTZeH_F.js} +31 -3
  29. package/dist/{identity-Dqft3mFA.js → identity-D7L8LCuH.js} +2 -2
  30. package/dist/legacy-state-migrations-api.js +1 -1
  31. package/dist/light-runtime-api.js +4 -4
  32. package/dist/{login-C48y0jlx.js → login-DGIoToX8.js} +48 -8
  33. package/dist/{login-qr-BjId7dll.js → login-qr-X-CZHOk9.js} +6 -7
  34. package/dist/login-qr-runtime.js +1 -1
  35. package/dist/{monitor-DD8bXohk.js → monitor-BZ8QvCeV.js} +145 -188
  36. package/dist/normalize-C-Z16y7Q.js +2 -0
  37. package/dist/{normalize-target-bVWjgftN.js → normalize-target-DSZnHkKF.js} +14 -10
  38. package/dist/{resolve-outbound-target-CcdugbDf.js → resolve-outbound-target-BR97fAbB.js} +1 -1
  39. package/dist/runtime-api.js +10 -10
  40. package/dist/{send-C5CpFcBG.js → send-D9Ydnn4o.js} +25 -320
  41. package/dist/{send-api-DLlXl8CH.js → send-api-W33lI2nR.js} +28 -88
  42. package/dist/{session-errors-BAj9D2La.js → session-errors-JuazczrA.js} +2 -1
  43. package/dist/{session-DriaHt7V.js → session-mxWFn0eS.js} +181 -19
  44. package/dist/session.runtime-Nsqaehbd.js +16 -0
  45. package/dist/{setup-core-DH-DFPLY.js → setup-core-3aSOoK2T.js} +18 -33
  46. package/dist/{setup-finalize-c8dl34sO.js → setup-finalize-DBf1jjBj.js} +41 -11
  47. package/dist/setup-plugin-api.js +1 -1
  48. package/dist/{setup-surface-DlWb0Z09.js → setup-surface-CiKGdNJv.js} +3 -3
  49. package/dist/{state-migrations-D_BmQUR9.js → state-migrations-CAMTrs2U.js} +1 -8
  50. package/dist/{targets-runtime-C-GiVn6Y.js → targets-runtime-Bsh0HR9y.js} +13 -6
  51. package/dist/text-runtime-BTGkMN0o.js +4 -0
  52. package/npm-shrinkwrap.json +3 -3
  53. package/openclaw.plugin.json +72 -48
  54. package/package.json +4 -4
  55. package/dist/config-schema-mBX2nmn1.js +0 -47
  56. package/dist/connection-controller-registry-TSX_udJp.js +0 -22
  57. package/dist/constants.js +0 -2
  58. package/dist/normalize-Bxwqo-bW.js +0 -2
  59. package/dist/session.runtime-CyooSQvj.js +0 -12
  60. package/dist/socket-timing-DhbVFjah.js +0 -77
  61. package/dist/targets.js +0 -2
  62. package/dist/text-runtime-DdX6-mC_.js +0 -4
@@ -1,14 +1,86 @@
1
1
  import { o as resolveWebCredsBackupPath, s as resolveWebCredsPath, t as assertWebCredsPathRegularFileOrMissing } from "./creds-files-B1kSWtBg.js";
2
- import { n as getStatusCode } from "./session-errors-BAj9D2La.js";
3
- import { t as DEFAULT_WHATSAPP_SOCKET_TIMING } from "./socket-timing-DhbVFjah.js";
4
- 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-Db-wfApd.js";
5
- import { i as makeWASocket, n as fetchLatestBaileysVersion, o as useMultiFileAuthState, r as makeCacheableSignalKeyStore } from "./session.runtime-CyooSQvj.js";
2
+ 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-BQi9pZqQ.js";
3
+ import { n as getStatusCode } from "./session-errors-JuazczrA.js";
4
+ import { a as makeWASocket, i as makeCacheableSignalKeyStore, n as createBaileysSignalRepository, r as fetchLatestBaileysVersion, s as useMultiFileAuthState } from "./session.runtime-Nsqaehbd.js";
6
5
  import { VERSION, formatCliCommand } from "openclaw/plugin-sdk/cli-runtime";
7
6
  import { danger, getChildLogger, success, toPinoLikeLogger } from "openclaw/plugin-sdk/runtime-env";
8
7
  import { renderQrTerminal } from "openclaw/plugin-sdk/media-runtime";
9
8
  import { ensureDir, resolveUserPath } from "openclaw/plugin-sdk/text-utility-runtime";
9
+ import { parseStrictPositiveInteger, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
10
10
  import { randomUUID } from "node:crypto";
11
11
  import { createHttp1EnvHttpProxyAgent, createHttp1ProxyAgent, createNodeProxyAgent } from "openclaw/plugin-sdk/fetch-runtime";
12
+ //#region extensions/whatsapp/src/socket-timing.ts
13
+ const socketSendMessageQueueTails = /* @__PURE__ */ new WeakMap();
14
+ const DEFAULT_WHATSAPP_SOCKET_TIMING = {
15
+ keepAliveIntervalMs: 25e3,
16
+ connectTimeoutMs: 6e4,
17
+ defaultQueryTimeoutMs: 6e4
18
+ };
19
+ var WhatsAppSocketOperationTimeoutError = class extends Error {
20
+ constructor(operation, timeoutMs) {
21
+ super(`WhatsApp socket ${operation} timed out after ${timeoutMs}ms; delivery state is unknown`);
22
+ this.operation = operation;
23
+ this.timeoutMs = timeoutMs;
24
+ this.deliveryState = "unknown";
25
+ this.name = "WhatsAppSocketOperationTimeoutError";
26
+ }
27
+ };
28
+ function resolveWhatsAppSocketTiming(cfg, overrides) {
29
+ const configured = cfg.web?.whatsapp;
30
+ return {
31
+ keepAliveIntervalMs: parseStrictPositiveInteger(overrides?.keepAliveIntervalMs) ?? parseStrictPositiveInteger(configured?.keepAliveIntervalMs) ?? DEFAULT_WHATSAPP_SOCKET_TIMING.keepAliveIntervalMs,
32
+ connectTimeoutMs: parseStrictPositiveInteger(overrides?.connectTimeoutMs) ?? parseStrictPositiveInteger(configured?.connectTimeoutMs) ?? DEFAULT_WHATSAPP_SOCKET_TIMING.connectTimeoutMs,
33
+ defaultQueryTimeoutMs: parseStrictPositiveInteger(overrides?.defaultQueryTimeoutMs) ?? parseStrictPositiveInteger(configured?.defaultQueryTimeoutMs) ?? DEFAULT_WHATSAPP_SOCKET_TIMING.defaultQueryTimeoutMs
34
+ };
35
+ }
36
+ function isWhatsAppSocketOperationTimeoutError(error) {
37
+ return error instanceof WhatsAppSocketOperationTimeoutError;
38
+ }
39
+ function resolveWhatsAppSocketOperationTimeoutMs(timeoutMs) {
40
+ return resolveTimerTimeoutMs(timeoutMs, DEFAULT_WHATSAPP_SOCKET_TIMING.defaultQueryTimeoutMs);
41
+ }
42
+ async function runSerializedSocketSendMessage(sock, run) {
43
+ const result = (socketSendMessageQueueTails.get(sock) ?? Promise.resolve()).then(run);
44
+ const tail = result.then(() => void 0, () => void 0);
45
+ socketSendMessageQueueTails.set(sock, tail);
46
+ tail.then(() => {
47
+ if (socketSendMessageQueueTails.get(sock) === tail) socketSendMessageQueueTails.delete(sock);
48
+ });
49
+ return await result;
50
+ }
51
+ async function withWhatsAppSocketOperationTimeout(operation, promise, timeoutMs, onTimeout) {
52
+ const resolvedTimeoutMs = resolveWhatsAppSocketOperationTimeoutMs(timeoutMs);
53
+ let timeout = null;
54
+ try {
55
+ return await Promise.race([promise, new Promise((_, reject) => {
56
+ timeout = setTimeout(() => {
57
+ onTimeout?.();
58
+ reject(new WhatsAppSocketOperationTimeoutError(operation, resolvedTimeoutMs));
59
+ }, resolvedTimeoutMs);
60
+ timeout.unref?.();
61
+ })]);
62
+ } finally {
63
+ if (timeout) clearTimeout(timeout);
64
+ }
65
+ }
66
+ function createWhatsAppSocketOperationTimeoutAdapter(sock, timeoutMs, hooks) {
67
+ const operationTimeoutMs = resolveWhatsAppSocketOperationTimeoutMs(timeoutMs);
68
+ return {
69
+ sendMessage: (jid, content, options) => {
70
+ return runSerializedSocketSendMessage(sock, () => {
71
+ const send = options ? sock.sendMessage(jid, content, options) : sock.sendMessage(jid, content);
72
+ return withWhatsAppSocketOperationTimeout("sendMessage", send, operationTimeoutMs, hooks?.onSendMessageTimeout ? () => hooks.onSendMessageTimeout?.({
73
+ jid,
74
+ promise: send
75
+ }) : void 0);
76
+ });
77
+ },
78
+ sendPresenceUpdate: (presence, jid) => {
79
+ return withWhatsAppSocketOperationTimeout("sendPresenceUpdate", jid === void 0 ? sock.sendPresenceUpdate(presence) : sock.sendPresenceUpdate(presence, jid), operationTimeoutMs);
80
+ }
81
+ };
82
+ }
83
+ //#endregion
12
84
  //#region extensions/whatsapp/src/session.ts
13
85
  const LOGGED_OUT_STATUS = 401;
14
86
  const WHATSAPP_WEBSOCKET_PROXY_TARGET = "https://mmg.whatsapp.net/";
@@ -17,29 +89,60 @@ const OPENCLAW_WHATSAPP_WEB_SOCKET_URL_ENV = "OPENCLAW_WHATSAPP_WEB_SOCKET_URL";
17
89
  async function rejectUnsafeWebCredsPath(authDir) {
18
90
  await assertWebCredsPathRegularFileOrMissing(resolveWebCredsPath(authDir));
19
91
  }
20
- function enqueueSaveCreds(authDir, saveCreds, logger) {
21
- enqueueCredsSave(authDir, () => safeSaveCreds(authDir, saveCreds, logger), (err) => {
92
+ function enqueueSaveCreds(authDir, saveCreds, logger, options) {
93
+ enqueueCredsSave(authDir, () => safeSaveCreds({
94
+ authDir,
95
+ saveCreds,
96
+ logger,
97
+ beforeCredentialPersistence: options?.beforeCredentialPersistence
98
+ }), (err) => {
22
99
  logger.warn({ error: String(err) }, "WhatsApp creds save queue error");
100
+ options?.onError?.(err);
23
101
  });
24
102
  }
25
- async function safeSaveCreds(authDir, saveCreds, logger) {
103
+ async function safeSaveCreds(params) {
104
+ let backup;
26
105
  try {
27
- const credsPath = resolveWebCredsPath(authDir);
28
- const backupPath = resolveWebCredsBackupPath(authDir);
106
+ const credsPath = resolveWebCredsPath(params.authDir);
107
+ const backupPath = resolveWebCredsBackupPath(params.authDir);
29
108
  const raw = readCredsJsonRaw(credsPath);
30
109
  if (raw) try {
31
110
  JSON.parse(raw);
32
- await writeWebCredsRawAtomically({
33
- filePath: backupPath,
111
+ backup = {
34
112
  content: raw,
113
+ filePath: backupPath
114
+ };
115
+ } catch {}
116
+ } catch {}
117
+ if (backup) {
118
+ await params.beforeCredentialPersistence?.();
119
+ try {
120
+ await writeWebCredsRawAtomically({
121
+ filePath: backup.filePath,
122
+ content: backup.content,
35
123
  tempPrefix: ".creds.backup"
36
124
  });
37
125
  } catch {}
38
- } catch {}
126
+ }
127
+ await params.beforeCredentialPersistence?.();
39
128
  try {
40
- await Promise.resolve(saveCreds());
129
+ await Promise.resolve(params.saveCreds());
41
130
  } catch (err) {
42
- logger.warn({ error: String(err) }, "failed saving WhatsApp creds");
131
+ params.logger.warn({ error: String(err) }, "failed saving WhatsApp creds");
132
+ if (params.beforeCredentialPersistence) throw err;
133
+ }
134
+ }
135
+ function abortSocketAfterCredentialPersistenceFailure(sock, error) {
136
+ const failure = error instanceof Error ? error : /* @__PURE__ */ new Error("WhatsApp credential persistence rejected");
137
+ const closeWebSocket = () => {
138
+ try {
139
+ sock.ws?.close?.();
140
+ } catch {}
141
+ };
142
+ try {
143
+ sock.end(failure).catch(closeWebSocket);
144
+ } catch {
145
+ closeWebSocket();
43
146
  }
44
147
  }
45
148
  async function printTerminalQr(qr) {
@@ -70,12 +173,13 @@ async function createWaSocket(printQr, verbose, opts = {}) {
70
173
  const logger = toPinoLikeLogger(getChildLogger({ module: "baileys" }, { level: verbose ? "info" : "silent" }), verbose ? "info" : "silent");
71
174
  const authDir = resolveUserPath(opts.authDir ?? resolveDefaultWebAuthDir());
72
175
  await rejectUnsafeWebCredsPath(authDir);
176
+ await opts.beforeCredentialPersistence?.();
73
177
  await ensureDir(authDir);
74
178
  const sessionLogger = getChildLogger({ module: "web-session" });
75
179
  if (await waitForCredsSaveQueueWithTimeout(authDir) === "timed_out") sessionLogger.warn({ authDir }, CREDS_FLUSH_TIMEOUT_MESSAGE);
76
180
  else {
77
181
  await rejectUnsafeWebCredsPath(authDir);
78
- await restoreCredsFromBackupIfNeeded(authDir);
182
+ await restoreCredsFromBackupIfNeeded(authDir, { beforeCredentialPersistence: opts.beforeCredentialPersistence });
79
183
  }
80
184
  await rejectUnsafeWebCredsPath(authDir);
81
185
  const { state } = await useMultiFileAuthState(authDir);
@@ -91,10 +195,62 @@ async function createWaSocket(printQr, verbose, opts = {}) {
91
195
  connectTimeoutMs: opts.connectTimeoutMs ?? DEFAULT_WHATSAPP_SOCKET_TIMING.connectTimeoutMs,
92
196
  defaultQueryTimeoutMs: opts.defaultQueryTimeoutMs ?? DEFAULT_WHATSAPP_SOCKET_TIMING.defaultQueryTimeoutMs
93
197
  };
198
+ const socketRef = {};
199
+ let pendingSocketAbort;
200
+ const reportCredentialPersistenceError = (error) => {
201
+ if (socketRef.current) abortSocketAfterCredentialPersistenceFailure(socketRef.current, error);
202
+ else pendingSocketAbort = { error };
203
+ opts.onCredentialPersistenceError?.(error);
204
+ };
205
+ const cachedSignalKeys = makeCacheableSignalKeyStore(opts.beforeCredentialPersistence ? {
206
+ ...state.keys,
207
+ async set(data) {
208
+ await opts.beforeCredentialPersistence?.();
209
+ await state.keys.set(data);
210
+ }
211
+ } : state.keys, logger);
212
+ const signalKeys = opts.beforeCredentialPersistence ? {
213
+ ...cachedSignalKeys,
214
+ get(type, ids) {
215
+ const task = Promise.resolve(cachedSignalKeys.get(type, ids));
216
+ opts.onCredentialPersistenceTask?.(task);
217
+ return task;
218
+ },
219
+ set(data) {
220
+ const task = (async () => {
221
+ try {
222
+ await cachedSignalKeys.set(data);
223
+ } catch (error) {
224
+ reportCredentialPersistenceError(error);
225
+ throw error;
226
+ }
227
+ })();
228
+ opts.onCredentialPersistenceTask?.(task);
229
+ return task;
230
+ }
231
+ } : cachedSignalKeys;
232
+ const makeSignalRepository = opts.onCredentialPersistenceTask ? (...args) => {
233
+ const repository = createBaileysSignalRepository(...args);
234
+ const storeLidPnMappings = repository.lidMapping.storeLIDPNMappings.bind(repository.lidMapping);
235
+ repository.lidMapping.storeLIDPNMappings = (...storeArgs) => {
236
+ const task = storeLidPnMappings(...storeArgs);
237
+ opts.onCredentialPersistenceTask?.(task);
238
+ task.then(void 0, reportCredentialPersistenceError);
239
+ return task;
240
+ };
241
+ const migrateSession = repository.migrateSession.bind(repository);
242
+ repository.migrateSession = (...migrateArgs) => {
243
+ const task = migrateSession(...migrateArgs);
244
+ opts.onCredentialPersistenceTask?.(task);
245
+ task.then(void 0, reportCredentialPersistenceError);
246
+ return task;
247
+ };
248
+ return repository;
249
+ } : void 0;
94
250
  const sock = makeWASocket({
95
251
  auth: {
96
252
  creds: state.creds,
97
- keys: makeCacheableSignalKeyStore(state.keys, logger)
253
+ keys: signalKeys
98
254
  },
99
255
  version,
100
256
  logger,
@@ -109,11 +265,17 @@ async function createWaSocket(printQr, verbose, opts = {}) {
109
265
  ...socketTiming,
110
266
  agent,
111
267
  fetchAgent,
268
+ ...makeSignalRepository ? { makeSignalRepository } : {},
112
269
  ...waWebSocketUrl ? { waWebSocketUrl } : {},
113
270
  ...opts.getMessage ? { getMessage: opts.getMessage } : {},
114
271
  ...opts.cachedGroupMetadata ? { cachedGroupMetadata: opts.cachedGroupMetadata } : {}
115
272
  });
116
- sock.ev.on("creds.update", () => enqueueSaveCreds(authDir, saveCreds, sessionLogger));
273
+ socketRef.current = sock;
274
+ if (pendingSocketAbort) abortSocketAfterCredentialPersistenceFailure(sock, pendingSocketAbort.error);
275
+ sock.ev.on("creds.update", () => enqueueSaveCreds(authDir, saveCreds, sessionLogger, {
276
+ beforeCredentialPersistence: opts.beforeCredentialPersistence,
277
+ onError: reportCredentialPersistenceError
278
+ }));
117
279
  sock.ev.on("connection.update", (update) => {
118
280
  (async () => {
119
281
  try {
@@ -208,7 +370,7 @@ async function waitForWaConnection(sock, options = { timeout: "none" }) {
208
370
  }
209
371
  if (update.connection === "close") {
210
372
  cleanup();
211
- reject(toLintErrorObject(update.lastDisconnect ?? /* @__PURE__ */ new Error("Connection closed"), "Non-Error rejection"));
373
+ reject(toLintErrorObject(update.lastDisconnect?.error ?? update.lastDisconnect ?? /* @__PURE__ */ new Error("Connection closed"), "Non-Error rejection"));
212
374
  }
213
375
  };
214
376
  sock.ev.on("connection.update", handler);
@@ -238,4 +400,4 @@ function createConnectionTimeoutError(timeoutMs) {
238
400
  return error;
239
401
  }
240
402
  //#endregion
241
- export { renderQrTerminal as i, newConnectionId as n, waitForWaConnection as r, createWaSocket as t };
403
+ export { createWhatsAppSocketOperationTimeoutAdapter as a, resolveWhatsAppSocketTiming as c, DEFAULT_WHATSAPP_SOCKET_TIMING as i, withWhatsAppSocketOperationTimeout as l, newConnectionId as n, isWhatsAppSocketOperationTimeoutError as o, waitForWaConnection as r, resolveWhatsAppSocketOperationTimeoutMs as s, createWaSocket as t, renderQrTerminal as u };
@@ -0,0 +1,16 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
+ import { BufferJSON, DEFAULT_CONNECTION_CONFIG, fetchLatestBaileysVersion, makeCacheableSignalKeyStore, makeWASocket, useMultiFileAuthState } from "baileys";
3
+ //#region extensions/whatsapp/src/session.runtime.ts
4
+ var session_runtime_exports = /* @__PURE__ */ __exportAll({
5
+ BufferJSON: () => BufferJSON,
6
+ createBaileysSignalRepository: () => createBaileysSignalRepository,
7
+ fetchLatestBaileysVersion: () => fetchLatestBaileysVersion,
8
+ makeCacheableSignalKeyStore: () => makeCacheableSignalKeyStore,
9
+ makeWASocket: () => makeWASocket,
10
+ useMultiFileAuthState: () => useMultiFileAuthState
11
+ });
12
+ function createBaileysSignalRepository(...args) {
13
+ return DEFAULT_CONNECTION_CONFIG.makeSignalRepository(...args);
14
+ }
15
+ //#endregion
16
+ export { makeWASocket as a, makeCacheableSignalKeyStore as i, createBaileysSignalRepository as n, session_runtime_exports as o, fetchLatestBaileysVersion as r, useMultiFileAuthState as s, BufferJSON as t };
@@ -1,7 +1,7 @@
1
1
  import { r as resolveDefaultWhatsAppAccountId, t as listAccountIds } from "./account-ids-CB5SOWjc.js";
2
- import { a as resolveWhatsAppAccount, n as hasAnyWhatsAppAuth } from "./accounts-4YgwroRU.js";
3
- import { a as normalizeWhatsAppAllowFromEntries } from "./normalize-target-bVWjgftN.js";
4
- import { t as WhatsAppChannelConfigSchema } from "./config-schema-mBX2nmn1.js";
2
+ import { a as resolveWhatsAppAccount, n as hasAnyWhatsAppAuth } from "./accounts-CKOFMPf-.js";
3
+ import { a as normalizeWhatsAppAllowFromEntries } from "./normalize-target-DSZnHkKF.js";
4
+ import { t as WhatsAppChannelConfigSchema } from "./config-schema-BZ8h1hWA.js";
5
5
  import { n as whatsappDoctor } from "./doctor-By3SB4lm.js";
6
6
  import { t as resolveWhatsAppConfigPath } from "./group-config-path-BGyzT9Lg.js";
7
7
  import { t as resolveLegacyGroupSessionKey } from "./group-session-contract-DDnZSsJ1.js";
@@ -11,7 +11,7 @@ import { normalizeUniqueStringEntries } from "openclaw/plugin-sdk/string-coerce-
11
11
  import { normalizeE164 } from "openclaw/plugin-sdk/account-resolution";
12
12
  import { createChannelPluginBase } from "openclaw/plugin-sdk/core";
13
13
  import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
14
- import { collectOpenGroupPolicyRouteAllowlistWarnings, createAllowlistProviderGroupPolicyWarningCollector, resolveChannelGroupRequireMention, resolveChannelGroupToolsPolicy } from "openclaw/plugin-sdk/channel-policy";
14
+ import { buildChannelGroupsScopeTree, collectOpenGroupPolicyRouteAllowlistWarnings, createAllowlistProviderGroupPolicyWarningCollector, resolveScopeRequireMention, resolveScopeToolsPolicy } from "openclaw/plugin-sdk/channel-policy";
15
15
  import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
16
16
  import { adaptScopedAccountAccessor, createScopedChannelConfigAdapter, createScopedDmSecurityResolver } from "openclaw/plugin-sdk/channel-config-helpers";
17
17
  import { createDelegatedSetupWizardProxy } from "openclaw/plugin-sdk/setup-runtime";
@@ -22,37 +22,22 @@ function formatWhatsAppConfigAllowFromEntries(allowFrom) {
22
22
  return normalizeWhatsAppAllowFromEntries(allowFrom);
23
23
  }
24
24
  //#endregion
25
- //#region extensions/whatsapp/src/group-intro.ts
26
- const WHATSAPP_GROUP_INTRO_HINT = "WhatsApp IDs: SenderId is the participant JID (group participant id).";
27
- function resolveWhatsAppGroupIntroHint() {
28
- return WHATSAPP_GROUP_INTRO_HINT;
29
- }
30
- function resolveWhatsAppMentionStripRegexes(ctx) {
31
- const selfE164 = (ctx.To ?? "").replace(/^whatsapp:/i, "");
32
- if (!selfE164) return [];
33
- const escaped = selfE164.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
34
- return [new RegExp(escaped, "g"), new RegExp(`@${escaped}`, "g")];
35
- }
36
- //#endregion
37
25
  //#region extensions/whatsapp/src/group-policy.ts
26
+ function resolveScopePath(params) {
27
+ return params.groupId ? [params.groupId] : [];
28
+ }
38
29
  function resolveWhatsAppGroupRequireMention(params) {
39
- return resolveChannelGroupRequireMention({
40
- cfg: params.cfg,
41
- channel: "whatsapp",
42
- groupId: params.groupId,
43
- accountId: params.accountId
30
+ return resolveScopeRequireMention({
31
+ tree: buildChannelGroupsScopeTree(params.cfg, "whatsapp", params.accountId),
32
+ path: resolveScopePath(params)
44
33
  });
45
34
  }
46
35
  function resolveWhatsAppGroupToolPolicy(params) {
47
- return resolveChannelGroupToolsPolicy({
48
- cfg: params.cfg,
49
- channel: "whatsapp",
50
- groupId: params.groupId,
51
- accountId: params.accountId,
52
- senderId: params.senderId,
53
- senderName: params.senderName,
54
- senderUsername: params.senderUsername,
55
- senderE164: params.senderE164
36
+ return resolveScopeToolsPolicy({
37
+ ...params,
38
+ tree: buildChannelGroupsScopeTree(params.cfg, "whatsapp", params.accountId),
39
+ path: resolveScopePath(params),
40
+ messageProvider: "whatsapp"
56
41
  });
57
42
  }
58
43
  //#endregion
@@ -99,10 +84,10 @@ async function applyWhatsAppSecurityConfigFixes(params) {
99
84
  //#region extensions/whatsapp/src/shared.ts
100
85
  const WHATSAPP_CHANNEL = "whatsapp";
101
86
  async function loadWhatsAppChannelRuntime() {
102
- return await import("./channel.runtime-CAssfx9p.js");
87
+ return await import("./channel.runtime-BDDy4Lhz.js");
103
88
  }
104
89
  async function loadWhatsAppSetupSurface() {
105
- return await import("./setup-surface-DlWb0Z09.js");
90
+ return await import("./setup-surface-CiKGdNJv.js");
106
91
  }
107
92
  const whatsappSetupWizardProxy = createWhatsAppSetupWizardProxy(async () => (await loadWhatsAppSetupSurface()).whatsappSetupWizard);
108
93
  const whatsappConfigAdapter = createScopedChannelConfigAdapter({
@@ -333,4 +318,4 @@ const whatsappSetupAdapter = {
333
318
  }
334
319
  };
335
320
  //#endregion
336
- export { resolveWhatsAppGroupRequireMention as a, resolveWhatsAppMentionStripRegexes as c, whatsappSetupWizardProxy as i, formatWhatsAppConfigAllowFromEntries as l, createWhatsAppPluginBase as n, resolveWhatsAppGroupToolPolicy as o, loadWhatsAppChannelRuntime as r, resolveWhatsAppGroupIntroHint as s, whatsappSetupAdapter as t };
321
+ export { resolveWhatsAppGroupRequireMention as a, whatsappSetupWizardProxy as i, createWhatsAppPluginBase as n, resolveWhatsAppGroupToolPolicy as o, loadWhatsAppChannelRuntime as r, formatWhatsAppConfigAllowFromEntries as s, whatsappSetupAdapter as t };
@@ -1,8 +1,8 @@
1
1
  import { r as resolveDefaultWhatsAppAccountId } from "./account-ids-CB5SOWjc.js";
2
2
  import { r as hasWebCredsSync } from "./creds-files-B1kSWtBg.js";
3
- import { a as resolveWhatsAppAccount, o as resolveWhatsAppAuthDir } from "./accounts-4YgwroRU.js";
4
- import { a as normalizeWhatsAppAllowFromEntries, o as normalizeWhatsAppAllowFromEntry } from "./normalize-target-bVWjgftN.js";
5
- import { t as whatsappSetupAdapter } from "./setup-core-DH-DFPLY.js";
3
+ import { a as resolveWhatsAppAccount, o as resolveWhatsAppAuthDir } from "./accounts-CKOFMPf-.js";
4
+ import { a as normalizeWhatsAppAllowFromEntries, o as normalizeWhatsAppAllowFromEntry } from "./normalize-target-DSZnHkKF.js";
5
+ import { t as whatsappSetupAdapter } from "./setup-core-3aSOoK2T.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
@@ -271,6 +271,15 @@ async function finalizeWhatsAppSetup(params) {
271
271
  cfg: next,
272
272
  accountId
273
273
  });
274
+ if (params.options?.deferDeviceLinkToClient) {
275
+ next = await promptWhatsAppDmAccess({
276
+ cfg: next,
277
+ accountId,
278
+ forceAllowFrom: params.forceAllowFrom,
279
+ prompter: params.prompter
280
+ });
281
+ return { cfg: next };
282
+ }
274
283
  if (!linked) await params.prompter.note([
275
284
  t("wizard.whatsapp.scanQr"),
276
285
  t("wizard.whatsapp.credentialsStored", { authDir }),
@@ -279,14 +288,35 @@ async function finalizeWhatsAppSetup(params) {
279
288
  if (await params.prompter.confirm({
280
289
  message: linked ? t("wizard.whatsapp.relinkPrompt") : t("wizard.whatsapp.linkNowPrompt"),
281
290
  initialValue: !linked
282
- })) try {
283
- const { loginWeb } = await import("./login-C48y0jlx.js").then((n) => n.n);
284
- await loginWeb(false, void 0, params.runtime, accountId);
285
- } catch (error) {
286
- params.runtime.error(`WhatsApp login failed: ${String(error)}`);
287
- await params.prompter.note(t("wizard.channels.docs", { link: formatDocsLink("/whatsapp", "whatsapp") }), t("wizard.whatsapp.helpTitle"));
288
- }
289
- else if (!linked) await params.prompter.note(t("wizard.whatsapp.linkLater", { command: formatCliCommand("openclaw channels login") }), "WhatsApp");
291
+ })) {
292
+ const reportLoginFailure = async (error) => {
293
+ params.runtime.error(`WhatsApp login failed: ${String(error)}`);
294
+ await params.prompter.note(t("wizard.channels.docs", { link: formatDocsLink("/whatsapp", "whatsapp") }), t("wizard.whatsapp.helpTitle"));
295
+ };
296
+ let loginWeb;
297
+ try {
298
+ ({loginWeb} = await import("./login-DGIoToX8.js").then((n) => n.n));
299
+ } catch (error) {
300
+ await reportLoginFailure(error);
301
+ }
302
+ if (loginWeb) {
303
+ let persistenceGuardFailure;
304
+ const beforeCredentialPersistence = params.options?.beforePersistentEffect ? async () => {
305
+ try {
306
+ await params.options?.beforePersistentEffect?.();
307
+ } catch (error) {
308
+ persistenceGuardFailure = { error };
309
+ throw error;
310
+ }
311
+ } : void 0;
312
+ try {
313
+ await loginWeb(false, void 0, params.runtime, accountId, { beforeCredentialPersistence });
314
+ } catch (error) {
315
+ if (persistenceGuardFailure) throw persistenceGuardFailure.error;
316
+ await reportLoginFailure(error);
317
+ }
318
+ }
319
+ } else if (!linked) await params.prompter.note(t("wizard.whatsapp.linkLater", { command: formatCliCommand("openclaw channels login") }), "WhatsApp");
290
320
  next = await promptWhatsAppDmAccess({
291
321
  cfg: next,
292
322
  accountId,
@@ -1,2 +1,2 @@
1
- import { t as whatsappSetupPlugin } from "./channel.setup-CURc5rEt.js";
1
+ import { t as whatsappSetupPlugin } from "./channel.setup-BZ-po8fg.js";
2
2
  export { whatsappSetupPlugin };
@@ -1,6 +1,6 @@
1
1
  import { t as listAccountIds } from "./account-ids-CB5SOWjc.js";
2
- import { o as resolveWhatsAppAuthDir } from "./accounts-4YgwroRU.js";
3
- import { a as formatWhatsAppWebAuthStatusState, h as readWebAuthState } from "./auth-store-Db-wfApd.js";
2
+ import { o as resolveWhatsAppAuthDir } from "./accounts-CKOFMPf-.js";
3
+ import { a as formatWhatsAppWebAuthStatusState, h as readWebAuthState } from "./auth-store-BQi9pZqQ.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-c8dl34sO.js")).finalizeWhatsAppSetup(params),
39
+ finalize: async (params) => await (await import("./setup-finalize-DBf1jjBj.js")).finalizeWhatsAppSetup(params),
40
40
  disable: (cfg) => setSetupChannelEnabled(cfg, channel, false),
41
41
  onAccountRecorded: (accountId, options) => {
42
42
  options?.onAccountId?.(channel, accountId);
@@ -1,15 +1,8 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
- import { statRegularFileSync } from "openclaw/plugin-sdk/security-runtime";
3
+ import { fileExists } from "openclaw/plugin-sdk/security-runtime";
4
4
  import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
5
5
  //#region extensions/whatsapp/src/state-migrations.ts
6
- function fileExists(pathValue) {
7
- try {
8
- return !statRegularFileSync(pathValue).missing;
9
- } catch {
10
- return false;
11
- }
12
- }
13
6
  function isLegacyWhatsAppAuthFile(name) {
14
7
  if (name === "creds.json" || name === "creds.json.bak") return true;
15
8
  if (!name.endsWith(".json")) return false;
@@ -71,22 +71,27 @@ async function resolveEquivalentWhatsAppDirectChatJids(jid, opts) {
71
71
  const pnMatch = normalized.match(DIRECT_PN_JID_RE);
72
72
  if (pnMatch) {
73
73
  addEquivalentDirectChatCandidate(candidates, await tryLookupMappedJid(() => opts?.lidLookup?.getLIDForPN?.(normalized)));
74
+ const phoneDigits = pnMatch[1];
75
+ const pnDomain = pnMatch[2];
76
+ if (!phoneDigits || !pnDomain) return candidates;
74
77
  const mappedLocalLid = readLidForwardMapping({
75
- phoneDigits: pnMatch[1],
78
+ phoneDigits,
76
79
  opts
77
80
  });
78
- const localLidDomain = pnMatch[2].toLowerCase() === "hosted" ? "hosted.lid" : "lid";
81
+ const localLidDomain = pnDomain.toLowerCase() === "hosted" ? "hosted.lid" : "lid";
79
82
  addUniqueString(candidates, mappedLocalLid ? `${mappedLocalLid}@${localLidDomain}` : null);
80
83
  return candidates;
81
84
  }
82
85
  const lidMatch = normalized.match(DIRECT_LID_JID_RE);
83
86
  if (lidMatch) {
84
87
  addEquivalentDirectChatCandidate(candidates, await tryLookupMappedJid(() => opts?.lidLookup?.getPNForLID?.(normalized)));
88
+ const lidDomain = lidMatch[2];
89
+ if (!lidMatch[1] || !lidDomain) return candidates;
85
90
  const e164 = jidToE164(normalized, {
86
91
  ...opts,
87
92
  logMissing: false
88
93
  });
89
- addUniqueString(candidates, e164 && lidMatch[2].toLowerCase() === "hosted.lid" ? `${e164.replace(/\D/g, "")}@hosted` : e164 ? toWhatsappJid(e164) : null);
94
+ addUniqueString(candidates, e164 && lidDomain.toLowerCase() === "hosted.lid" ? `${e164.replace(/\D/g, "")}@hosted` : e164 ? toWhatsappJid(e164) : null);
90
95
  }
91
96
  return candidates;
92
97
  }
@@ -132,12 +137,14 @@ function readLidForwardMapping(params) {
132
137
  return null;
133
138
  }
134
139
  function jidToE164(jid, opts) {
135
- const match = jid.match(/^(\d+)(?::\d+)?@(s\.whatsapp\.net|hosted)$/);
136
- if (match) return `+${match[1]}`;
140
+ const phoneDigits = jid.match(/^(\d+)(?::\d+)?@(s\.whatsapp\.net|hosted)$/)?.[1];
141
+ if (phoneDigits) return `+${phoneDigits}`;
137
142
  const lidMatch = jid.match(/^(\d+)(?::\d+)?@(lid|hosted\.lid)$/);
138
143
  if (!lidMatch) return null;
144
+ const lid = lidMatch[1];
145
+ if (!lid) return null;
139
146
  const phone = readLidReverseMapping({
140
- lid: lidMatch[1],
147
+ lid,
141
148
  opts
142
149
  });
143
150
  if (phone) return phone;
@@ -0,0 +1,4 @@
1
+ import "./targets-runtime-Bsh0HR9y.js";
2
+ import { convertMarkdownTables, sanitizeAssistantVisibleText, sanitizeAssistantVisibleTextWithProfile, stripToolCallXmlTags } from "openclaw/plugin-sdk/text-chunking";
3
+ import { normalizeE164, resolveUserPath as resolveUserPath$1 } from "openclaw/plugin-sdk/text-utility-runtime";
4
+ export { sanitizeAssistantVisibleTextWithProfile as a, sanitizeAssistantVisibleText as i, normalizeE164 as n, stripToolCallXmlTags as o, resolveUserPath$1 as r, convertMarkdownTables as t };
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "@openclaw/whatsapp",
3
- "version": "2026.7.1",
3
+ "version": "2026.7.2-beta.2",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@openclaw/whatsapp",
9
- "version": "2026.7.1",
9
+ "version": "2026.7.2-beta.2",
10
10
  "dependencies": {
11
11
  "audio-decode": "2.2.3",
12
12
  "baileys": "7.0.0-rc13",
13
13
  "typebox": "1.3.3"
14
14
  },
15
15
  "peerDependencies": {
16
- "openclaw": ">=2026.7.1"
16
+ "openclaw": ">=2026.7.2-beta.2"
17
17
  },
18
18
  "peerDependenciesMeta": {
19
19
  "openclaw": {