@openclaw/whatsapp 2026.7.2-beta.7 → 2026.8.1-beta.3

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-api.js +1 -1
  3. package/dist/{action-runtime-BzfDFPbH.js → action-runtime-pM-ExU0l.js} +2 -2
  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-CkMMvUjk.js} +4 -4
  8. package/dist/{approval-reactions-Cu66aYdq.js → approval-reactions-Jyr1JaAK.js} +29 -81
  9. package/dist/auth-presence.js +1 -1
  10. package/dist/{auth-store-DcEpIOmE.js → auth-store-CtpBqH5S.js} +82 -18
  11. package/dist/call-tool-api.js +1 -1
  12. package/dist/{channel-Dg62olhy.js → channel-DRMYRfZ8.js} +56 -160
  13. package/dist/channel-plugin-api.js +1 -1
  14. package/dist/{channel-react-action-J_YtyMGX.js → channel-react-action-CstrR0CT.js} +14 -12
  15. package/dist/{channel.runtime-BP0xNmLi.js → channel.runtime-X3JC2gaq.js} +4 -4
  16. package/dist/channel.setup-DhBBhbQv.js +14 -0
  17. package/dist/{connection-controller-BOB2MVKY.js → connection-controller-CIYuBJrs.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-P7_3U73Z.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-BkpKpndm.js} +4 -4
  26. package/dist/{login-qr-Bncpb6js.js → login-qr-1dpv6jjT.js} +4 -4
  27. package/dist/login-qr-runtime.js +1 -1
  28. package/dist/{monitor-CfkaUSL2.js → monitor-IzwQKizW.js} +545 -549
  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-D37ddk22.js → send-CwvTU4RI.js} +298 -23
  33. package/dist/{send-api-7wk6eQyW.js → send-api-obOSm2cC.js} +126 -137
  34. package/dist/setup-entry.js +1 -8
  35. package/dist/{setup-finalize-BZucx24W.js → setup-finalize-n4K2I2gJ.js} +4 -4
  36. package/dist/setup-plugin-api.js +1 -1
  37. package/dist/{setup-surface-BkVcd769.js → setup-surface-Cwn3zyxK.js} +3 -3
  38. package/dist/{shared-CAxd15bp.js → shared-wg42NKFB.js} +13 -8
  39. package/dist/{socket-close-DridEuzz.js → socket-close-2T0_jZTN.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,2 +1,2 @@
1
- import { t as handleWhatsAppAction } from "./action-runtime-BzfDFPbH.js";
1
+ import { t as handleWhatsAppAction } from "./action-runtime-pM-ExU0l.js";
2
2
  export { handleWhatsAppAction };
@@ -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 { r as sendReactionWhatsApp, v as resolveWhatsAppReactionLevel } from "./send-CwvTU4RI.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-pM-ExU0l.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-DRMYRfZ8.js";
8
+ import { a as resolveWhatsAppGroupRequireMention, o as resolveWhatsAppGroupToolPolicy } from "./shared-wg42NKFB.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-DhBBhbQv.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-2T0_jZTN.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-P7_3U73Z.js";
15
+ import { _ as resolveInboundMediaMimetype, c as extractContextInfo, m as findMessageSection, o as describeReplyContext, p as extractText, t as createWebSendApi, u as extractLocationData } from "./send-api-obOSm2cC.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-CwvTU4RI.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-Jyr1JaAK.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, buildApprovalReactionDeliveredBindingMarker, 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({
@@ -60,58 +53,17 @@ function reportApprovalBindingCorrelationMismatch(binding) {
60
53
  }
61
54
  function readPersistedTarget(target) {
62
55
  const value = target;
63
- if (!value || typeof value.approvalId !== "string" || !Array.isArray(value.allowedDecisions) || value.approvalKind !== "exec" && value.approvalKind !== "plugin") return null;
56
+ if (!value || typeof value.approvalId !== "string" || value.approvalKind !== "exec" && value.approvalKind !== "plugin") return null;
57
+ const allowedDecisions = readApprovalReactionDecisionList(value.allowedDecisions);
58
+ if (!allowedDecisions) return null;
64
59
  return {
65
60
  approvalId: value.approvalId,
66
61
  approvalKind: value.approvalKind,
67
- allowedDecisions: value.allowedDecisions
62
+ allowedDecisions
68
63
  };
69
64
  }
70
- function listWhatsAppApprovalReactionBindings(allowedDecisions) {
71
- return listApprovalReactionBindings({ allowedDecisions });
72
- }
73
65
  const APPROVAL_ID_LINE_RE = /^\s*ID:\s*(\S(?:.*\S)?)\s*$/i;
74
66
  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
67
  function visibleApprovalBindingMatches(text, binding) {
116
68
  const lines = (text ?? "").split(/\r?\n/).map((line) => line.replace(/\*\*/g, ""));
117
69
  const kindMatches = lines.map((line) => line.match(APPROVAL_KIND_LINE_RE)).filter((match) => Boolean(match));
@@ -131,27 +83,18 @@ function visibleApprovalBindingMatches(text, binding) {
131
83
  decisionLines.push(decisionLine);
132
84
  cursor += 1;
133
85
  }
134
- const knownBindings = listWhatsAppApprovalReactionBindings([
86
+ const knownBindings = listApprovalReactionBindings({ allowedDecisions: [
135
87
  "allow-once",
136
88
  "allow-always",
137
89
  "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;
90
+ ] });
91
+ const decisions = readApprovalReactionDecisionList(decisionLines.map((line) => knownBindings.find((entry) => `${entry.emoji} ${entry.label}` === line)?.decision));
92
+ if (!decisions) return false;
93
+ return approvalReactionDecisionSetsMatch(binding.allowedDecisions, decisions);
151
94
  }
152
95
  /** Preserve a validated typed approval binding until the platform message id is known. */
153
96
  function prepareWhatsAppApprovalPayloadForDelivery(params) {
154
- const binding = readTypedApprovalDeliveryBinding(params);
97
+ const binding = readApprovalReactionPresentationBinding(params);
155
98
  if (!binding) return null;
156
99
  if (!visibleApprovalBindingMatches(params.payload.text, binding)) {
157
100
  reportApprovalBindingCorrelationMismatch(binding);
@@ -161,14 +104,14 @@ function prepareWhatsAppApprovalPayloadForDelivery(params) {
161
104
  ...params.payload,
162
105
  channelData: {
163
106
  ...params.payload.channelData,
164
- [DELIVERY_BINDING_CHANNEL_DATA_KEY]: binding
107
+ [DELIVERY_BINDING_CHANNEL_DATA_KEY]: buildApprovalReactionDeliveredBindingMarker(binding)
165
108
  }
166
109
  };
167
110
  }
168
111
  function registerWhatsAppApprovalReactionTarget(params) {
169
112
  const key = buildReactionTargetKey(params);
170
113
  const approvalId = params.approvalId.trim();
171
- const allowedDecisions = listWhatsAppApprovalReactionBindings(params.allowedDecisions).map((binding) => binding.decision);
114
+ const allowedDecisions = listApprovalReactionBindings({ allowedDecisions: params.allowedDecisions }).map((binding) => binding.decision);
172
115
  if (!key || !approvalId || params.approvalKind !== "exec" && params.approvalKind !== "plugin" || allowedDecisions.length === 0) return null;
173
116
  const target = {
174
117
  approvalId,
@@ -208,7 +151,10 @@ function listWhatsAppDeliveredMessageIdentities(results) {
208
151
  /** Bind generic forwarded approvals to the exact WhatsApp messages accepted by Baileys. */
209
152
  function registerWhatsAppApprovalReactionTargetForDeliveredPayload(params) {
210
153
  if (params.target.channel.trim().toLowerCase() !== "whatsapp") return false;
211
- const binding = readDeliveredApprovalBinding(params.payload);
154
+ const binding = readApprovalReactionDeliveredBinding({
155
+ payload: params.payload,
156
+ channelDataKey: DELIVERY_BINDING_CHANNEL_DATA_KEY
157
+ });
212
158
  if (!binding) return false;
213
159
  if (!visibleApprovalBindingMatches(params.payload.text, binding)) {
214
160
  reportApprovalBindingCorrelationMismatch(binding);
@@ -333,13 +279,15 @@ async function maybeResolveWhatsAppApprovalReaction(params) {
333
279
  params.logVerboseMessage?.(`whatsapp: approval reaction denied id=${target.approvalId} sender=${actorId}`);
334
280
  return true;
335
281
  }
336
- const { isApprovalNotFoundError, resolveWhatsAppApproval } = await loadApprovalResolver();
282
+ const resolveApprovalOverGateway = await loadResolveApprovalOverGateway();
337
283
  try {
338
- const result = await resolveWhatsAppApproval({
284
+ const result = await resolveApprovalOverGateway({
339
285
  cfg: params.cfg,
340
286
  approvalId: target.approvalId,
341
287
  approvalKind: target.approvalKind,
342
288
  decision: target.decision,
289
+ channel: "whatsapp",
290
+ accountId: params.accountId,
343
291
  senderId: actorId,
344
292
  gatewayUrl: params.gatewayUrl
345
293
  });
@@ -367,7 +315,7 @@ async function maybeResolveWhatsAppApprovalReaction(params) {
367
315
  }
368
316
  function clearWhatsAppApprovalReactionTargetsForTest() {
369
317
  whatsappApprovalReactionTargets.clearForTest();
370
- resolverRuntimeLoader.clear();
318
+ loadResolveApprovalOverGateway.clear();
371
319
  }
372
320
  //#endregion
373
321
  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";