@openclaw/whatsapp 2026.7.2-beta.7 → 2026.8.1-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 (48) hide show
  1. package/dist/{accounts-CSqLvCY5.js → accounts-BX2fZUyR.js} +1 -1
  2. package/dist/{action-runtime-BzfDFPbH.js → action-runtime-B4e3XFOY.js} +2 -2
  3. package/dist/action-runtime-api.js +1 -1
  4. package/dist/action-runtime.runtime.js +1 -1
  5. package/dist/{agent-tools-login-DE9MU98T.js → agent-tools-login-BjRpD-JQ.js} +5 -4
  6. package/dist/api.js +69 -127
  7. package/dist/{approval-handler.runtime-DrA59QSA.js → approval-handler.runtime-fgGZhALv.js} +4 -4
  8. package/dist/{approval-reactions-Cu66aYdq.js → approval-reactions-CmtJCxe_.js} +25 -73
  9. package/dist/auth-presence.js +1 -1
  10. package/dist/{auth-store-DcEpIOmE.js → auth-store-B_DQIdzp.js} +79 -12
  11. package/dist/call-tool-api.js +1 -1
  12. package/dist/{channel-Dg62olhy.js → channel-DJVQHz_V.js} +56 -160
  13. package/dist/channel-plugin-api.js +1 -1
  14. package/dist/{channel-react-action-J_YtyMGX.js → channel-react-action-d6OacTNj.js} +3 -3
  15. package/dist/{channel.runtime-BP0xNmLi.js → channel.runtime-RxuNGZ7w.js} +4 -4
  16. package/dist/channel.setup-Cmvd967u.js +14 -0
  17. package/dist/{connection-controller-BOB2MVKY.js → connection-controller-CUyZgGpf.js} +2 -3
  18. package/dist/contract-api.js +2 -3
  19. package/dist/{creds-files-B1kSWtBg.js → creds-files-W6B3EMZ8.js} +17 -1
  20. package/dist/{directory-config-DalGrfGN.js → directory-config-Pc4f07wB.js} +3 -3
  21. package/dist/directory-contract-api.js +1 -1
  22. package/dist/doctor-contract-api.js +37 -2
  23. package/dist/{group-session-key-DVMZlO3x.js → group-session-key-DmFc_Cqi.js} +23 -4
  24. package/dist/light-runtime-api.js +2 -2
  25. package/dist/{login-CvY2Dhch.js → login-D6_rfxTZ.js} +4 -4
  26. package/dist/{login-qr-Bncpb6js.js → login-qr-B0VyVSqQ.js} +4 -4
  27. package/dist/login-qr-runtime.js +1 -1
  28. package/dist/{monitor-CfkaUSL2.js → monitor-BCe5Mm-1.js} +574 -163
  29. package/dist/{question-reactions-CRsnyoMK.js → question-reactions-D3eAeB0i.js} +29 -78
  30. package/dist/runtime-api.js +9 -9
  31. package/dist/runtime-group-policy-DeSRFXEV.js +11 -0
  32. package/dist/{send-api-7wk6eQyW.js → send-api-DimZST3E.js} +86 -107
  33. package/dist/{send-D37ddk22.js → send-prK8F7Vj.js} +277 -16
  34. package/dist/setup-entry.js +1 -8
  35. package/dist/{setup-finalize-BZucx24W.js → setup-finalize-D3n71Uyx.js} +4 -4
  36. package/dist/setup-plugin-api.js +1 -1
  37. package/dist/{setup-surface-BkVcd769.js → setup-surface-BCZszf3l.js} +3 -3
  38. package/dist/{shared-CAxd15bp.js → shared-Dp9M3ZPX.js} +5 -6
  39. package/dist/{socket-close-DridEuzz.js → socket-close-09FojDO2.js} +4 -10
  40. package/openclaw.plugin.json +4 -0
  41. package/package.json +4 -5
  42. package/skills/wacli/SKILL.md +8 -1
  43. package/dist/access-control-pZcxTmd5.js +0 -363
  44. package/dist/approval-resolver-DoeBBt22.js +0 -16
  45. package/dist/channel.setup-pMwNVkCA.js +0 -19
  46. package/dist/identity-CPrT5aEU.js +0 -76
  47. package/dist/legacy-state-migrations-api.js +0 -2
  48. package/dist/state-migrations-CAMTrs2U.js +0 -33
@@ -1,5 +1,5 @@
1
1
  import { n as listConfiguredAccountIds, r as resolveDefaultWhatsAppAccountId, t as listAccountIds } from "./account-ids-CB5SOWjc.js";
2
- import { n as hasWebCredsRegularFileSync, r as hasWebCredsSync } from "./creds-files-B1kSWtBg.js";
2
+ import { n as hasWebCredsRegularFileSync, r as hasWebCredsSync } from "./creds-files-W6B3EMZ8.js";
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
5
5
  import { DEFAULT_ACCOUNT_ID, mergeAccountConfig, normalizeAccountId, resolveAccountEntry, resolveMergedAccountConfig, resolveUserPath } from "openclaw/plugin-sdk/account-core";
