@openclaw/whatsapp 2026.7.1 → 2026.7.2-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 (59) 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-D_1cK7-w.js} +72 -33
  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-BPrKzcYd.js} +5 -5
  20. package/dist/{channel.setup-CURc5rEt.js → channel.setup-eX64WZDx.js} +3 -4
  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/light-runtime-api.js +4 -4
  31. package/dist/{login-C48y0jlx.js → login-DGIoToX8.js} +48 -8
  32. package/dist/{login-qr-BjId7dll.js → login-qr-X-CZHOk9.js} +6 -7
  33. package/dist/login-qr-runtime.js +1 -1
  34. package/dist/{monitor-DD8bXohk.js → monitor-BKtA0lzq.js} +102 -100
  35. package/dist/normalize-C-Z16y7Q.js +2 -0
  36. package/dist/{normalize-target-bVWjgftN.js → normalize-target-DSZnHkKF.js} +14 -10
  37. package/dist/{resolve-outbound-target-CcdugbDf.js → resolve-outbound-target-BR97fAbB.js} +1 -1
  38. package/dist/runtime-api.js +10 -10
  39. package/dist/{send-C5CpFcBG.js → send-D9Ydnn4o.js} +25 -320
  40. package/dist/{send-api-DLlXl8CH.js → send-api-W33lI2nR.js} +28 -88
  41. package/dist/{session-errors-BAj9D2La.js → session-errors-JuazczrA.js} +2 -1
  42. package/dist/{session-DriaHt7V.js → session-mxWFn0eS.js} +181 -19
  43. package/dist/session.runtime-Nsqaehbd.js +16 -0
  44. package/dist/{setup-core-DH-DFPLY.js → setup-core-BXDFGqky.js} +18 -33
  45. package/dist/{setup-finalize-c8dl34sO.js → setup-finalize-DzOHXnPj.js} +41 -11
  46. package/dist/setup-plugin-api.js +1 -1
  47. package/dist/{setup-surface-DlWb0Z09.js → setup-surface-5EUmMLHS.js} +3 -3
  48. package/dist/{targets-runtime-C-GiVn6Y.js → targets-runtime-Bsh0HR9y.js} +13 -6
  49. package/dist/targets.js +1 -1
  50. package/dist/text-runtime-BTGkMN0o.js +4 -0
  51. package/npm-shrinkwrap.json +3 -3
  52. package/openclaw.plugin.json +72 -48
  53. package/package.json +4 -4
  54. package/dist/config-schema-mBX2nmn1.js +0 -47
  55. package/dist/connection-controller-registry-TSX_udJp.js +0 -22
  56. package/dist/normalize-Bxwqo-bW.js +0 -2
  57. package/dist/session.runtime-CyooSQvj.js +0 -12
  58. package/dist/socket-timing-DhbVFjah.js +0 -77
  59. package/dist/text-runtime-DdX6-mC_.js +0 -4
@@ -1,4 +1,4 @@
1
- import { n as listWhatsAppDirectoryGroupsFromConfig, r as listWhatsAppDirectoryPeersFromConfig } from "./directory-config-Dijefxc3.js";
1
+ import { n as listWhatsAppDirectoryGroupsFromConfig, r as listWhatsAppDirectoryPeersFromConfig } from "./directory-config-CLBQrjtC.js";
2
2
  //#region extensions/whatsapp/directory-contract-api.ts
