@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,7 +1,7 @@
1
- import { a as resolveWhatsAppAccount } from "./accounts-4YgwroRU.js";
2
- import { n as isSelfChatMode } from "./targets-runtime-C-GiVn6Y.js";
3
- import { n as normalizeE164 } from "./text-runtime-DdX6-mC_.js";
4
- import { a as getSelfIdentity, o as getSenderIdentity } from "./identity-Dqft3mFA.js";
1
+ import { a as resolveWhatsAppAccount } from "./accounts-CKOFMPf-.js";
2
+ import { n as isSelfChatMode } from "./targets-runtime-Bsh0HR9y.js";
3
+ import { n as normalizeE164 } from "./text-runtime-BTGkMN0o.js";
4
+ import { a as getSelfIdentity, o as getSenderIdentity } from "./identity-D7L8LCuH.js";
5
5
  import { defaultRuntime } from "openclaw/plugin-sdk/runtime-env";
6
6
  import { resolveChannelGroupPolicy, resolveChannelGroupRequireMention } from "openclaw/plugin-sdk/channel-policy";
7
7
  import { createChannelPairingChallengeIssuer } from "openclaw/plugin-sdk/channel-pairing";
@@ -1,5 +1,4 @@
1
1
  import { DEFAULT_ACCOUNT_ID, mergeAccountConfig, resolveAccountEntry, resolveMergedAccountConfig } from "openclaw/plugin-sdk/account-core";
2
- import { resolveChannelStreamingBlockEnabled, resolveChannelStreamingChunkMode } from "openclaw/plugin-sdk/channel-outbound";
3
2
  //#region extensions/whatsapp/src/account-config.ts
4
3
  function resolveWhatsAppDefaultAccountSharedConfig(cfg) {
5
4
  const defaultAccount = resolveAccountEntry(cfg.channels?.whatsapp?.accounts, DEFAULT_ACCOUNT_ID);
@@ -32,15 +31,12 @@ function resolveMergedWhatsAppAccountConfig(params) {
32
31
  accountId,
33
32
  omitKeys: ["defaultAccount"]
34
33
  });
35
- const merged = accountId === DEFAULT_ACCOUNT_ID ? base : resolveMergedNamedWhatsAppAccountConfig({
36
- cfg: params.cfg,
37
- accountId
38
- });
39
34
  return {
40
35
  accountId,
41
- ...merged,
42
- chunkMode: resolveChannelStreamingChunkMode(merged) ?? merged.chunkMode,
43
- blockStreaming: resolveChannelStreamingBlockEnabled(merged) ?? merged.blockStreaming
36
+ ...accountId === DEFAULT_ACCOUNT_ID ? base : resolveMergedNamedWhatsAppAccountConfig({
37
+ cfg: params.cfg,
38
+ accountId
39
+ })
44
40
  };
45
41
  }
46
42
  //#endregion
@@ -1,4 +1,4 @@
1
- import { t as resolveMergedWhatsAppAccountConfig } from "./account-config-6PTOSfaI.js";
1
+ import { t as resolveMergedWhatsAppAccountConfig } from "./account-config-LiT9wWH9.js";
2
2
  import { n as listConfiguredAccountIds, r as resolveDefaultWhatsAppAccountId, t as listAccountIds } from "./account-ids-CB5SOWjc.js";
3
3
  import { n as hasWebCredsRegularFileSync, r as hasWebCredsSync } from "./creds-files-B1kSWtBg.js";
4
4
  import fs from "node:fs";