@@ -1,6 +1,6 @@
1
- import { a as resolveWhatsAppAccount } from "./accounts-CSqLvCY5.js";
1
+ import { a as resolveWhatsAppAccount } from "./accounts-BX2fZUyR.js";
2
2
  import { t as resolveWhatsAppOutboundTarget } from "./resolve-outbound-target-1GqbT1uX.js";
3
- import { r as sendReactionWhatsApp, u as resolveWhatsAppReactionLevel } from "./send-D37ddk22.js";
3
+ import { _ as resolveWhatsAppReactionLevel, r as sendReactionWhatsApp } from "./send-prK8F7Vj.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-BzfDFPbH.js";
1
+ import { t as handleWhatsAppAction } from "./action-runtime-B4e3XFOY.js";
2
2
  export { handleWhatsAppAction };
@@ -1,2 +1,2 @@
1
- import { t as handleWhatsAppAction } from "./action-runtime-BzfDFPbH.js";
1
+ import { t as handleWhatsAppAction } from "./action-runtime-B4e3XFOY.js";
2
2
  export { handleWhatsAppAction };
@@ -1,11 +1,12 @@
1
1
  import { startWebLoginWithQr, waitForWebLogin } from "./login-qr-runtime.js";
2
2
  import "./login-qr-api.js";
3
3
  import { optionalPositiveIntegerSchema, readPositiveIntegerParam } from "openclaw/plugin-sdk/channel-actions";
4
+ import { hasNonEmptyString } from "openclaw/plugin-sdk/string-coerce-runtime";
4
5
  import { Type } from "typebox";
5
6
  //#region extensions/whatsapp/src/agent-tools-login.ts
6
7
  const QR_DATA_URL_MAX_LENGTH = 16384;