3
3
  const whatsappDirectoryContractPlugin = {
4
4
  id: "whatsapp",
@@ -1,10 +1,95 @@
1
1
  import { t as normalizeCompatibilityConfig$1 } from "./doctor-By3SB4lm.js";
2
+ import { asObjectRecord, defineChannelAliasMigration } from "openclaw/plugin-sdk/runtime-doctor";
2
3
  //#region extensions/whatsapp/src/doctor-contract.ts
4
+ const streamingAliasMigration = defineChannelAliasMigration({
5
+ channelId: "whatsapp",
6
+ streaming: {
7
+ defaultMode: "partial",
8
+ deliveryOnly: true
9
+ }
10
+ });
11
+ const legacyConfigRules = streamingAliasMigration.legacyConfigRules;
12
+ /** Deep-fills fields missing from target with copies of source values. */
13
+ function fillMissingStreamingFields(target, source) {
14
+ let filled = false;
15
+ const value = { ...target };
16
+ for (const [key, sourceValue] of Object.entries(source)) {
17
+ if (sourceValue === void 0) continue;
18
+ const existing = value[key];
19
+ if (existing === void 0) {
20
+ value[key] = structuredClone(sourceValue);
21
+ filled = true;
22
+ continue;
23
+ }
24
+ const existingRecord = asObjectRecord(existing);
25
+ const sourceRecord = asObjectRecord(sourceValue);
26
+ if (!existingRecord || !sourceRecord) continue;
27
+ const merged = fillMissingStreamingFields(existingRecord, sourceRecord);
28
+ if (merged.filled) {
29
+ value[key] = merged.value;
30
+ filled = true;
31
+ }
32
+ }
33
+ return {
34
+ value,
35
+ filled
36
+ };
37
+ }
38
+ function seedMigratedAccountStreaming(params) {
39
+ const channels = params.cfg.channels;
40
+ const entry = asObjectRecord(channels?.whatsapp);
41
+ const accounts = asObjectRecord(entry?.accounts);
42
+ if (!entry || !accounts) return params.cfg;
43
+ const rootStreaming = asObjectRecord(entry.streaming);
44
+ const defaultKey = Object.hasOwn(accounts, "default") ? "default" : Object.keys(accounts).find((key) => key.trim().toLowerCase() === "default");
45
+ let accountsChanged = false;
46
+ const nextAccounts = { ...accounts };
47
+ const seedOrder = Object.keys(accounts).toSorted((left, right) => left === defaultKey ? -1 : right === defaultKey ? 1 : left.localeCompare(right));
48
+ for (const accountId of seedOrder) {
49
+ const account = asObjectRecord(nextAccounts[accountId]);
50
+ const created = asObjectRecord(account?.streaming);
51
+ if (!account || !created || !params.accountsWithoutStreamingBefore.has(accountId)) continue;
52
+ const defaultStreaming = defaultKey ? asObjectRecord(asObjectRecord(nextAccounts[defaultKey])?.streaming) : null;
53
+ const inheritedSource = accountId === defaultKey ? rootStreaming : defaultStreaming ?? rootStreaming;
54
+ if (!inheritedSource) continue;
55
+ const seeded = fillMissingStreamingFields(created, inheritedSource);
56
+ if (!seeded.filled) continue;
57
+ nextAccounts[accountId] = {
58
+ ...account,
59
+ streaming: seeded.value
60
+ };
61
+ accountsChanged = true;
62
+ const sourcePath = accountId === defaultKey ? "channels.whatsapp.streaming" : "effective channels.whatsapp streaming defaults";
63
+ params.changes.push(`Copied ${sourcePath} into channels.whatsapp.accounts.${accountId}.streaming to keep inherited settings while migrating flat streaming keys.`);
64
+ }
65
+ if (!accountsChanged) return params.cfg;
66
+ return {
67
+ ...params.cfg,
68
+ channels: {
69
+ ...channels,
70
+ whatsapp: {
71
+ ...entry,
72
+ accounts: nextAccounts
73
+ }
74
+ }
75
+ };
76
+ }
3
77
  function normalizeCompatibilityConfig({ cfg }) {
4
- return normalizeCompatibilityConfig$1({ cfg });
78
+ const ackReaction = normalizeCompatibilityConfig$1({ cfg });
79
+ const accountsBefore = asObjectRecord(asObjectRecord(ackReaction.config.channels?.whatsapp)?.accounts);
80
+ const accountsWithoutStreamingBefore = new Set(Object.entries(accountsBefore ?? {}).filter(([, account]) => asObjectRecord(account)?.streaming === void 0).map(([accountId]) => accountId));
81
+ const aliases = streamingAliasMigration.normalizeChannelConfig({
82
+ cfg: ackReaction.config,
83
+ changes: ackReaction.changes
84
+ });
85
+ return {
86
+ config: seedMigratedAccountStreaming({
87
+ cfg: aliases.config,
88
+ accountsWithoutStreamingBefore,
89
+ changes: aliases.changes
90
+ }),
91
+ changes: aliases.changes
92
+ };
5
93
  }
6
94
  //#endregion
7
- //#region extensions/whatsapp/doctor-contract-api.ts
8
- const legacyConfigRules = [];
9
- //#endregion
10
95
  export { legacyConfigRules, normalizeCompatibilityConfig };
@@ -1,6 +1,34 @@
1
- import { r as jidToE164 } from "./targets-runtime-C-GiVn6Y.js";
2
- import "./text-runtime-DdX6-mC_.js";
1
+ import { a as resolveWhatsAppAccount } from "./accounts-CKOFMPf-.js";
2
+ import { c as normalizeWhatsAppTarget } from "./normalize-target-DSZnHkKF.js";
3
+ import "./normalize-C-Z16y7Q.js";
4
+ import { r as jidToE164 } from "./targets-runtime-Bsh0HR9y.js";
5
+ import "./text-runtime-BTGkMN0o.js";
6
+ import { createChannelApprovalAuth } from "openclaw/plugin-sdk/approval-auth-runtime";
3
7
  import { DEFAULT_ACCOUNT_ID, normalizeAccountId, resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
8
+ //#region extensions/whatsapp/src/approval-auth.ts
9
+ function normalizeWhatsAppApproverId(value) {
10
+ const normalized = normalizeWhatsAppTarget(String(value));
11
+ if (!normalized || normalized.endsWith("@g.us")) return;
12
+ return normalized;
13
+ }
14
+ function normalizeWhatsAppApproverEntry(value) {
15
+ return String(value).trim() === "*" ? "*" : normalizeWhatsAppApproverId(value);
16
+ }
17
+ const whatsappApproval = createChannelApprovalAuth({
18
+ channelLabel: "WhatsApp",
19
+ resolveInputs: ({ cfg, accountId }) => {
20
+ return { allowFrom: resolveWhatsAppAccount({
21
+ cfg,
22
+ accountId
23
+ }).allowFrom };
24
+ },
25
+ normalizeApprover: normalizeWhatsAppApproverEntry,
26
+ normalizeSenderId: normalizeWhatsAppApproverId,
27
+ isWildcardAuthorized: ({ purpose, approvers }) => purpose === "action" && approvers.includes("*")
28
+ });
29
+ const getWhatsAppApprovalApprovers = whatsappApproval.resolveApprovers;
30
+ const whatsappApprovalAuth = whatsappApproval.approvalAuth;
31
+ //#endregion
4
32
  //#region extensions/whatsapp/src/quoted-message.ts
5
33
  const CACHE_TTL_MS = 600 * 1e3;
6
34
  const MAX_ENTRIES = 500;
@@ -134,4 +162,4 @@ function resolveWhatsAppGroupSessionRoute(route) {
134
162
  };
135
163
  }
136
164
  //#endregion
137
- export { cacheInboundMessageMeta as a, buildQuotedMessageOptions as i, resolveWhatsAppGroupSessionRoute as n, lookupInboundMessageMeta as o, resolveWhatsAppLegacyGroupSessionKey as r, lookupInboundMessageMetaForTarget as s, resolveWhatsAppGroupSessionKey as t };
165
+ export { cacheInboundMessageMeta as a, getWhatsAppApprovalApprovers as c, buildQuotedMessageOptions as i, whatsappApprovalAuth as l, resolveWhatsAppGroupSessionRoute as n, lookupInboundMessageMeta as o, resolveWhatsAppLegacyGroupSessionKey as r, lookupInboundMessageMetaForTarget as s, resolveWhatsAppGroupSessionKey as t };
@@ -1,5 +1,5 @@
1
- import { r as jidToE164 } from "./targets-runtime-C-GiVn6Y.js";
2
- import { n as normalizeE164 } from "./text-runtime-DdX6-mC_.js";
1
+ import { r as jidToE164 } from "./targets-runtime-Bsh0HR9y.js";
2
+ import { n as normalizeE164 } from "./text-runtime-BTGkMN0o.js";
3
3
  //#region extensions/whatsapp/src/identity.ts
4
4
  const WHATSAPP_LID_RE = /@(lid|hosted\.lid)$/i;
5
5
  function normalizeDeviceScopedJid(jid) {
@@ -1,5 +1,5 @@
1
- import { n as getStatusCode, t as formatError } from "./session-errors-BAj9D2La.js";
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-Db-wfApd.js";
4
- import { t as getActiveWebListener } from "./active-listener-B4SDebQ6.js";
1
+ import { t as createWhatsAppLoginTool } from "./agent-tools-login-DfyToBpG.js";
2
+ 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-BQi9pZqQ.js";
3
+ import { n as getStatusCode, t as formatError } from "./session-errors-JuazczrA.js";
4
+ import { t as getActiveWebListener } from "./active-listener-5kHap439.js";
5
5
  export { WA_WEB_AUTH_DIR, createWhatsAppLoginTool, formatError, getActiveWebListener, getStatusCode, getWebAuthAgeMs, logWebSelfId, logoutWeb, pickWebChannel, readWebSelfId, resolveDefaultWebAuthDir, webAuthExists };
@@ -1,9 +1,8 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { a as resolveWhatsAppAccount } from "./accounts-4YgwroRU.js";
3
- import { a as resolveWhatsAppSocketTiming } from "./socket-timing-DhbVFjah.js";
4
- import { b as restoreCredsFromBackupIfNeeded } from "./auth-store-Db-wfApd.js";
5
- import { i as renderQrTerminal, t as createWaSocket } from "./session-DriaHt7V.js";
6
- import { a as closeWaSocketSoon, o as waitForWhatsAppLoginResult } from "./connection-controller-DkbrFSIn.js";
2
+ import { a as resolveWhatsAppAccount } from "./accounts-CKOFMPf-.js";
3
+ import { b as restoreCredsFromBackupIfNeeded } from "./auth-store-BQi9pZqQ.js";
4
+ import { c as resolveWhatsAppSocketTiming, t as createWaSocket, u as renderQrTerminal } from "./session-mxWFn0eS.js";
5
+ import { a as closeWaSocketSoon, o as waitForWhatsAppLoginResult } from "./connection-controller-C1rwfWb4.js";
7
6
  import { formatCliCommand } from "openclaw/plugin-sdk/cli-runtime";
8
7
  import { logInfo } from "openclaw/plugin-sdk/logging-core";
9
8
  import { danger, defaultRuntime, success } from "openclaw/plugin-sdk/runtime-env";
@@ -12,14 +11,47 @@ import { getRuntimeConfig } from "openclaw/plugin-sdk/runtime-config-snapshot";
12
11
  var login_exports = /* @__PURE__ */ __exportAll({ loginWeb: () => loginWeb });
13
12
  const QR_LINK_INSTRUCTION = "Open the WhatsApp app, go to Linked Devices, then scan this QR:";
14
13
  const CLEAR_TERMINAL = "\x1B[2J\x1B[H";
15
- async function loginWeb(verbose, waitForConnection, runtime = defaultRuntime, accountId) {
14
+ async function loginWeb(verbose, waitForConnection, runtime = defaultRuntime, accountId, options) {
16
15
  const cfg = getRuntimeConfig();
17
16
  const account = resolveWhatsAppAccount({
18
17
  cfg,
19
18
  accountId
20
19
  });
21
20
  const socketTiming = resolveWhatsAppSocketTiming(cfg);
22
- const restoredFromBackup = await restoreCredsFromBackupIfNeeded(account.authDir);
21
+ const restoredFromBackup = await restoreCredsFromBackupIfNeeded(account.authDir, { beforeCredentialPersistence: options?.beforeCredentialPersistence });
22
+ const credentialPersistenceState = { failure: null };
23
+ let resolveCredentialPersistenceFailure = (_failure) => {};
24
+ const credentialPersistenceFailurePromise = new Promise((resolve) => {
25
+ resolveCredentialPersistenceFailure = resolve;
26
+ });
27
+ const onCredentialPersistenceError = (error) => {
28
+ if (credentialPersistenceState.failure) return;
29
+ credentialPersistenceState.failure = { error };
30
+ resolveCredentialPersistenceFailure(credentialPersistenceState.failure);
31
+ };
32
+ const credentialPersistenceTasks = /* @__PURE__ */ new Set();
33
+ const onCredentialPersistenceTask = (task) => {
34
+ credentialPersistenceTasks.add(task);
35
+ task.then(() => credentialPersistenceTasks.delete(task), () => credentialPersistenceTasks.delete(task));
36
+ };
37
+ const waitForCredentialPersistence = async () => {
38
+ await new Promise((resolve) => {
39
+ setImmediate(resolve);
40
+ });
41
+ while (credentialPersistenceTasks.size > 0) await Promise.allSettled(credentialPersistenceTasks);
42
+ };
43
+ const credentialPersistenceOptions = options?.beforeCredentialPersistence ? {
44
+ beforeCredentialPersistence: async () => {
45
+ try {
46
+ await options.beforeCredentialPersistence?.();
47
+ } catch (error) {
48
+ onCredentialPersistenceError(error);
49
+ throw error;
50
+ }
51
+ },
52
+ onCredentialPersistenceError,
53
+ onCredentialPersistenceTask
54
+ } : {};
23
55
  let qrVersion = 0;
24
56
  const onQr = (qr) => {
25
57
  const currentQrVersion = ++qrVersion;
@@ -36,7 +68,8 @@ async function loginWeb(verbose, waitForConnection, runtime = defaultRuntime, ac
36
68
  let sock = await createWaSocket(false, verbose, {
37
69
  authDir: account.authDir,
38
70
  ...socketTiming,
39
- onQr
71
+ onQr,
72
+ ...credentialPersistenceOptions
40
73
  });
41
74
  logInfo("Waiting for WhatsApp connection...", runtime);
42
75
  try {
@@ -49,10 +82,17 @@ async function loginWeb(verbose, waitForConnection, runtime = defaultRuntime, ac
49
82
  waitForConnection,
50
83
  socketTiming,
51
84
  onQr,
85
+ ...credentialPersistenceOptions,
86
+ ...options?.beforeCredentialPersistence ? {
87
+ credentialPersistenceFailure: credentialPersistenceFailurePromise,
88
+ getCredentialPersistenceFailure: () => credentialPersistenceState.failure,
89
+ waitForCredentialPersistence
90
+ } : {},
52
91
  onSocketReplaced: (replacementSock) => {
53
92
  sock = replacementSock;
54
93
  }
55
94
  });
95
+ if (credentialPersistenceState.failure) throw credentialPersistenceState.failure.error;
56
96
  if (result.outcome === "connected") {
57
97
  runtime.log(success(result.restarted ? "✅ Linked after restart; web session ready." : restoredFromBackup ? "✅ Recovered from creds.json.bak; web session ready." : "✅ Linked! Credentials saved for future sends."));
58
98
  return;
@@ -1,10 +1,9 @@
1
- import { a as resolveWhatsAppAccount } from "./accounts-4YgwroRU.js";
2
- import { t as formatError } from "./session-errors-BAj9D2La.js";
3
- import { a as resolveWhatsAppSocketTiming } from "./socket-timing-DhbVFjah.js";
4
- import { c as logoutWeb, f as readWebAuthExistsForDecision, g as readWebSelfId, n as WHATSAPP_AUTH_UNSTABLE_CODE } from "./auth-store-Db-wfApd.js";
5
- import { t as createWaSocket } from "./session-DriaHt7V.js";
6
- import { t as getActiveWebListener } from "./active-listener-B4SDebQ6.js";
7
- import { i as closeWaSocket, o as waitForWhatsAppLoginResult, t as WHATSAPP_LOGGED_OUT_QR_MESSAGE } from "./connection-controller-DkbrFSIn.js";
1
+ import { a as resolveWhatsAppAccount } from "./accounts-CKOFMPf-.js";
2
+ import { c as logoutWeb, f as readWebAuthExistsForDecision, g as readWebSelfId, n as WHATSAPP_AUTH_UNSTABLE_CODE } from "./auth-store-BQi9pZqQ.js";
3
+ import { c as resolveWhatsAppSocketTiming, t as createWaSocket } from "./session-mxWFn0eS.js";
4
+ import { t as formatError } from "./session-errors-JuazczrA.js";
5
+ import { t as getActiveWebListener } from "./active-listener-5kHap439.js";
6
+ import { i as closeWaSocket, o as waitForWhatsAppLoginResult, t as WHATSAPP_LOGGED_OUT_QR_MESSAGE } from "./connection-controller-C1rwfWb4.js";
8
7
  import { logInfo } from "openclaw/plugin-sdk/logging-core";
9
8
  import { danger, defaultRuntime, info, success } from "openclaw/plugin-sdk/runtime-env";
10
9
  import { renderQrPngDataUrl } from "openclaw/plugin-sdk/media-runtime";
@@ -1,6 +1,6 @@
1
1
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
2
2
  //#region extensions/whatsapp/login-qr-runtime.ts
3
- const loadLoginQrModule = createLazyRuntimeModule(() => import("./login-qr-BjId7dll.js"));
3
+ const loadLoginQrModule = createLazyRuntimeModule(() => import("./login-qr-X-CZHOk9.js"));
4
4
  async function startWebLoginWithQr(...args) {
5
5
  const { startWebLoginWithQr: startWebLoginWithQrLocal } = await loadLoginQrModule();
6
6
  return await startWebLoginWithQrLocal(...args);