@@ -89,9 +89,8 @@ function resolveWhatsAppAccount(params) {
89
89
  mentionPatterns: merged.mentionPatterns,
90
90
  historyLimit: merged.historyLimit,
91
91
  textChunkLimit: merged.textChunkLimit,
92
- chunkMode: merged.chunkMode,
92
+ streaming: merged.streaming,
93
93
  mediaMaxMb: merged.mediaMaxMb,
94
- blockStreaming: merged.blockStreaming,
95
94
  ackReaction: merged.ackReaction,
96
95
  reactionLevel: merged.reactionLevel,
97
96
  groups: merged.groups,
@@ -1,6 +1,6 @@
1
- import { a as resolveWhatsAppAccount } from "./accounts-4YgwroRU.js";
2
- import { t as resolveWhatsAppOutboundTarget } from "./resolve-outbound-target-CcdugbDf.js";
3
- import { g as resolveWhatsAppReactionLevel, r as sendReactionWhatsApp } from "./send-C5CpFcBG.js";
1
+ import { a as resolveWhatsAppAccount } from "./accounts-CKOFMPf-.js";
2
+ import { t as resolveWhatsAppOutboundTarget } from "./resolve-outbound-target-BR97fAbB.js";
3
+ import { r as sendReactionWhatsApp, u as resolveWhatsAppReactionLevel } from "./send-D9Ydnn4o.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-DPahAqxV.js";
1
+ import { t as handleWhatsAppAction } from "./action-runtime-Bf-12TIH.js";
2
2
  export { handleWhatsAppAction };
@@ -1,2 +1,2 @@
1
- import { t as handleWhatsAppAction } from "./action-runtime-DPahAqxV.js";
1
+ import { t as handleWhatsAppAction } from "./action-runtime-Bf-12TIH.js";
2
2
  export { handleWhatsAppAction };
@@ -1,11 +1,11 @@
1
1
  import { r as resolveDefaultWhatsAppAccountId } from "./account-ids-CB5SOWjc.js";
2
- import { t as getRegisteredWhatsAppConnectionController } from "./connection-controller-registry-TSX_udJp.js";
2
+ import { n as getWhatsAppConnectionController } from "./connection-controller-runtime-context-CbTsqmPT.js";
3
3
  //#region extensions/whatsapp/src/active-listener.ts
4
4
  function resolveWebAccountId(params) {
5
5
  return (params.accountId ?? "").trim() || resolveDefaultWhatsAppAccountId(params.cfg);
6
6
  }
7
7
  function getActiveWebListener(accountId) {
8
- return getRegisteredWhatsAppConnectionController(accountId)?.getActiveListener() ?? null;
8
+ return getWhatsAppConnectionController(accountId)?.getActiveListener() ?? null;
9
9
  }
10
10
  //#endregion
11
11
  export { resolveWebAccountId as n, getActiveWebListener as t };
@@ -13,10 +13,7 @@ function createWhatsAppLoginTool() {
13
13
  name: "whatsapp_login",
14
14
  description: "Generate a WhatsApp QR code for linking, or wait for the scan to complete.",
15
15
  parameters: Type.Object({
16
- action: Type.Unsafe({
17
- type: "string",
18
- enum: ["start", "wait"]
19
- }),
16
+ action: Type.Enum(["start", "wait"], { type: "string" }),
20
17
  timeoutMs: optionalPositiveIntegerSchema(),
21
18
  force: Type.Optional(Type.Boolean()),
22
19
  accountId: Type.Optional(Type.String()),
package/dist/api.js CHANGED
@@ -1,29 +1,28 @@
1
1
  import { r as resolveDefaultWhatsAppAccountId, t as listAccountIds } from "./account-ids-CB5SOWjc.js";
2
- import { a as resolveWhatsAppAccount, i as listWhatsAppAuthDirs, n as hasAnyWhatsAppAuth, o as resolveWhatsAppAuthDir, r as listEnabledWhatsAppAccounts, s as resolveWhatsAppMediaMaxBytes, t as DEFAULT_WHATSAPP_MEDIA_MAX_MB } from "./accounts-4YgwroRU.js";
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
- import { t as resolveWhatsAppOutboundTarget } from "./resolve-outbound-target-CcdugbDf.js";
5
- import "./send-C5CpFcBG.js";
6
- import { n as getStatusCode, t as formatError } from "./session-errors-BAj9D2La.js";
7
- import { n as createWhatsAppSocketOperationTimeoutAdapter, t as DEFAULT_WHATSAPP_SOCKET_TIMING } from "./socket-timing-DhbVFjah.js";
8
- import { c as toWhatsappJidWithLid, i as markdownToWhatsApp, n as isSelfChatMode, o as resolveJidToE164, r as jidToE164, s as toWhatsappJid, t as assertWebChannel } from "./targets-runtime-C-GiVn6Y.js";
9
- import { n as normalizeE164, r as resolveUserPath } from "./text-runtime-DdX6-mC_.js";
10
- import { n as WHATSAPP_LEGACY_OUTBOUND_SEND_DEP_KEYS, t as whatsappPlugin } from "./channel-BWp7h1uY.js";
2
+ import { a as resolveWhatsAppAccount, i as listWhatsAppAuthDirs, n as hasAnyWhatsAppAuth, o as resolveWhatsAppAuthDir, r as listEnabledWhatsAppAccounts, s as resolveWhatsAppMediaMaxBytes, t as DEFAULT_WHATSAPP_MEDIA_MAX_MB } from "./accounts-CKOFMPf-.js";
3
+ import { a as normalizeWhatsAppAllowFromEntries, c as normalizeWhatsAppTarget, i as looksLikeWhatsAppTargetId, r as isWhatsAppUserTarget, s as normalizeWhatsAppMessagingTarget, t as isWhatsAppGroupJid } from "./normalize-target-DSZnHkKF.js";
4
+ import { t as resolveWhatsAppOutboundTarget } from "./resolve-outbound-target-BR97fAbB.js";
5
+ import "./send-D9Ydnn4o.js";
6
+ import { c as toWhatsappJidWithLid, i as markdownToWhatsApp, n as isSelfChatMode, o as resolveJidToE164, r as jidToE164, s as toWhatsappJid, t as assertWebChannel } from "./targets-runtime-Bsh0HR9y.js";
7
+ import { n as normalizeE164, r as resolveUserPath } from "./text-runtime-BTGkMN0o.js";
8
+ import { n as resolveWhatsAppGroupIntroHint, r as WHATSAPP_LEGACY_OUTBOUND_SEND_DEP_KEYS, t as whatsappPlugin } from "./channel-DbadDUDD.js";
11
9
  import { t as whatsappCommandPolicy } from "./command-policy-BIOSHySD.js";
12
- import { a as resolveWhatsAppGroupRequireMention, o as resolveWhatsAppGroupToolPolicy, s as resolveWhatsAppGroupIntroHint } from "./setup-core-DH-DFPLY.js";
13
- import "./config-schema-mBX2nmn1.js";
14
- import { t as whatsappSetupPlugin } from "./channel.setup-CURc5rEt.js";
10
+ import { a as resolveWhatsAppGroupRequireMention, o as resolveWhatsAppGroupToolPolicy } from "./setup-core-3aSOoK2T.js";
11
+ import "./config-schema-BZ8h1hWA.js";
12
+ import { t as whatsappSetupPlugin } from "./channel.setup-BZ-po8fg.js";
15
13
  import { t as DEFAULT_WEB_MEDIA_BYTES } from "./constants-HU41RHGI.js";
16
- import { n as listWhatsAppDirectoryGroupsFromConfig, r as listWhatsAppDirectoryPeersFromConfig } from "./directory-config-Dijefxc3.js";
17
- import { n as testing } from "./access-control-DYE5dXna.js";
18
- import { _ as extractLocationData, b as extractText, d as normalizeMessageContent, f as resolveInboundMediaMimetype, h as extractContextInfo, p as describeReplyContext, t as createWebSendApi } from "./send-api-DLlXl8CH.js";
19
- import { r as waitForWaConnection, t as createWaSocket } from "./session-DriaHt7V.js";
14
+ import { n as listWhatsAppDirectoryGroupsFromConfig, r as listWhatsAppDirectoryPeersFromConfig } from "./directory-config-CLBQrjtC.js";
15
+ import { n as testing } from "./access-control-DazDX3RB.js";
16
+ import { _ as extractLocationData, b as extractText, d as normalizeMessageContent, f as resolveInboundMediaMimetype, h as extractContextInfo, p as describeReplyContext, t as createWebSendApi } from "./send-api-W33lI2nR.js";
17
+ import { a as createWhatsAppSocketOperationTimeoutAdapter, i as DEFAULT_WHATSAPP_SOCKET_TIMING, r as waitForWaConnection, t as createWaSocket } from "./session-mxWFn0eS.js";
18
+ import { n as getStatusCode, t as formatError } from "./session-errors-JuazczrA.js";
20
19
  import "openclaw/plugin-sdk/channel-actions";
21
20
  import "openclaw/plugin-sdk/account-resolution";
22
21
  import "openclaw/plugin-sdk/core";
23
- import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
24
22
  import "openclaw/plugin-sdk/account-id";
23
+ import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
25
24
  import { formatLocationText } from "openclaw/plugin-sdk/channel-inbound";
26
- createLazyRuntimeModule(() => import("./channel.runtime-CAssfx9p.js"));
25
+ createLazyRuntimeModule(() => import("./channel.runtime-BDDy4Lhz.js"));
27
26
  //#endregion
28
27
  //#region extensions/whatsapp/src/qa-driver.runtime.ts
29
28
  function isRecord(value) {
@@ -1,10 +1,14 @@
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-C5CpFcBG.js";
3
- import "./normalize-Bxwqo-bW.js";
1
+ import { r as resolveDefaultWhatsAppAccountId } from "./account-ids-CB5SOWjc.js";
2
+ import "./accounts-CKOFMPf-.js";
3
+ import { s as normalizeWhatsAppMessagingTarget } from "./normalize-target-DSZnHkKF.js";
4
+ import { i as sendTypingWhatsApp, t as sendMessageWhatsApp } from "./send-D9Ydnn4o.js";
4
5
  import { n as getWhatsAppRuntime } from "./runtime-BfAdAEYT.js";
6
+ import "./normalize-C-Z16y7Q.js";
7
+ import { i as unregisterWhatsAppApprovalReactionTarget, r as registerWhatsAppApprovalReactionTarget } from "./approval-reactions-BGQoz25s.js";
5
8
  import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
6
- import { buildApprovalReactionPendingContent } from "openclaw/plugin-sdk/approval-reaction-runtime";
9
+ import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
7
10
  import { buildChannelApprovalNativeTargetKey } from "openclaw/plugin-sdk/approval-native-runtime";
11
+ import { buildApprovalReactionPendingContent } from "openclaw/plugin-sdk/approval-reaction-runtime";
8
12
  import { buildChannelApprovalExpiredText, buildChannelApprovalResolvedText, createChannelApprovalNativeRuntimeAdapter, resolvePreparedApprovalAccountId } from "openclaw/plugin-sdk/approval-handler-runtime";
9
13
  //#region extensions/whatsapp/src/approval-handler.runtime.ts
10
14
  const log = createSubsystemLogger("whatsapp/approvals");
@@ -40,14 +44,15 @@ const whatsappApprovalNativeRuntime = createChannelApprovalNativeRuntimeAdapter(
40
44
  })
41
45
  },
42
46
  transport: {
43
- prepareTarget: ({ plannedTarget, accountId }) => {
47
+ prepareTarget: ({ cfg, plannedTarget, accountId }) => {
44
48
  const to = normalizeWhatsAppMessagingTarget(plannedTarget.target.to);
45
49
  if (!to) return null;
46
50
  const prepared = {
47
51
  to,
48
52
  accountId: resolvePreparedApprovalAccountId({
49
53
  plannedAccountId: plannedTarget.target.accountId,
50
- contextAccountId: accountId
54
+ contextAccountId: accountId,
55
+ fallbackAccountId: cfg ? resolveDefaultWhatsAppAccountId(cfg) : DEFAULT_ACCOUNT_ID
51
56
  })
52
57
  };
53
58
  return {
@@ -59,13 +64,13 @@ const whatsappApprovalNativeRuntime = createChannelApprovalNativeRuntimeAdapter(
59
64
  const verbose = getWhatsAppRuntime().logging.shouldLogVerbose();
60
65
  await sendTypingWhatsApp(preparedTarget.to, {
61
66
  cfg,
62
- ...preparedTarget.accountId ? { accountId: preparedTarget.accountId } : {}
67
+ accountId: preparedTarget.accountId
63
68
  }).catch(() => {});
64
69
  const result = await sendMessageWhatsApp(preparedTarget.to, pendingPayload.reactionPayload.text ?? "", {
65
70
  cfg,
66
71
  verbose,
67
- preserveLeadingWhitespace: true,
68
- ...preparedTarget.accountId ? { accountId: preparedTarget.accountId } : {}
72
+ accountId: preparedTarget.accountId,
73
+ preserveLeadingWhitespace: true
69
74
  });
70
75
  if (!result.messageId) return null;
71
76
  return {
@@ -80,8 +85,8 @@ const whatsappApprovalNativeRuntime = createChannelApprovalNativeRuntimeAdapter(
80
85
  await sendMessageWhatsApp(entry.to, payload.text, {
81
86
  cfg,
82
87
  verbose,
88
+ accountId: entry.accountId,
83
89
  preserveLeadingWhitespace: true,
84
- ...entry.accountId ? { accountId: entry.accountId } : {},
85
90
  quotedMessageKey: {
86
91
  id: entry.messageId,
87
92
  remoteJid: entry.remoteJid,
@@ -92,23 +97,24 @@ const whatsappApprovalNativeRuntime = createChannelApprovalNativeRuntimeAdapter(
92
97
  },
93
98
  interactions: {
94
99
  bindPending: ({ entry, request, view, pendingPayload }) => registerWhatsAppApprovalReactionTarget({
95
- accountId: entry.accountId ?? "",
100
+ accountId: entry.accountId,
96
101
  remoteJid: entry.remoteJid,
97
102
  messageId: entry.messageId,
98
103
  approvalId: request.id,
104
+ approvalKind: view.approvalKind,
99
105
  allowedDecisions: pendingPayload.reactionPayload.allowedDecisions,
100
106
  ttlMs: Math.max(1, view.expiresAtMs - Date.now())
101
107
  }) ? true : null,
102
108
  unbindPending: ({ entry }) => {
103
109
  unregisterWhatsAppApprovalReactionTarget({
104
- accountId: entry.accountId ?? "",
110
+ accountId: entry.accountId,
105
111
  remoteJid: entry.remoteJid,
106
112
  messageId: entry.messageId
107
113
  });
108
114
  },
109
115
  cancelDelivered: ({ entry }) => {
110
116
  unregisterWhatsAppApprovalReactionTarget({
111
- accountId: entry.accountId ?? "",
117
+ accountId: entry.accountId,
112
118
  remoteJid: entry.remoteJid,
113
119
  messageId: entry.messageId
114
120
  });
@@ -0,0 +1,373 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
+ import { a as resolveWhatsAppAccount } from "./accounts-CKOFMPf-.js";
3
+ import { t as getOptionalWhatsAppRuntime } from "./runtime-BfAdAEYT.js";
4
+ import { c as getWhatsAppApprovalApprovers, l as whatsappApprovalAuth } from "./group-session-key-CLTZeH_F.js";
5
+ import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
6
+ import { createApprovalReactionTargetStore, listApprovalReactionBindings, resolveTypedApprovalReactionTarget } from "openclaw/plugin-sdk/approval-reaction-runtime";
7
+ //#region extensions/whatsapp/src/approval-reactions.ts
8
+ var approval_reactions_exports = /* @__PURE__ */ __exportAll({
9
+ clearWhatsAppApprovalReactionTargetsForTest: () => clearWhatsAppApprovalReactionTargetsForTest,
10
+ maybeResolveWhatsAppApprovalReaction: () => maybeResolveWhatsAppApprovalReaction,
11
+ prepareWhatsAppApprovalPayloadForDelivery: () => prepareWhatsAppApprovalPayloadForDelivery,
12
+ registerWhatsAppApprovalReactionTarget: () => registerWhatsAppApprovalReactionTarget,
13
+ registerWhatsAppApprovalReactionTargetForDeliveredPayload: () => registerWhatsAppApprovalReactionTargetForDeliveredPayload,
14
+ resolveWhatsAppApprovalReactionTargetWithPersistence: () => resolveWhatsAppApprovalReactionTargetWithPersistence,
15
+ unregisterWhatsAppApprovalReactionTarget: () => unregisterWhatsAppApprovalReactionTarget
16
+ });
17
+ const PERSISTENT_NAMESPACE = "whatsapp.approval-reactions";
18
+ const PERSISTENT_MAX_ENTRIES = 1e3;
19
+ const DEFAULT_REACTION_TARGET_TTL_MS = 1440 * 60 * 1e3;
20
+ const DELIVERY_BINDING_CHANNEL_DATA_KEY = "whatsappApprovalReactionBindingV1";
21
+ const resolverRuntimeLoader = createLazyRuntimeModule(() => import("./approval-resolver-DoeBBt22.js"));
22
+ const whatsappApprovalReactionTargets = createApprovalReactionTargetStore({
23
+ namespace: PERSISTENT_NAMESPACE,
24
+ maxEntries: PERSISTENT_MAX_ENTRIES,
25
+ defaultTtlMs: DEFAULT_REACTION_TARGET_TTL_MS,
26
+ openStore: (storeParams) => getOptionalWhatsAppRuntime()?.state.openKeyedStore(storeParams),
27
+ logPersistentError: reportPersistentApprovalReactionError,
28
+ readPersistedTarget
29
+ });
30
+ const loadApprovalResolver = resolverRuntimeLoader;
31
+ function buildReactionTargetKey(params) {
32
+ const accountId = params.accountId.trim();
33
+ const remoteJid = params.remoteJid.trim();
34
+ const messageId = params.messageId.trim();
35
+ if (!accountId || !remoteJid || !messageId) return null;
36
+ return `${accountId}:${remoteJid}:${messageId}`;
37
+ }
38
+ function addCandidateRemoteJid(target, value) {
39
+ const remoteJid = value?.trim();
40
+ if (remoteJid && !target.includes(remoteJid)) target.push(remoteJid);
41
+ }
42
+ function reportPersistentApprovalReactionError(error) {
43
+ try {
44
+ getOptionalWhatsAppRuntime()?.logging.getChildLogger({
45
+ plugin: "whatsapp",
46
+ feature: "approval-reaction-state"
47
+ }).warn("WhatsApp persistent approval reaction state failed", { error: String(error) });
48
+ } catch {}
49
+ }
50
+ function reportApprovalBindingCorrelationMismatch(binding) {
51
+ try {
52
+ getOptionalWhatsAppRuntime()?.logging.getChildLogger({
53
+ plugin: "whatsapp",
54
+ feature: "approval-reaction-state"
55
+ }).warn("WhatsApp approval prompt text failed binding correlation; reactions disabled", {
56
+ approvalId: binding.approvalId,
57
+ approvalKind: binding.approvalKind
58
+ });
59
+ } catch {}
60
+ }
61
+ function readPersistedTarget(target) {
62
+ const value = target;
63
+ if (!value || typeof value.approvalId !== "string" || !Array.isArray(value.allowedDecisions) || value.approvalKind !== "exec" && value.approvalKind !== "plugin") return null;
64
+ return {
65
+ approvalId: value.approvalId,
66
+ approvalKind: value.approvalKind,
67
+ allowedDecisions: value.allowedDecisions
68
+ };
69
+ }
70
+ function listWhatsAppApprovalReactionBindings(allowedDecisions) {
71
+ return listApprovalReactionBindings({ allowedDecisions });
72
+ }
73
+ const APPROVAL_ID_LINE_RE = /^\s*ID:\s*(\S(?:.*\S)?)\s*$/i;
74
+ const APPROVAL_KIND_LINE_RE = /^\s*(?:\S+\s+)?(Exec|Plugin) approval required\s*$/i;
75
+ function isApprovalDecision(value) {
76
+ return value === "allow-once" || value === "allow-always" || value === "deny";
77
+ }
78
+ function readStrictDecisionList(value) {
79
+ if (!Array.isArray(value) || value.length === 0 || !value.every(isApprovalDecision)) return null;
80
+ return new Set(value).size === value.length ? [...value] : null;
81
+ }
82
+ function readStrictApprovalMetadata(payload) {
83
+ const value = payload.channelData?.execApproval;
84
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
85
+ const record = value;
86
+ const approvalId = record.approvalId;
87
+ const approvalKind = record.approvalKind;
88
+ const allowedDecisions = readStrictDecisionList(record.allowedDecisions);
89
+ if (typeof approvalId !== "string" || !approvalId || approvalId !== approvalId.trim() || approvalKind !== "exec" && approvalKind !== "plugin" || !allowedDecisions) return null;
90
+ return {
91
+ version: 1,
92
+ approvalId,
93
+ approvalKind,
94
+ allowedDecisions
95
+ };
96
+ }
97
+ function listTypedApprovalActions(presentation) {
98
+ return presentation.blocks.flatMap((block) => {
99
+ if (block.type === "buttons") return block.buttons.flatMap((button) => button.action?.type === "approval" ? [button.action] : []);
100
+ return [];
101
+ });
102
+ }
103
+ function decisionSetsMatch(left, right) {
104
+ return left.length === right.length && left.every((decision) => right.includes(decision));
105
+ }
106
+ function readTypedApprovalDeliveryBinding(params) {
107
+ const metadata = readStrictApprovalMetadata(params.payload);
108
+ if (!metadata) return null;
109
+ const actions = listTypedApprovalActions(params.presentation);
110
+ if (actions.length === 0 || actions.some((action) => action.approvalId !== metadata.approvalId || action.approvalKind !== metadata.approvalKind)) return null;
111
+ const actionDecisions = actions.map((action) => action.decision);
112
+ if (new Set(actionDecisions).size !== actionDecisions.length || !decisionSetsMatch(metadata.allowedDecisions, actionDecisions)) return null;
113
+ return metadata;
114
+ }
115
+ function visibleApprovalBindingMatches(text, binding) {
116
+ const lines = (text ?? "").split(/\r?\n/);
117
+ const kindMatches = lines.map((line) => line.match(APPROVAL_KIND_LINE_RE)).filter((match) => Boolean(match));
118
+ const idMatches = lines.map((line) => line.match(APPROVAL_ID_LINE_RE)).filter((match) => Boolean(match));
119
+ const visibleKind = kindMatches[0]?.[1]?.toLowerCase();
120
+ if (kindMatches.length !== 1 || idMatches.length !== 1 || visibleKind !== binding.approvalKind || idMatches[0]?.[1] !== binding.approvalId) return false;
121
+ const hintIndices = lines.flatMap((line, index) => line.trim().toLowerCase() === "react with:" ? [index] : []);
122
+ if (hintIndices.length !== 1) return false;
123
+ const hintIndex = hintIndices[0];
124
+ if (hintIndex === void 0) return false;
125
+ let cursor = hintIndex + 1;
126
+ while (cursor < lines.length && !lines[cursor]?.trim()) cursor += 1;
127
+ const decisionLines = [];
128
+ while (cursor < lines.length) {
129
+ const decisionLine = lines[cursor]?.trim();
130
+ if (!decisionLine) break;
131
+ decisionLines.push(decisionLine);
132
+ cursor += 1;
133
+ }
134
+ const knownBindings = listWhatsAppApprovalReactionBindings([
135
+ "allow-once",
136
+ "allow-always",
137
+ "deny"
138
+ ]);
139
+ const visibleDecisions = decisionLines.map((line) => knownBindings.find((entry) => `${entry.emoji} ${entry.label}` === line)?.decision);
140
+ if (!visibleDecisions.every(isApprovalDecision)) return false;
141
+ return new Set(visibleDecisions).size === visibleDecisions.length && decisionSetsMatch(binding.allowedDecisions, visibleDecisions);
142
+ }
143
+ function readDeliveredApprovalBinding(payload) {
144
+ const metadata = readStrictApprovalMetadata(payload);
145
+ const value = payload.channelData?.[DELIVERY_BINDING_CHANNEL_DATA_KEY];
146
+ if (!metadata || !value || typeof value !== "object" || Array.isArray(value)) return null;
147
+ const record = value;
148
+ const allowedDecisions = readStrictDecisionList(record.allowedDecisions);
149
+ if (record.version !== 1 || record.approvalId !== metadata.approvalId || record.approvalKind !== metadata.approvalKind || !allowedDecisions || !decisionSetsMatch(metadata.allowedDecisions, allowedDecisions)) return null;
150
+ return metadata;
151
+ }
152
+ /** Preserve a validated typed approval binding until the platform message id is known. */
153
+ function prepareWhatsAppApprovalPayloadForDelivery(params) {
154
+ const binding = readTypedApprovalDeliveryBinding(params);
155
+ if (!binding) return null;
156
+ if (!visibleApprovalBindingMatches(params.payload.text, binding)) {
157
+ reportApprovalBindingCorrelationMismatch(binding);
158
+ return null;
159
+ }
160
+ return {
161
+ ...params.payload,
162
+ channelData: {
163
+ ...params.payload.channelData,
164
+ [DELIVERY_BINDING_CHANNEL_DATA_KEY]: binding
165
+ }
166
+ };
167
+ }
168
+ function registerWhatsAppApprovalReactionTarget(params) {
169
+ const key = buildReactionTargetKey(params);
170
+ const approvalId = params.approvalId.trim();
171
+ const allowedDecisions = listWhatsAppApprovalReactionBindings(params.allowedDecisions).map((binding) => binding.decision);
172
+ if (!key || !approvalId || params.approvalKind !== "exec" && params.approvalKind !== "plugin" || allowedDecisions.length === 0) return null;
173
+ const target = {
174
+ approvalId,
175
+ approvalKind: params.approvalKind,
176
+ allowedDecisions
177
+ };
178
+ whatsappApprovalReactionTargets.register(key, target, { ttlMs: params.ttlMs });
179
+ return target;
180
+ }
181
+ function listWhatsAppDeliveredMessageIdentities(results) {
182
+ const identities = [];
183
+ const seen = /* @__PURE__ */ new Set();
184
+ const add = (params) => {
185
+ if (params.channel && params.channel !== "whatsapp") return;
186
+ const messageId = params.messageId?.trim() ?? "";
187
+ const remoteJid = params.toJid?.trim() ?? "";
188
+ const key = `${remoteJid}:${messageId}`;
189
+ if (!messageId || messageId === "unknown" || !remoteJid || seen.has(key)) return;
190
+ seen.add(key);
191
+ identities.push({
192
+ messageId,
193
+ remoteJid
194
+ });
195
+ };
196
+ for (const result of results) {
197
+ if (result.channel !== "whatsapp") continue;
198
+ add(result);
199
+ for (const raw of result.receipt?.raw ?? []) add(raw);
200
+ for (const part of result.receipt?.parts ?? []) add({
201
+ channel: part.raw?.channel,
202
+ messageId: part.raw?.messageId ?? part.platformMessageId,
203
+ toJid: part.raw?.toJid
204
+ });
205
+ }
206
+ return identities;
207
+ }
208
+ /** Bind generic forwarded approvals to the exact WhatsApp messages accepted by Baileys. */
209
+ function registerWhatsAppApprovalReactionTargetForDeliveredPayload(params) {
210
+ if (params.target.channel.trim().toLowerCase() !== "whatsapp") return false;
211
+ const binding = readDeliveredApprovalBinding(params.payload);
212
+ if (!binding) return false;
213
+ if (!visibleApprovalBindingMatches(params.payload.text, binding)) {
214
+ reportApprovalBindingCorrelationMismatch(binding);
215
+ return false;
216
+ }
217
+ const accountId = resolveWhatsAppAccount({
218
+ cfg: params.cfg,
219
+ accountId: params.target.accountId
220
+ }).accountId;
221
+ let registered = false;
222
+ for (const { messageId, remoteJid } of listWhatsAppDeliveredMessageIdentities(params.results)) registered = Boolean(registerWhatsAppApprovalReactionTarget({
223
+ accountId,
224
+ remoteJid,
225
+ messageId,
226
+ approvalId: binding.approvalId,
227
+ approvalKind: binding.approvalKind,
228
+ allowedDecisions: binding.allowedDecisions,
229
+ ttlMs: params.ttlMs
230
+ })) || registered;
231
+ return registered;
232
+ }
233
+ function unregisterWhatsAppApprovalReactionTarget(params) {
234
+ const key = buildReactionTargetKey(params);
235
+ if (!key) return;
236
+ whatsappApprovalReactionTargets.delete(key);
237
+ }
238
+ function resolveTarget(params) {
239
+ const resolved = resolveTypedApprovalReactionTarget({
240
+ target: params.target,
241
+ reactionKey: params.reactionKey
242
+ });
243
+ return resolved ? {
244
+ approvalId: resolved.approvalId,
245
+ approvalKind: resolved.approvalKind,
246
+ decision: resolved.decision
247
+ } : null;
248
+ }
249
+ async function resolveWhatsAppApprovalReactionTargetWithPersistence(params) {
250
+ const key = buildReactionTargetKey(params);
251
+ if (!key) return null;
252
+ return resolveTarget({
253
+ target: await whatsappApprovalReactionTargets.lookup(key),
254
+ reactionKey: params.reactionKey
255
+ });
256
+ }
257
+ async function resolveWhatsAppApprovalReactionTargetFromCandidates(params) {
258
+ const candidateRemoteJids = [];
259
+ for (const observedRemoteJid of params.observedRemoteJids) {
260
+ addCandidateRemoteJid(candidateRemoteJids, observedRemoteJid);
261
+ try {
262
+ for (const candidate of await params.resolveReactionTargetJids?.(observedRemoteJid) ?? []) addCandidateRemoteJid(candidateRemoteJids, candidate);
263
+ } catch (error) {
264
+ params.logVerboseMessage?.(`whatsapp: approval reaction target JID mapping failed for ${observedRemoteJid}: ${String(error)}`);
265
+ }
266
+ }
267
+ for (const remoteJid of candidateRemoteJids) {
268
+ const target = await resolveWhatsAppApprovalReactionTargetWithPersistence({
269
+ accountId: params.accountId,
270
+ remoteJid,
271
+ messageId: params.messageId,
272
+ reactionKey: params.reactionKey
273
+ });
274
+ if (target) return {
275
+ ...target,
276
+ remoteJid
277
+ };
278
+ }
279
+ return null;
280
+ }
281
+ function readWhatsAppApprovalReactionEvent(params) {
282
+ const msg = params.msg;
283
+ const reaction = msg.message?.reactionMessage;
284
+ const reactionKey = reaction?.text?.trim() ?? "";
285
+ const messageId = reaction?.key?.id?.trim() ?? "";
286
+ const remoteJids = [];
287
+ addCandidateRemoteJid(remoteJids, reaction?.key?.remoteJid);
288
+ addCandidateRemoteJid(remoteJids, msg.key?.remoteJid);
289
+ const actorJid = msg.key?.participant?.trim() || (msg.key?.fromMe ? params.selfLid?.trim() ?? params.selfJid?.trim() ?? "" : msg.key?.remoteJid?.trim() ?? "");
290
+ if (!reactionKey || !messageId || remoteJids.length === 0 || !actorJid) return null;
291
+ return {
292
+ remoteJids,
293
+ messageId,
294
+ actorJid,
295
+ reactionKey
296
+ };
297
+ }
298
+ async function maybeResolveWhatsAppApprovalReaction(params) {
299
+ const event = readWhatsAppApprovalReactionEvent({
300
+ msg: params.msg,
301
+ selfJid: params.selfJid,
302
+ selfLid: params.selfLid
303
+ });
304
+ if (!event) return false;
305
+ const target = await resolveWhatsAppApprovalReactionTargetFromCandidates({
306
+ accountId: params.accountId,
307
+ observedRemoteJids: event.remoteJids,
308
+ messageId: event.messageId,
309
+ reactionKey: event.reactionKey,
310
+ resolveReactionTargetJids: params.resolveReactionTargetJids,
311
+ logVerboseMessage: params.logVerboseMessage
312
+ });
313
+ if (!target) return false;
314
+ const actorId = await params.resolveInboundJid(event.actorJid);
315
+ if (!actorId) {
316
+ params.logVerboseMessage?.(`whatsapp: approval reaction ignored for ${target.approvalId}; missing actor identity`);
317
+ return true;
318
+ }
319
+ if (getWhatsAppApprovalApprovers({
320
+ cfg: params.cfg,
321
+ accountId: params.accountId
322
+ }).length === 0) {
323
+ params.logVerboseMessage?.(`whatsapp: approval reaction denied id=${target.approvalId}; reactions require explicit approvers`);
324
+ return true;
325
+ }
326
+ if (!whatsappApprovalAuth.authorizeActorAction({
327
+ cfg: params.cfg,
328
+ accountId: params.accountId,
329
+ senderId: actorId,
330
+ action: "approve",
331
+ approvalKind: target.approvalKind
332
+ }).authorized) {
333
+ params.logVerboseMessage?.(`whatsapp: approval reaction denied id=${target.approvalId} sender=${actorId}`);
334
+ return true;
335
+ }
336
+ const { isApprovalNotFoundError, resolveWhatsAppApproval } = await loadApprovalResolver();
337
+ try {
338
+ const result = await resolveWhatsAppApproval({
339
+ cfg: params.cfg,
340
+ approvalId: target.approvalId,
341
+ approvalKind: target.approvalKind,
342
+ decision: target.decision,
343
+ senderId: actorId,
344
+ gatewayUrl: params.gatewayUrl
345
+ });
346
+ unregisterWhatsAppApprovalReactionTarget({
347
+ accountId: params.accountId,
348
+ remoteJid: target.remoteJid,
349
+ messageId: event.messageId
350
+ });
351
+ const canonicalDecision = "decision" in result.approval ? ` decision=${result.approval.decision}` : "";
352
+ params.logVerboseMessage?.(result.applied ? `whatsapp: approval reaction applied id=${target.approvalId} sender=${actorId} status=${result.approval.status}${canonicalDecision}` : `whatsapp: approval reaction already resolved id=${target.approvalId} sender=${actorId} status=${result.approval.status}${canonicalDecision}`);
353
+ return true;
354
+ } catch (error) {
355
+ if (isApprovalNotFoundError(error)) {
356
+ unregisterWhatsAppApprovalReactionTarget({
357
+ accountId: params.accountId,
358
+ remoteJid: target.remoteJid,
359
+ messageId: event.messageId
360
+ });
361
+ params.logVerboseMessage?.(`whatsapp: approval reaction ignored for expired approval id=${target.approvalId} sender=${actorId}`);
362
+ return true;
363
+ }
364
+ params.logVerboseMessage?.(`whatsapp: approval reaction failed id=${target.approvalId} sender=${actorId}: ${String(error)}`);
365
+ return true;
366
+ }
367
+ }
368
+ function clearWhatsAppApprovalReactionTargetsForTest() {
369
+ whatsappApprovalReactionTargets.clearForTest();
370
+ resolverRuntimeLoader.clear();
371
+ }
372
+ //#endregion
373
+ export { unregisterWhatsAppApprovalReactionTarget as i, maybeResolveWhatsAppApprovalReaction as n, registerWhatsAppApprovalReactionTarget as r, approval_reactions_exports as t };
@@ -2,9 +2,10 @@ import { isApprovalNotFoundError } from "openclaw/plugin-sdk/error-runtime";
2
2
  import { resolveApprovalOverGateway } from "openclaw/plugin-sdk/approval-gateway-runtime";
3
3
  //#region extensions/whatsapp/src/approval-resolver.ts
4
4
  async function resolveWhatsAppApproval(params) {
5
- await resolveApprovalOverGateway({
5
+ return await resolveApprovalOverGateway({
6
6
  cfg: params.cfg,
7
7
  approvalId: params.approvalId,
8
+ approvalKind: params.approvalKind,
8
9
  decision: params.decision,
9
10
  senderId: params.senderId,
10
11
  gatewayUrl: params.gatewayUrl,