7
- function readOptionalString(value) {
8
- return typeof value === "string" && value.trim() ? value : void 0;
8
+ function readLoginStringPreservingWhitespace(value) {
9
+ return hasNonEmptyString(value) ? value : void 0;
9
10
  }
10
11
  function createWhatsAppLoginTool() {
11
12
  return {
@@ -42,13 +43,13 @@ function createWhatsAppLoginTool() {
42
43
  };
43
44
  };
44
45
  const action = args?.action ?? "start";
45
- const accountId = readOptionalString(args.accountId);
46
+ const accountId = readLoginStringPreservingWhitespace(args.accountId);
46
47
  const timeoutMs = readPositiveIntegerParam(args, "timeoutMs");
47
48
  if (action === "wait") {
48
49
  const result = await waitForWebLogin({
49
50
  accountId,
50
51
  timeoutMs,
51
- currentQrDataUrl: readOptionalString(args.currentQrDataUrl)
52
+ currentQrDataUrl: readLoginStringPreservingWhitespace(args.currentQrDataUrl)
52
53
  });
53
54
  if (result.qrDataUrl) return renderQrReply({
54
55
  message: result.message,
package/dist/api.js CHANGED
@@ -1,108 +1,63 @@
1
- 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-CSqLvCY5.js";
1
+ 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-BX2fZUyR.js";
2
2
  import { r as resolveDefaultWhatsAppAccountId, t as listAccountIds } from "./account-ids-CB5SOWjc.js";
3
3
  import { a as normalizeWhatsAppAllowFromEntries, c as normalizeWhatsAppTarget, i as looksLikeWhatsAppTargetId, r as isWhatsAppUserTarget, s as normalizeWhatsAppMessagingTarget, t as isWhatsAppGroupJid } from "./normalize-target-CugRyONv.js";
4
4
  import { t as resolveWhatsAppOutboundTarget } from "./resolve-outbound-target-1GqbT1uX.js";
5
5
  import { c as toWhatsappJid, i as markdownToWhatsApp, l as toWhatsappJidWithLid, n as isSelfChatMode, r as jidToE164, s as resolveJidToE164, t as assertWebChannel } from "./targets-runtime-TMk0lGuy.js";
6
6
  import { n as resolveUserPath, t as normalizeE164 } from "./text-runtime-CaKLhowd.js";
7
- import { n as WHATSAPP_LEGACY_OUTBOUND_SEND_DEP_KEYS, t as whatsappPlugin } from "./channel-Dg62olhy.js";
8
- import { a as resolveWhatsAppGroupRequireMention, o as resolveWhatsAppGroupToolPolicy } from "./shared-CAxd15bp.js";
7
+ import { n as WHATSAPP_LEGACY_OUTBOUND_SEND_DEP_KEYS, t as whatsappPlugin } from "./channel-DJVQHz_V.js";
8
+ import { a as resolveWhatsAppGroupRequireMention, o as resolveWhatsAppGroupToolPolicy } from "./shared-Dp9M3ZPX.js";
9
9
  import { t as whatsappCommandPolicy } from "./command-policy-BIOSHySD.js";
10
- import { t as whatsappSetupPlugin } from "./channel.setup-pMwNVkCA.js";
10
+ import { t as whatsappSetupPlugin } from "./channel.setup-Cmvd967u.js";
11
11
  import { t as DEFAULT_WEB_MEDIA_BYTES } from "./constants-HU41RHGI.js";
12
- import { a as waitForWaConnection, o as DEFAULT_WHATSAPP_SOCKET_TIMING, r as createWaSocket, s as createWhatsAppSocketOperationTimeoutAdapter } from "./socket-close-DridEuzz.js";
12
+ import { a as waitForWaConnection, o as DEFAULT_WHATSAPP_SOCKET_TIMING, r as createWaSocket, s as createWhatsAppSocketOperationTimeoutAdapter } from "./socket-close-09FojDO2.js";
13
13
  import { n as getStatusCode, t as formatError } from "./session-errors-JuazczrA.js";
14
- import { n as listWhatsAppDirectoryGroupsFromConfig, r as listWhatsAppDirectoryPeersFromConfig } from "./directory-config-DalGrfGN.js";
15
- import { n as testing } from "./access-control-pZcxTmd5.js";
16
- import { d as normalizeMessageContent, f as describeReplyContext, g as extractLocationData, m as extractContextInfo, t as createWebSendApi, x as resolveInboundMediaMimetype, y as extractText } from "./send-api-7wk6eQyW.js";
14
+ import { n as listWhatsAppDirectoryGroupsFromConfig, r as listWhatsAppDirectoryPeersFromConfig } from "./directory-config-Pc4f07wB.js";
15
+ import { c as extractContextInfo, g as resolveInboundMediaMimetype, m as findMessageSection, o as describeReplyContext, p as extractText, t as createWebSendApi, u as extractLocationData } from "./send-api-DimZST3E.js";
16
+ import { asBoolean, isRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
17
17
  import { formatLocationText } from "openclaw/plugin-sdk/channel-inbound";
18
18
  //#region extensions/whatsapp/src/qa-driver.runtime.ts
19
- function isRecord(value) {
20
- return Boolean(value && typeof value === "object");
21
- }
22
- function readString(value) {
23
- return typeof value === "string" && value.trim() ? value.trim() : void 0;
24
- }
25
- function readBoolean(value) {
26
- return typeof value === "boolean" ? value : void 0;
27
- }
28
- function findMessageSection(message, sectionNames) {
29
- if (!isRecord(message)) return;
30
- const queue = [{
31
- depth: 0,
32
- value: message
33
- }];
34
- const seen = /* @__PURE__ */ new Set();
35
- while (queue.length > 0) {
36
- const current = queue.shift();
37
- if (!current || seen.has(current.value)) continue;
38
- seen.add(current.value);
39
- for (const sectionName of sectionNames) {
40
- const section = current.value[sectionName];
41
- if (isRecord(section)) return section;
42
- }
43
- if (current.depth >= 4) continue;
44
- for (const wrapperName of [
45
- "botInvokeMessage",
46
- "documentWithCaptionMessage",
47
- "ephemeralMessage",
48
- "groupMentionedMessage",
49
- "viewOnceMessage",
50
- "viewOnceMessageV2",
51
- "viewOnceMessageV2Extension"
52
- ]) {
53
- const wrapper = current.value[wrapperName];
54
- if (isRecord(wrapper) && isRecord(wrapper.message)) queue.push({
55
- depth: current.depth + 1,
56
- value: wrapper.message
57
- });
58
- }
59
- }
60
- }
61
19
  function readReaction(message) {
62
- const reaction = findMessageSection(message, ["reactionMessage"]);
20
+ const reaction = findMessageSection(message ?? void 0, ["reactionMessage"])?.value;
63
21
  if (!reaction) return;
64
- const emoji = readString(reaction.text) ?? "";
22
+ const emoji = normalizeOptionalString(reaction.text) ?? "";
65
23
  const key = isRecord(reaction.key) ? reaction.key : void 0;
66
24
  return {
67
25
  emoji,
68
- fromMe: readBoolean(key?.fromMe),
69
- messageId: readString(key?.id),
70
- participant: readString(key?.participant)
26
+ fromMe: asBoolean(key?.fromMe),
27
+ messageId: normalizeOptionalString(key?.id),
28
+ participant: normalizeOptionalString(key?.participant)
71
29
  };
72
30
  }
73
31
  function readPoll(message) {
74
- const poll = findMessageSection(message, [
32
+ const poll = findMessageSection(message ?? void 0, [
75
33
  "pollCreationMessage",
76
34
  "pollCreationMessageV2",
77
- "pollCreationMessageV3"
78
- ]);
35
+ "pollCreationMessageV3",
36
+ "pollCreationMessageV5"
37
+ ])?.value;
79
38
  if (!poll) return;
80
39
  return {
81
- options: (Array.isArray(poll.options) ? poll.options : []).map((option) => isRecord(option) ? readString(option.optionName) : void 0).filter((option) => Boolean(option)),
82
- question: readString(poll.name)
40
+ options: (Array.isArray(poll.options) ? poll.options : []).map((option) => isRecord(option) ? normalizeOptionalString(option.optionName) : void 0).filter((option) => Boolean(option)),
41
+ question: normalizeOptionalString(poll.name)
83
42
  };
84
43
  }
85
44
  function readMedia(message) {
86
- const normalizedMessage = isRecord(message) ? normalizeMessageContent(message) : void 0;
87
- for (const sectionName of [
45
+ const media = findMessageSection(message ?? void 0, [
88
46
  "imageMessage",
89
47
  "videoMessage",
48
+ "ptvMessage",
90
49
  "audioMessage",
91
50
  "documentMessage",
92
51
  "stickerMessage"
93
- ]) {
94
- const section = findMessageSection(normalizedMessage ?? message, [sectionName]);
95
- if (!section) continue;
96
- const mediaMessage = { [sectionName]: section };
97
- return {
98
- fileName: readString(section.fileName),
99
- mediaType: resolveInboundMediaMimetype(mediaMessage)
100
- };
101
- }
52
+ ]);
53
+ return media ? {
54
+ fileName: normalizeOptionalString(media.value.fileName),
55
+ mediaType: resolveInboundMediaMimetype({ [media.name]: media.value })
56
+ } : void 0;
102
57
  }
103
58
  function readQuotedMessage(message) {
104
59
  const contextInfo = extractContextInfo(message.message ?? void 0);
105
- const replyContext = describeReplyContext(message.message);
60
+ const replyContext = describeReplyContext(message.message ?? void 0);
106
61
  if (!contextInfo && !replyContext) return;
107
62
  if (!contextInfo?.stanzaId && !contextInfo?.participant && !replyContext?.body) return;
108
63
  return {
@@ -114,7 +69,7 @@ function readQuotedMessage(message) {
114
69
  function normalizeObservedMessage(message, authDir) {
115
70
  if (message.key.fromMe) return null;
116
71
  const extractedText = extractText(message.message ?? void 0);
117
- const location = extractLocationData(message.message);
72
+ const location = extractLocationData(message.message ?? void 0);
118
73
  const text = [extractedText, location ? formatLocationText(location) : void 0].filter(Boolean).join("\n").trim() || void 0;
119
74
  const reaction = readReaction(message.message);
120
75
  const poll = readPoll(message.message);
@@ -141,15 +96,6 @@ function normalizeObservedMessage(message, authDir) {
141
96
  text: text ?? ""
142
97
  };
143
98
  }
144
- function closeSocket(sock) {
145
- const maybeEnd = sock.end;
146
- if (typeof maybeEnd === "function") {
147
- maybeEnd.call(sock);
148
- return;
149
- }
150
- const maybeClose = sock.ws?.close;
151
- if (typeof maybeClose === "function") maybeClose.call(sock.ws);
152
- }
153
99
  function createConnectionClosedError(update) {
154
100
  const reason = update.lastDisconnect?.error;
155
101
  const status = getStatusCode(reason);
@@ -160,32 +106,26 @@ function createConnectionClosedError(update) {
160
106
  async function startWhatsAppQaDriverSession(params) {
161
107
  const sock = await createWaSocket(false, false, { authDir: params.authDir });
162
108
  const observedMessages = [];
163
- const pendingNotificationsWaiters = [];
164
- const waiters = [];
109
+ const waiters = /* @__PURE__ */ new Set();
110
+ let pendingNotificationsWaiter;
165
111
  let closed = false;
166
112
  let closedError;
167
113
  let receivedPendingNotifications = false;
168
114
  const removeWaiter = (waiter) => {
169
- const index = waiters.indexOf(waiter);
170
- if (index >= 0) waiters.splice(index, 1);
115
+ waiters.delete(waiter);
171
116
  clearTimeout(waiter.timeout);
172
117
  };
173
- const removePendingNotificationsWaiter = (waiter) => {
174
- const index = pendingNotificationsWaiters.indexOf(waiter);
175
- if (index >= 0) pendingNotificationsWaiters.splice(index, 1);
118
+ const settlePendingNotifications = (error) => {
119
+ const waiter = pendingNotificationsWaiter;
120
+ if (!waiter) return;
121
+ pendingNotificationsWaiter = void 0;
176
122
  clearTimeout(waiter.timeout);
177
- };
178
- const markPendingNotificationsReceived = () => {
179
- if (receivedPendingNotifications) return;
180
- receivedPendingNotifications = true;
181
- for (const waiter of pendingNotificationsWaiters.slice()) {
182
- removePendingNotificationsWaiter(waiter);
183
- waiter.resolve();
184
- }
123
+ if (error) waiter.reject(error);
124
+ else waiter.resolve();
185
125
  };
186
126
  const observe = (message) => {
187
127
  observedMessages.push(message);
188
- for (const waiter of waiters.slice()) {
128
+ for (const waiter of waiters) {
189
129
  if (!waiter.predicate(message)) continue;
190
130
  removeWaiter(waiter);
191
131
  waiter.resolve(message);
@@ -198,28 +138,27 @@ async function startWhatsAppQaDriverSession(params) {
198
138
  }
199
139
  };
200
140
  const onConnectionUpdate = (event) => {
201
- if (event.receivedPendingNotifications === true) markPendingNotificationsReceived();
141
+ if (event.receivedPendingNotifications === true) {
142
+ receivedPendingNotifications = true;
143
+ settlePendingNotifications();
144
+ }
202
145
  if (event.connection === "close") closeSessionResources(createConnectionClosedError(event));
203
146
  };
204
147
  const removeMessageListener = () => {
205
- const evWithOff = sock.ev;
206
- evWithOff.off?.("messages.upsert", onMessagesUpsert);
207
- evWithOff.off?.("connection.update", onConnectionUpdate);
148
+ sock.ev.off("messages.upsert", onMessagesUpsert);
149
+ sock.ev.off("connection.update", onConnectionUpdate);
208
150
  };
209
151
  const closeSessionResources = (waiterError) => {
210
152
  if (closed) return;
211
153
  closed = true;
212
154
  closedError = waiterError;
213
- for (const waiter of pendingNotificationsWaiters.slice()) {
214
- removePendingNotificationsWaiter(waiter);
215
- if (waiterError) waiter.reject(waiterError);
216
- }
217
- for (const waiter of waiters.slice()) {
155
+ settlePendingNotifications(waiterError);
156
+ for (const waiter of waiters) {
218
157
  removeWaiter(waiter);
219
158
  if (waiterError) waiter.reject(waiterError);
220
159
  }
221
160
  removeMessageListener();
222
- closeSocket(sock);
161
+ sock.end(void 0);
223
162
  };
224
163
  sock.ev.on("messages.upsert", onMessagesUpsert);
225
164
  sock.ev.on("connection.update", onConnectionUpdate);
@@ -235,15 +174,14 @@ async function startWhatsAppQaDriverSession(params) {
235
174
  return;
236
175
  }
237
176
  const timeoutMs = params.connectionTimeoutMs ?? 45e3;
238
- const waiter = {
177
+ pendingNotificationsWaiter = {
239
178
  resolve,
240
179
  reject,
241
180
  timeout: setTimeout(() => {
242
- removePendingNotificationsWaiter(waiter);
181
+ pendingNotificationsWaiter = void 0;
243
182
  reject(/* @__PURE__ */ new Error(`timed out after ${timeoutMs}ms waiting for WhatsApp QA driver pending notifications`));
244
183
  }, timeoutMs)
245
184
  };
246
- pendingNotificationsWaiters.push(waiter);
247
185
  });
248
186
  } catch (error) {
249
187
  closeSessionResources(error instanceof Error ? error : /* @__PURE__ */ new Error("failed starting WhatsApp QA driver session"));
@@ -261,26 +199,26 @@ async function startWhatsAppQaDriverSession(params) {
261
199
  getObservedMessages() {
262
200
  return [...observedMessages];
263
201
  },
264
- async sendContact(to, contact) {
265
- return { messageId: (await sendApi.sendContact(to, contact)).messageId };
202
+ sendContact(to, contact) {
203
+ return toMessageIdResult(sendApi.sendContact(to, contact));
266
204
  },
267
- async sendLocation(to, location) {
268
- return { messageId: (await sendApi.sendLocation(to, location)).messageId };
205
+ sendLocation(to, location) {
206
+ return toMessageIdResult(sendApi.sendLocation(to, location));
269
207
  },
270
- async sendMedia(to, text, mediaBuffer, mediaType, options) {
271
- return { messageId: (await sendApi.sendMessage(to, text, mediaBuffer, mediaType, options)).messageId };
208
+ sendMedia(to, text, mediaBuffer, mediaType, options) {
209
+ return toMessageIdResult(sendApi.sendMessage(to, text, mediaBuffer, mediaType, options));
272
210
  },
273
- async sendPoll(to, poll) {
274
- return { messageId: (await sendApi.sendPoll(to, poll)).messageId };
211
+ sendPoll(to, poll) {
212
+ return toMessageIdResult(sendApi.sendPoll(to, poll));
275
213
  },
276
- async sendReaction(chatJid, messageId, emoji, options) {
277
- return { messageId: (await sendApi.sendReaction(chatJid, messageId, emoji, options.fromMe, options.participant)).messageId };
214
+ sendReaction(chatJid, messageId, emoji, options) {
215
+ return toMessageIdResult(sendApi.sendReaction(chatJid, messageId, emoji, options.fromMe, options.participant));
278
216
  },
279
- async sendSticker(to, stickerBuffer, options) {
280
- return { messageId: (await sendApi.sendSticker(to, stickerBuffer, options)).messageId };
217
+ sendSticker(to, stickerBuffer, options) {
218
+ return toMessageIdResult(sendApi.sendSticker(to, stickerBuffer, options));
281
219
  },
282
- async sendText(to, text, options) {
283
- return { messageId: (await sendApi.sendMessage(to, text, void 0, void 0, options)).messageId };
220
+ sendText(to, text, options) {
221
+ return toMessageIdResult(sendApi.sendMessage(to, text, void 0, void 0, options));
284
222
  },
285
223
  async waitForMessage(paramsLocal) {
286
224
  const predicate = (message) => (!paramsLocal.observedAfter || new Date(message.observedAt).getTime() >= paramsLocal.observedAfter.getTime()) && paramsLocal.match(message);
@@ -297,10 +235,14 @@ async function startWhatsAppQaDriverSession(params) {
297
235
  reject(/* @__PURE__ */ new Error("timed out waiting for WhatsApp QA driver message"));
298
236
  }, paramsLocal.timeoutMs)
299
237
  };
300
- waiters.push(waiter);
238
+ waiters.add(waiter);
301
239
  });
302
240
  }
303
241
  };
304
242
  }
243
+ async function toMessageIdResult(pending) {
244
+ const { messageId } = await pending;
245
+ return { messageId };
246
+ }
305
247
  //#endregion
306
- export { DEFAULT_WEB_MEDIA_BYTES, DEFAULT_WHATSAPP_MEDIA_MAX_MB, WHATSAPP_LEGACY_OUTBOUND_SEND_DEP_KEYS, assertWebChannel, hasAnyWhatsAppAuth, isSelfChatMode, isWhatsAppGroupJid, isWhatsAppUserTarget, jidToE164, listEnabledWhatsAppAccounts, listAccountIds as listWhatsAppAccountIds, listWhatsAppAuthDirs, listWhatsAppDirectoryGroupsFromConfig, listWhatsAppDirectoryPeersFromConfig, looksLikeWhatsAppTargetId, markdownToWhatsApp, normalizeE164, normalizeWhatsAppAllowFromEntries, normalizeWhatsAppMessagingTarget, normalizeWhatsAppTarget, resolveDefaultWhatsAppAccountId, resolveJidToE164, resolveUserPath, resolveWhatsAppAccount, resolveWhatsAppAuthDir, resolveWhatsAppGroupRequireMention, resolveWhatsAppGroupToolPolicy, resolveWhatsAppMediaMaxBytes, resolveWhatsAppOutboundTarget, startWhatsAppQaDriverSession, toWhatsappJid, toWhatsappJidWithLid, testing as whatsappAccessControlTesting, whatsappCommandPolicy, whatsappPlugin, whatsappSetupPlugin };
248
+ export { DEFAULT_WEB_MEDIA_BYTES, DEFAULT_WHATSAPP_MEDIA_MAX_MB, WHATSAPP_LEGACY_OUTBOUND_SEND_DEP_KEYS, assertWebChannel, hasAnyWhatsAppAuth, isSelfChatMode, isWhatsAppGroupJid, isWhatsAppUserTarget, jidToE164, listEnabledWhatsAppAccounts, listAccountIds as listWhatsAppAccountIds, listWhatsAppAuthDirs, listWhatsAppDirectoryGroupsFromConfig, listWhatsAppDirectoryPeersFromConfig, looksLikeWhatsAppTargetId, markdownToWhatsApp, normalizeE164, normalizeWhatsAppAllowFromEntries, normalizeWhatsAppMessagingTarget, normalizeWhatsAppTarget, resolveDefaultWhatsAppAccountId, resolveJidToE164, resolveUserPath, resolveWhatsAppAccount, resolveWhatsAppAuthDir, resolveWhatsAppGroupRequireMention, resolveWhatsAppGroupToolPolicy, resolveWhatsAppMediaMaxBytes, resolveWhatsAppOutboundTarget, startWhatsAppQaDriverSession, toWhatsappJid, toWhatsappJidWithLid, whatsappCommandPolicy, whatsappPlugin, whatsappSetupPlugin };
@@ -1,15 +1,15 @@
1
- import "./accounts-CSqLvCY5.js";
1
+ import "./accounts-BX2fZUyR.js";
2
2
  import { r as resolveDefaultWhatsAppAccountId } from "./account-ids-CB5SOWjc.js";
3
3
  import { s as normalizeWhatsAppMessagingTarget } from "./normalize-target-CugRyONv.js";
4
- import { i as sendTypingWhatsApp, t as sendMessageWhatsApp } from "./send-D37ddk22.js";
4
+ import { i as sendTypingWhatsApp, t as sendMessageWhatsApp } from "./send-prK8F7Vj.js";
5
5
  import { i as getWhatsAppRuntime } from "./runtime-BLlToOi6.js";
6
6
  import "./normalize-C7Hkc_vE.js";
7
- import { i as unregisterWhatsAppApprovalReactionTarget, r as registerWhatsAppApprovalReactionTarget } from "./approval-reactions-Cu66aYdq.js";
7
+ import { i as unregisterWhatsAppApprovalReactionTarget, r as registerWhatsAppApprovalReactionTarget } from "./approval-reactions-CmtJCxe_.js";
8
8
  import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
9
9
  import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
10
- import { buildChannelApprovalNativeTargetKey } from "openclaw/plugin-sdk/approval-native-runtime";
11
10
  import { buildApprovalReactionPendingContent } from "openclaw/plugin-sdk/approval-reaction-runtime";
12
11
  import { buildChannelApprovalExpiredText, buildChannelApprovalResolvedText, createChannelApprovalNativeRuntimeAdapter, resolvePreparedApprovalAccountId } from "openclaw/plugin-sdk/approval-handler-runtime";
12
+ import { buildChannelApprovalNativeTargetKey } from "openclaw/plugin-sdk/approval-native-runtime";
13
13
  //#region extensions/whatsapp/src/approval-handler.runtime.ts
14
14
  const log = createSubsystemLogger("whatsapp/approvals");
15
15
  function buildPendingPayload(params) {
@@ -1,9 +1,11 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { a as resolveWhatsAppAccount } from "./accounts-CSqLvCY5.js";
2
+ import { a as resolveWhatsAppAccount } from "./accounts-BX2fZUyR.js";
3
3
  import { n as getOptionalWhatsAppRuntime } from "./runtime-BLlToOi6.js";
4
- import { c as getWhatsAppApprovalApprovers, l as whatsappApprovalAuth } from "./group-session-key-DVMZlO3x.js";
5
- import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
6
- import { createApprovalReactionTargetStore, listApprovalReactionBindings, resolveTypedApprovalReactionTarget } from "openclaw/plugin-sdk/approval-reaction-runtime";
4
+ import { c as getWhatsAppApprovalApprovers, l as whatsappApprovalAuth } from "./group-session-key-DmFc_Cqi.js";
5
+ import { isApprovalNotFoundError } from "openclaw/plugin-sdk/error-runtime";
6
+ import { createLazyRuntimeSurface } from "openclaw/plugin-sdk/lazy-runtime";
7
+ import { approvalReactionDecisionSetsMatch, createApprovalReactionTargetStore, listApprovalReactionBindings, readApprovalReactionDecisionList, readApprovalReactionDeliveredBinding, readApprovalReactionPresentationBinding, resolveTypedApprovalReactionTarget } from "openclaw/plugin-sdk/approval-reaction-runtime";
8
+ import { createPluginStateErrorReporter } from "openclaw/plugin-sdk/plugin-state-runtime";
7
9
  //#region extensions/whatsapp/src/approval-reactions.ts
8
10
  var approval_reactions_exports = /* @__PURE__ */ __exportAll({
9
11
  clearWhatsAppApprovalReactionTargetsForTest: () => clearWhatsAppApprovalReactionTargetsForTest,
@@ -18,16 +20,15 @@ const PERSISTENT_NAMESPACE = "whatsapp.approval-reactions";
18
20
  const PERSISTENT_MAX_ENTRIES = 1e3;
19
21
  const DEFAULT_REACTION_TARGET_TTL_MS = 1440 * 60 * 1e3;
20
22
  const DELIVERY_BINDING_CHANNEL_DATA_KEY = "whatsappApprovalReactionBindingV1";
21
- const resolverRuntimeLoader = createLazyRuntimeModule(() => import("./approval-resolver-DoeBBt22.js"));
23
+ const loadResolveApprovalOverGateway = createLazyRuntimeSurface(() => import("openclaw/plugin-sdk/approval-gateway-runtime"), (runtime) => runtime.resolveApprovalOverGateway);
22
24
  const whatsappApprovalReactionTargets = createApprovalReactionTargetStore({
23
25
  namespace: PERSISTENT_NAMESPACE,
24
26
  maxEntries: PERSISTENT_MAX_ENTRIES,
25
27
  defaultTtlMs: DEFAULT_REACTION_TARGET_TTL_MS,
26
28
  openStore: (storeParams) => getOptionalWhatsAppRuntime()?.state.openKeyedStore(storeParams),
27
- logPersistentError: reportPersistentApprovalReactionError,
29
+ logPersistentError: createPluginStateErrorReporter(getOptionalWhatsAppRuntime, "whatsapp", "approval-reaction-state", "WhatsApp persistent approval reaction state failed"),
28
30
  readPersistedTarget
29
31
  });
30
- const loadApprovalResolver = resolverRuntimeLoader;
31
32
  function buildReactionTargetKey(params) {
32
33
  const accountId = params.accountId.trim();
33
34
  const remoteJid = params.remoteJid.trim();
@@ -39,14 +40,6 @@ function addCandidateRemoteJid(target, value) {
39
40
  const remoteJid = value?.trim();
40
41
  if (remoteJid && !target.includes(remoteJid)) target.push(remoteJid);
41
42
  }
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
43
  function reportApprovalBindingCorrelationMismatch(binding) {
51
44
  try {
52
45
  getOptionalWhatsAppRuntime()?.logging.getChildLogger({
@@ -72,46 +65,6 @@ function listWhatsAppApprovalReactionBindings(allowedDecisions) {
72
65
  }
73
66
  const APPROVAL_ID_LINE_RE = /^\s*ID:\s*(\S(?:.*\S)?)\s*$/i;
74
67
  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
68
  function visibleApprovalBindingMatches(text, binding) {
116
69
  const lines = (text ?? "").split(/\r?\n/).map((line) => line.replace(/\*\*/g, ""));
117
70
  const kindMatches = lines.map((line) => line.match(APPROVAL_KIND_LINE_RE)).filter((match) => Boolean(match));
@@ -136,22 +89,13 @@ function visibleApprovalBindingMatches(text, binding) {
136
89
  "allow-always",
137
90
  "deny"
138
91
  ]);
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;
92
+ const decisions = readApprovalReactionDecisionList(decisionLines.map((line) => knownBindings.find((entry) => `${entry.emoji} ${entry.label}` === line)?.decision));
93
+ if (!decisions) return false;
94
+ return approvalReactionDecisionSetsMatch(binding.allowedDecisions, decisions);
151
95
  }
152
96
  /** Preserve a validated typed approval binding until the platform message id is known. */
153
97
  function prepareWhatsAppApprovalPayloadForDelivery(params) {
154
- const binding = readTypedApprovalDeliveryBinding(params);
98
+ const binding = readApprovalReactionPresentationBinding(params);
155
99
  if (!binding) return null;
156
100
  if (!visibleApprovalBindingMatches(params.payload.text, binding)) {
157
101
  reportApprovalBindingCorrelationMismatch(binding);
@@ -161,7 +105,10 @@ function prepareWhatsAppApprovalPayloadForDelivery(params) {
161
105
  ...params.payload,
162
106
  channelData: {
163
107
  ...params.payload.channelData,
164
- [DELIVERY_BINDING_CHANNEL_DATA_KEY]: binding
108
+ [DELIVERY_BINDING_CHANNEL_DATA_KEY]: {
109
+ version: 1,
110
+ ...binding
111
+ }
165
112
  }
166
113
  };
167
114
  }
@@ -208,7 +155,10 @@ function listWhatsAppDeliveredMessageIdentities(results) {
208
155
  /** Bind generic forwarded approvals to the exact WhatsApp messages accepted by Baileys. */
209
156
  function registerWhatsAppApprovalReactionTargetForDeliveredPayload(params) {
210
157
  if (params.target.channel.trim().toLowerCase() !== "whatsapp") return false;
211
- const binding = readDeliveredApprovalBinding(params.payload);
158
+ const binding = readApprovalReactionDeliveredBinding({
159
+ payload: params.payload,
160
+ channelDataKey: DELIVERY_BINDING_CHANNEL_DATA_KEY
161
+ });
212
162
  if (!binding) return false;
213
163
  if (!visibleApprovalBindingMatches(params.payload.text, binding)) {
214
164
  reportApprovalBindingCorrelationMismatch(binding);
@@ -333,13 +283,15 @@ async function maybeResolveWhatsAppApprovalReaction(params) {
333
283
  params.logVerboseMessage?.(`whatsapp: approval reaction denied id=${target.approvalId} sender=${actorId}`);
334
284
  return true;
335
285
  }
336
- const { isApprovalNotFoundError, resolveWhatsAppApproval } = await loadApprovalResolver();
286
+ const resolveApprovalOverGateway = await loadResolveApprovalOverGateway();
337
287
  try {
338
- const result = await resolveWhatsAppApproval({
288
+ const result = await resolveApprovalOverGateway({
339
289
  cfg: params.cfg,
340
290
  approvalId: target.approvalId,
341
291
  approvalKind: target.approvalKind,
342
292
  decision: target.decision,
293
+ channel: "whatsapp",
294
+ accountId: params.accountId,
343
295
  senderId: actorId,
344
296
  gatewayUrl: params.gatewayUrl
345
297
  });
@@ -367,7 +319,7 @@ async function maybeResolveWhatsAppApprovalReaction(params) {
367
319
  }
368
320
  function clearWhatsAppApprovalReactionTargetsForTest() {
369
321
  whatsappApprovalReactionTargets.clearForTest();
370
- resolverRuntimeLoader.clear();
322
+ loadResolveApprovalOverGateway.clear();
371
323
  }
372
324
  //#endregion
373
325
  export { unregisterWhatsAppApprovalReactionTarget as i, maybeResolveWhatsAppApprovalReaction as n, registerWhatsAppApprovalReactionTarget as r, approval_reactions_exports as t };
@@ -1,4 +1,4 @@
1
- import { r as hasWebCredsSync } from "./creds-files-B1kSWtBg.js";
1
+ import { r as hasWebCredsSync } from "./creds-files-W6B3EMZ8.js";
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import { resolveOAuthDir } from "openclaw/plugin-sdk/state-paths";