@openclaw/whatsapp 2026.5.2 → 2026.5.3-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/dist/access-control-BQ3tCkH8.js +288 -0
  2. package/dist/account-config-CNQ33oav.js +47 -0
  3. package/dist/account-ids-DG18xddX.js +5 -0
  4. package/dist/accounts-BDqgpFEB.js +116 -0
  5. package/dist/action-runtime-DTGNgG-i.js +74 -0
  6. package/dist/action-runtime-api.js +2 -0
  7. package/dist/action-runtime.runtime.js +2 -0
  8. package/dist/active-listener-N7GFKsuN.js +11 -0
  9. package/dist/agent-tools-login-DpRxLNRB.js +89 -0
  10. package/dist/api.js +148 -0
  11. package/dist/audio-preflight.runtime-Bcdsl_ri.js +7 -0
  12. package/dist/auth-presence.js +32 -0
  13. package/dist/auth-store-BjCb50Ry.js +381 -0
  14. package/dist/channel-DQ-5Xoj9.js +542 -0
  15. package/dist/channel-config-api.js +2 -0
  16. package/dist/channel-plugin-api.js +2 -0
  17. package/dist/channel-react-action-Df20qAy9.js +42 -0
  18. package/dist/channel.runtime-DKXRnA8x.js +55 -0
  19. package/dist/channel.setup-DOHR2BGp.js +20 -0
  20. package/dist/command-policy-O8sRnqUV.js +8 -0
  21. package/dist/config-schema-Dmo66Ubb.js +27 -0
  22. package/dist/connection-controller-BiHAsTM8.js +596 -0
  23. package/dist/connection-controller-registry-D_iIGz5m.js +22 -0
  24. package/dist/constants-DLGCIbfl.js +4 -0
  25. package/dist/constants.js +2 -0
  26. package/dist/contract-api.js +19 -0
  27. package/dist/creds-files-_2V8jzQa.js +19 -0
  28. package/dist/directory-config-DVs4ffXu.js +37 -0
  29. package/dist/directory-contract-api.js +2 -0
  30. package/dist/doctor-A9tXm9Om.js +48 -0
  31. package/dist/doctor-contract-api.js +10 -0
  32. package/dist/group-session-contract-B8QBn0I2.js +15 -0
  33. package/dist/identity-QHAlV7Fu.js +75 -0
  34. package/dist/index.js +18 -0
  35. package/dist/legacy-session-surface-api.js +8 -0
  36. package/dist/legacy-state-migrations-api.js +2 -0
  37. package/dist/light-runtime-api.js +5 -0
  38. package/dist/login-DymdrKca.js +52 -0
  39. package/dist/login-qr-DIS0Iv-7.js +378 -0
  40. package/dist/login-qr-api.js +2 -0
  41. package/dist/login-qr-runtime.js +16 -0
  42. package/dist/monitor-C4Fhg_lD.js +3349 -0
  43. package/dist/normalize-CWYiGkXw.js +2 -0
  44. package/dist/normalize-target-BPVHNsM5.js +74 -0
  45. package/dist/outbound-adapter-BssVnZdz.js +29 -0
  46. package/dist/outbound-base-Bq1UYEK5.js +119 -0
  47. package/dist/outbound-media-contract-CGss_QHy.js +163 -0
  48. package/dist/outbound-payload-test-api.js +2 -0
  49. package/dist/quoted-message-TENQzyxV.js +108 -0
  50. package/dist/reaction-level-CRVEVAfi.js +16 -0
  51. package/dist/reply-resolver.runtime-BRCgoO4C.js +2 -0
  52. package/dist/resolve-outbound-target-CN-Wo6IY.js +39 -0
  53. package/dist/rolldown-runtime-RkAeH_Qm.js +27 -0
  54. package/dist/runtime-6fZ67abR.js +8 -0
  55. package/dist/runtime-api.js +15 -0
  56. package/dist/runtime-group-policy-Gp1lQ0at.js +11 -0
  57. package/dist/secret-contract-api.js +5 -0
  58. package/dist/security-contract-DqH8JDX6.js +26 -0
  59. package/dist/security-contract-api.js +2 -0
  60. package/dist/send-CIyLFxdZ.js +234 -0
  61. package/dist/session-contract-B0efQf9P.js +27 -0
  62. package/dist/session-errors-CSuKZPub.js +63 -0
  63. package/dist/session.runtime-C1eSE_KK.js +13 -0
  64. package/dist/setup-core-DZKvpzbH.js +46 -0
  65. package/dist/setup-entry.js +23 -0
  66. package/dist/setup-plugin-api.js +2 -0
  67. package/dist/setup-surface-ieFnIW4g.js +344 -0
  68. package/dist/shared-D_wzSVar.js +307 -0
  69. package/dist/state-migrations-DnCdvoYD.js +39 -0
  70. package/dist/targets.js +2 -0
  71. package/dist/test-api.js +3 -0
  72. package/dist/text-runtime-C1zNiZeO.js +116 -0
  73. package/package.json +14 -6
  74. package/action-runtime-api.ts +0 -1
  75. package/action-runtime.runtime.ts +0 -1
  76. package/api.ts +0 -213
  77. package/auth-presence.ts +0 -80
  78. package/channel-config-api.ts +0 -1
  79. package/channel-plugin-api.ts +0 -3
  80. package/config-api.ts +0 -4
  81. package/constants.ts +0 -1
  82. package/contract-api.ts +0 -29
  83. package/directory-contract-api.ts +0 -4
  84. package/doctor-contract-api.ts +0 -8
  85. package/index.test.ts +0 -13
  86. package/index.ts +0 -16
  87. package/legacy-session-surface-api.ts +0 -6
  88. package/legacy-state-migrations-api.ts +0 -1
  89. package/light-runtime-api.ts +0 -12
  90. package/login-qr-api.ts +0 -1
  91. package/login-qr-runtime.ts +0 -23
  92. package/outbound-payload-test-api.ts +0 -1
  93. package/runtime-api.ts +0 -84
  94. package/secret-contract-api.ts +0 -4
  95. package/security-contract-api.ts +0 -4
  96. package/setup-entry.test.ts +0 -21
  97. package/setup-entry.ts +0 -21
  98. package/setup-plugin-api.ts +0 -3
  99. package/src/account-config.ts +0 -77
  100. package/src/account-ids.ts +0 -13
  101. package/src/account-types.ts +0 -5
  102. package/src/accounts.test.ts +0 -182
  103. package/src/accounts.ts +0 -176
  104. package/src/accounts.whatsapp-auth.test.ts +0 -59
  105. package/src/action-runtime-target-auth.ts +0 -27
  106. package/src/action-runtime.test.ts +0 -330
  107. package/src/action-runtime.ts +0 -76
  108. package/src/active-listener.test.ts +0 -65
  109. package/src/active-listener.ts +0 -17
  110. package/src/agent-tools-login.test.ts +0 -81
  111. package/src/agent-tools-login.ts +0 -113
  112. package/src/approval-auth.test.ts +0 -24
  113. package/src/approval-auth.ts +0 -27
  114. package/src/auth-store.runtime.ts +0 -1
  115. package/src/auth-store.test.ts +0 -311
  116. package/src/auth-store.ts +0 -502
  117. package/src/auto-reply/config.runtime.ts +0 -16
  118. package/src/auto-reply/constants.ts +0 -1
  119. package/src/auto-reply/deliver-reply.test.ts +0 -843
  120. package/src/auto-reply/deliver-reply.ts +0 -279
  121. package/src/auto-reply/loggers.ts +0 -6
  122. package/src/auto-reply/mentions.ts +0 -131
  123. package/src/auto-reply/monitor/ack-reaction.test.ts +0 -170
  124. package/src/auto-reply/monitor/ack-reaction.ts +0 -99
  125. package/src/auto-reply/monitor/audio-preflight.runtime.ts +0 -9
  126. package/src/auto-reply/monitor/broadcast.ts +0 -153
  127. package/src/auto-reply/monitor/commands.ts +0 -19
  128. package/src/auto-reply/monitor/echo.ts +0 -64
  129. package/src/auto-reply/monitor/group-activation.runtime.ts +0 -1
  130. package/src/auto-reply/monitor/group-activation.test.ts +0 -189
  131. package/src/auto-reply/monitor/group-activation.ts +0 -73
  132. package/src/auto-reply/monitor/group-gating.audio-preflight.test.ts +0 -103
  133. package/src/auto-reply/monitor/group-gating.runtime.ts +0 -8
  134. package/src/auto-reply/monitor/group-gating.ts +0 -217
  135. package/src/auto-reply/monitor/group-members.test.ts +0 -56
  136. package/src/auto-reply/monitor/group-members.ts +0 -65
  137. package/src/auto-reply/monitor/inbound-context.test.ts +0 -97
  138. package/src/auto-reply/monitor/inbound-context.ts +0 -92
  139. package/src/auto-reply/monitor/inbound-dispatch.runtime.ts +0 -21
  140. package/src/auto-reply/monitor/inbound-dispatch.test.ts +0 -895
  141. package/src/auto-reply/monitor/inbound-dispatch.ts +0 -422
  142. package/src/auto-reply/monitor/last-route.test.ts +0 -37
  143. package/src/auto-reply/monitor/last-route.ts +0 -61
  144. package/src/auto-reply/monitor/message-line.runtime.ts +0 -38
  145. package/src/auto-reply/monitor/message-line.ts +0 -54
  146. package/src/auto-reply/monitor/on-message.audio-preflight.test.ts +0 -354
  147. package/src/auto-reply/monitor/on-message.ts +0 -291
  148. package/src/auto-reply/monitor/peer.ts +0 -17
  149. package/src/auto-reply/monitor/process-message.audio-preflight.test.ts +0 -420
  150. package/src/auto-reply/monitor/process-message.test.ts +0 -355
  151. package/src/auto-reply/monitor/process-message.ts +0 -531
  152. package/src/auto-reply/monitor/runtime-api.ts +0 -30
  153. package/src/auto-reply/monitor-state.test.ts +0 -64
  154. package/src/auto-reply/monitor-state.ts +0 -106
  155. package/src/auto-reply/monitor.ts +0 -600
  156. package/src/auto-reply/reply-resolver.runtime.ts +0 -1
  157. package/src/auto-reply/types.ts +0 -48
  158. package/src/auto-reply/util.ts +0 -63
  159. package/src/auto-reply/web-auto-reply-monitor.test.ts +0 -687
  160. package/src/auto-reply/web-auto-reply-utils.test.ts +0 -392
  161. package/src/auto-reply.broadcast-groups.combined.test.ts +0 -246
  162. package/src/auto-reply.broadcast-groups.test-harness.ts +0 -47
  163. package/src/auto-reply.impl.ts +0 -6
  164. package/src/auto-reply.test-harness.ts +0 -421
  165. package/src/auto-reply.ts +0 -1
  166. package/src/auto-reply.web-auto-reply.compresses-common-formats-jpeg-cap.test.ts +0 -427
  167. package/src/auto-reply.web-auto-reply.connection-and-logging.e2e.test.ts +0 -908
  168. package/src/auto-reply.web-auto-reply.last-route.test.ts +0 -184
  169. package/src/channel-actions.runtime.ts +0 -7
  170. package/src/channel-actions.test.ts +0 -216
  171. package/src/channel-actions.ts +0 -84
  172. package/src/channel-outbound.test.ts +0 -131
  173. package/src/channel-outbound.ts +0 -36
  174. package/src/channel-react-action.runtime.ts +0 -7
  175. package/src/channel-react-action.test.ts +0 -294
  176. package/src/channel-react-action.ts +0 -84
  177. package/src/channel.runtime.ts +0 -117
  178. package/src/channel.setup.test.ts +0 -461
  179. package/src/channel.setup.ts +0 -28
  180. package/src/channel.ts +0 -339
  181. package/src/command-policy.ts +0 -7
  182. package/src/config-accessors.test.ts +0 -34
  183. package/src/config-accessors.ts +0 -22
  184. package/src/config-schema.test.ts +0 -121
  185. package/src/config-schema.ts +0 -6
  186. package/src/config-ui-hints.ts +0 -24
  187. package/src/connection-controller-registry.test.ts +0 -27
  188. package/src/connection-controller-registry.ts +0 -49
  189. package/src/connection-controller.test.ts +0 -282
  190. package/src/connection-controller.ts +0 -679
  191. package/src/creds-files.ts +0 -19
  192. package/src/creds-persistence.ts +0 -102
  193. package/src/directory-config.test.ts +0 -60
  194. package/src/directory-config.ts +0 -40
  195. package/src/directory-contract.test.ts +0 -56
  196. package/src/doctor-contract.ts +0 -11
  197. package/src/doctor.test.ts +0 -74
  198. package/src/doctor.ts +0 -56
  199. package/src/group-intro.ts +0 -15
  200. package/src/group-policy.test.ts +0 -36
  201. package/src/group-policy.ts +0 -40
  202. package/src/group-session-contract.ts +0 -20
  203. package/src/group-session-key.test.ts +0 -53
  204. package/src/group-session-key.ts +0 -41
  205. package/src/heartbeat.ts +0 -34
  206. package/src/identity.ts +0 -164
  207. package/src/inbound/access-control.test-harness.ts +0 -37
  208. package/src/inbound/access-control.test.ts +0 -375
  209. package/src/inbound/access-control.ts +0 -237
  210. package/src/inbound/dedupe.ts +0 -132
  211. package/src/inbound/extract.test.ts +0 -282
  212. package/src/inbound/extract.ts +0 -488
  213. package/src/inbound/lifecycle.ts +0 -39
  214. package/src/inbound/media.node.test.ts +0 -83
  215. package/src/inbound/media.ts +0 -102
  216. package/src/inbound/monitor.ts +0 -890
  217. package/src/inbound/runtime-api.ts +0 -7
  218. package/src/inbound/save-media.runtime.ts +0 -1
  219. package/src/inbound/send-api.test.ts +0 -319
  220. package/src/inbound/send-api.ts +0 -145
  221. package/src/inbound/send-result.ts +0 -61
  222. package/src/inbound/types.ts +0 -106
  223. package/src/inbound-context.contract.test.ts +0 -32
  224. package/src/inbound-policy.ts +0 -231
  225. package/src/inbound.media.test.ts +0 -320
  226. package/src/inbound.test.ts +0 -290
  227. package/src/inbound.ts +0 -9
  228. package/src/login-qr.test.ts +0 -483
  229. package/src/login-qr.ts +0 -542
  230. package/src/login.coverage.test.ts +0 -133
  231. package/src/login.test.ts +0 -89
  232. package/src/login.ts +0 -70
  233. package/src/logout.test.ts +0 -162
  234. package/src/media.test.ts +0 -480
  235. package/src/media.ts +0 -10
  236. package/src/monitor-inbox.allows-messages-from-senders-allowfrom-list.test-support.ts +0 -400
  237. package/src/monitor-inbox.append-upsert.test-support.ts +0 -133
  238. package/src/monitor-inbox.behavior.test.ts +0 -5
  239. package/src/monitor-inbox.blocks-messages-from-unauthorized-senders-not-allowfrom.test-support.ts +0 -362
  240. package/src/monitor-inbox.captures-media-path-image-messages.test-support.ts +0 -306
  241. package/src/monitor-inbox.streams-inbound-messages.test-support.ts +0 -729
  242. package/src/monitor-inbox.test-harness.ts +0 -304
  243. package/src/normalize-target.ts +0 -123
  244. package/src/normalize.ts +0 -7
  245. package/src/outbound-adapter.poll.test.ts +0 -62
  246. package/src/outbound-adapter.sendpayload.test.ts +0 -195
  247. package/src/outbound-adapter.ts +0 -36
  248. package/src/outbound-base.test.ts +0 -560
  249. package/src/outbound-base.ts +0 -244
  250. package/src/outbound-media-contract.ts +0 -278
  251. package/src/outbound-media.runtime.ts +0 -36
  252. package/src/outbound-payload.contract.test.ts +0 -61
  253. package/src/outbound-send-deps.ts +0 -1
  254. package/src/outbound-test-support.ts +0 -16
  255. package/src/pairing-security.test-harness.ts +0 -59
  256. package/src/qr-image.ts +0 -1
  257. package/src/qr-terminal.ts +0 -1
  258. package/src/quoted-message.test.ts +0 -83
  259. package/src/quoted-message.ts +0 -184
  260. package/src/reaction-level.test.ts +0 -94
  261. package/src/reaction-level.ts +0 -21
  262. package/src/reconnect.test.ts +0 -51
  263. package/src/reconnect.ts +0 -55
  264. package/src/resolve-outbound-target.test.ts +0 -288
  265. package/src/resolve-outbound-target.ts +0 -58
  266. package/src/resolve-target.test.ts +0 -120
  267. package/src/runtime-api.ts +0 -59
  268. package/src/runtime-group-policy.ts +0 -16
  269. package/src/runtime.ts +0 -9
  270. package/src/security-contract.ts +0 -47
  271. package/src/security-fix.ts +0 -71
  272. package/src/send.test.ts +0 -534
  273. package/src/send.ts +0 -292
  274. package/src/session-contract.test.ts +0 -31
  275. package/src/session-contract.ts +0 -43
  276. package/src/session-errors.ts +0 -125
  277. package/src/session-route.test.ts +0 -41
  278. package/src/session-route.ts +0 -32
  279. package/src/session.runtime.ts +0 -8
  280. package/src/session.test.ts +0 -559
  281. package/src/session.ts +0 -330
  282. package/src/setup-core.ts +0 -52
  283. package/src/setup-finalize.ts +0 -446
  284. package/src/setup-surface.test.ts +0 -367
  285. package/src/setup-surface.ts +0 -69
  286. package/src/setup-test-helpers.ts +0 -216
  287. package/src/shared.ts +0 -291
  288. package/src/socket-timing.test.ts +0 -49
  289. package/src/socket-timing.ts +0 -38
  290. package/src/state-migrations.ts +0 -54
  291. package/src/status-issues.test.ts +0 -137
  292. package/src/status-issues.ts +0 -185
  293. package/src/system-prompt.test.ts +0 -199
  294. package/src/system-prompt.ts +0 -31
  295. package/src/targets-runtime.ts +0 -180
  296. package/src/test-helpers.ts +0 -690
  297. package/src/text-runtime.test.ts +0 -162
  298. package/src/text-runtime.ts +0 -11
  299. package/src/vcard.ts +0 -84
  300. package/targets.ts +0 -5
  301. package/test-api.ts +0 -2
  302. package/tsconfig.json +0 -16
@@ -0,0 +1,288 @@
1
+ import { a as resolveWhatsAppAccount } from "./accounts-BDqgpFEB.js";
2
+ import { r as isSelfChatMode, t as text_runtime_exports } from "./text-runtime-C1zNiZeO.js";
3
+ import { a as getSelfIdentity, o as getSenderIdentity } from "./identity-QHAlV7Fu.js";
4
+ import { t as resolveWhatsAppRuntimeGroupPolicy } from "./runtime-group-policy-Gp1lQ0at.js";
5
+ import { defaultRuntime } from "openclaw/plugin-sdk/runtime-env";
6
+ import { resolveChannelGroupPolicy, resolveChannelGroupRequireMention } from "openclaw/plugin-sdk/channel-policy";
7
+ import { createChannelPairingChallengeIssuer } from "openclaw/plugin-sdk/channel-pairing";
8
+ import { upsertChannelPairingRequest } from "openclaw/plugin-sdk/conversation-runtime";
9
+ import { resolveDefaultGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce } from "openclaw/plugin-sdk/runtime-group-policy";
10
+ import { expandAllowFromWithAccessGroups, readStoreAllowFromForDmPolicy, resolveDmGroupAccessWithCommandGate, resolveDmGroupAccessWithLists, resolveEffectiveAllowFromLists } from "openclaw/plugin-sdk/security-runtime";
11
+ import { resolveGroupSessionKey } from "openclaw/plugin-sdk/session-store-runtime";
12
+ //#region extensions/whatsapp/src/inbound-policy.ts
13
+ function resolveGroupConversationId(conversationId) {
14
+ return resolveGroupSessionKey({
15
+ From: conversationId,
16
+ ChatType: "group",
17
+ Provider: "whatsapp"
18
+ })?.id ?? conversationId;
19
+ }
20
+ function isNormalizedSenderAllowed(allowEntries, sender) {
21
+ if (allowEntries.includes("*")) return true;
22
+ const normalizedSender = (0, text_runtime_exports.normalizeE164)(sender ?? "");
23
+ if (!normalizedSender) return false;
24
+ return new Set(allowEntries.map((entry) => (0, text_runtime_exports.normalizeE164)(entry)).filter((entry) => Boolean(entry))).has(normalizedSender);
25
+ }
26
+ function buildResolvedWhatsAppGroupConfig(params) {
27
+ return { channels: { whatsapp: {
28
+ groupPolicy: params.groupPolicy,
29
+ groups: params.groups
30
+ } } };
31
+ }
32
+ function resolveWhatsAppInboundPolicy(params) {
33
+ const account = resolveWhatsAppAccount({
34
+ cfg: params.cfg,
35
+ accountId: params.accountId
36
+ });
37
+ const configuredAllowFrom = account.allowFrom ?? [];
38
+ const dmPolicy = account.dmPolicy ?? "pairing";
39
+ const dmAllowFrom = configuredAllowFrom.length > 0 ? configuredAllowFrom : params.selfE164 ? [params.selfE164] : [];
40
+ const groupAllowFrom = account.groupAllowFrom ?? (configuredAllowFrom.length > 0 ? configuredAllowFrom : void 0) ?? [];
41
+ const { effectiveGroupAllowFrom } = resolveEffectiveAllowFromLists({
42
+ allowFrom: configuredAllowFrom,
43
+ groupAllowFrom
44
+ });
45
+ const defaultGroupPolicy = resolveDefaultGroupPolicy(params.cfg);
46
+ const { groupPolicy, providerMissingFallbackApplied } = resolveWhatsAppRuntimeGroupPolicy({
47
+ providerConfigPresent: params.cfg.channels?.whatsapp !== void 0,
48
+ groupPolicy: account.groupPolicy,
49
+ defaultGroupPolicy
50
+ });
51
+ const resolvedGroupCfg = buildResolvedWhatsAppGroupConfig({
52
+ groupPolicy,
53
+ groups: account.groups
54
+ });
55
+ const isSamePhone = (value) => typeof value === "string" && typeof params.selfE164 === "string" && value === params.selfE164;
56
+ return {
57
+ account,
58
+ dmPolicy,
59
+ groupPolicy,
60
+ configuredAllowFrom,
61
+ dmAllowFrom,
62
+ groupAllowFrom,
63
+ isSelfChat: account.selfChatMode ?? isSelfChatMode(params.selfE164, configuredAllowFrom),
64
+ providerMissingFallbackApplied,
65
+ shouldReadStorePairingApprovals: dmPolicy !== "allowlist",
66
+ isSamePhone,
67
+ isDmSenderAllowed: (allowEntries, sender) => isSamePhone(sender) || isNormalizedSenderAllowed(allowEntries, sender),
68
+ isGroupSenderAllowed: (allowEntries, sender) => isNormalizedSenderAllowed(allowEntries, sender),
69
+ resolveConversationGroupPolicy: (conversationId) => resolveChannelGroupPolicy({
70
+ cfg: resolvedGroupCfg,
71
+ channel: "whatsapp",
72
+ groupId: resolveGroupConversationId(conversationId),
73
+ hasGroupAllowFrom: effectiveGroupAllowFrom.length > 0
74
+ }),
75
+ resolveConversationRequireMention: (conversationId) => resolveChannelGroupRequireMention({
76
+ cfg: resolvedGroupCfg,
77
+ channel: "whatsapp",
78
+ groupId: resolveGroupConversationId(conversationId)
79
+ })
80
+ };
81
+ }
82
+ async function resolveWhatsAppCommandAuthorized(params) {
83
+ const useAccessGroups = params.cfg.commands?.useAccessGroups !== false;
84
+ if (!useAccessGroups) return true;
85
+ const self = getSelfIdentity(params.msg);
86
+ const policy = params.policy ?? resolveWhatsAppInboundPolicy({
87
+ cfg: params.cfg,
88
+ accountId: params.msg.accountId,
89
+ selfE164: self.e164 ?? null
90
+ });
91
+ const isGroup = params.msg.chatType === "group";
92
+ const sender = getSenderIdentity(params.msg);
93
+ const dmSender = sender.e164 ?? params.msg.from ?? "";
94
+ const groupSender = sender.e164 ?? "";
95
+ const normalizedSender = (0, text_runtime_exports.normalizeE164)(isGroup ? groupSender : dmSender);
96
+ if (!normalizedSender) return false;
97
+ const storeAllowFrom = isGroup || !policy.shouldReadStorePairingApprovals ? [] : await readStoreAllowFromForDmPolicy({
98
+ provider: "whatsapp",
99
+ accountId: policy.account.accountId,
100
+ dmPolicy: policy.dmPolicy,
101
+ shouldRead: policy.shouldReadStorePairingApprovals
102
+ });
103
+ const isSenderAllowed = (senderId, allowEntries) => isGroup ? policy.isGroupSenderAllowed(allowEntries, senderId) : policy.isDmSenderAllowed(allowEntries, senderId);
104
+ const [allowFrom, groupAllowFrom] = await Promise.all([expandAllowFromWithAccessGroups({
105
+ cfg: params.cfg,
106
+ allowFrom: policy.dmAllowFrom,
107
+ channel: "whatsapp",
108
+ accountId: policy.account.accountId,
109
+ senderId: normalizedSender,
110
+ isSenderAllowed
111
+ }), expandAllowFromWithAccessGroups({
112
+ cfg: params.cfg,
113
+ allowFrom: policy.groupAllowFrom,
114
+ channel: "whatsapp",
115
+ accountId: policy.account.accountId,
116
+ senderId: normalizedSender,
117
+ isSenderAllowed
118
+ })]);
119
+ const dmStoreAllowFrom = isGroup ? [] : await expandAllowFromWithAccessGroups({
120
+ cfg: params.cfg,
121
+ allowFrom: storeAllowFrom,
122
+ channel: "whatsapp",
123
+ accountId: policy.account.accountId,
124
+ senderId: normalizedSender,
125
+ isSenderAllowed
126
+ });
127
+ return resolveDmGroupAccessWithCommandGate({
128
+ isGroup,
129
+ dmPolicy: policy.dmPolicy,
130
+ groupPolicy: policy.groupPolicy,
131
+ allowFrom,
132
+ groupAllowFrom,
133
+ storeAllowFrom: dmStoreAllowFrom,
134
+ isSenderAllowed: (allowEntries) => isGroup ? policy.isGroupSenderAllowed(allowEntries, groupSender) : policy.isDmSenderAllowed(allowEntries, dmSender),
135
+ command: {
136
+ useAccessGroups,
137
+ allowTextCommands: true,
138
+ hasControlCommand: true
139
+ }
140
+ }).commandAuthorized;
141
+ }
142
+ //#endregion
143
+ //#region extensions/whatsapp/src/inbound/access-control.ts
144
+ const PAIRING_REPLY_HISTORY_GRACE_MS = 3e4;
145
+ function logWhatsAppVerbose(enabled, message) {
146
+ if (!enabled) return;
147
+ defaultRuntime.log(message);
148
+ }
149
+ async function checkInboundAccessControl(params) {
150
+ const policy = resolveWhatsAppInboundPolicy({
151
+ cfg: params.cfg,
152
+ accountId: params.accountId,
153
+ selfE164: params.selfE164
154
+ });
155
+ const storeAllowFrom = params.group ? [] : await readStoreAllowFromForDmPolicy({
156
+ provider: "whatsapp",
157
+ accountId: policy.account.accountId,
158
+ dmPolicy: policy.dmPolicy,
159
+ shouldRead: policy.shouldReadStorePairingApprovals
160
+ });
161
+ const pairingGraceMs = typeof params.pairingGraceMs === "number" && params.pairingGraceMs > 0 ? params.pairingGraceMs : PAIRING_REPLY_HISTORY_GRACE_MS;
162
+ const suppressPairingReply = typeof params.connectedAtMs === "number" && typeof params.messageTimestampMs === "number" && params.messageTimestampMs < params.connectedAtMs - pairingGraceMs;
163
+ warnMissingProviderGroupPolicyFallbackOnce({
164
+ providerMissingFallbackApplied: policy.providerMissingFallbackApplied,
165
+ providerKey: "whatsapp",
166
+ accountId: policy.account.accountId,
167
+ log: (message) => logWhatsAppVerbose(params.verbose, message)
168
+ });
169
+ const accessGroupSenderId = params.group ? params.senderE164 ?? params.from : params.from;
170
+ const isAccessGroupSenderAllowed = (senderId, allowEntries) => {
171
+ return params.group ? policy.isGroupSenderAllowed(allowEntries, senderId) : policy.isDmSenderAllowed(allowEntries, senderId);
172
+ };
173
+ const [allowFrom, groupAllowFrom] = await Promise.all([expandAllowFromWithAccessGroups({
174
+ cfg: params.cfg,
175
+ allowFrom: params.group ? policy.configuredAllowFrom : policy.dmAllowFrom,
176
+ channel: "whatsapp",
177
+ accountId: policy.account.accountId,
178
+ senderId: accessGroupSenderId,
179
+ isSenderAllowed: isAccessGroupSenderAllowed
180
+ }), expandAllowFromWithAccessGroups({
181
+ cfg: params.cfg,
182
+ allowFrom: policy.groupAllowFrom,
183
+ channel: "whatsapp",
184
+ accountId: policy.account.accountId,
185
+ senderId: accessGroupSenderId,
186
+ isSenderAllowed: isAccessGroupSenderAllowed
187
+ })]);
188
+ const dmStoreAllowFrom = params.group ? [] : await expandAllowFromWithAccessGroups({
189
+ cfg: params.cfg,
190
+ allowFrom: storeAllowFrom,
191
+ channel: "whatsapp",
192
+ accountId: policy.account.accountId,
193
+ senderId: accessGroupSenderId,
194
+ isSenderAllowed: isAccessGroupSenderAllowed
195
+ });
196
+ const access = resolveDmGroupAccessWithLists({
197
+ isGroup: params.group,
198
+ dmPolicy: policy.dmPolicy,
199
+ groupPolicy: policy.groupPolicy,
200
+ allowFrom,
201
+ groupAllowFrom,
202
+ storeAllowFrom: dmStoreAllowFrom,
203
+ isSenderAllowed: (allowEntries) => {
204
+ return params.group ? policy.isGroupSenderAllowed(allowEntries, params.senderE164) : policy.isDmSenderAllowed(allowEntries, params.from);
205
+ }
206
+ });
207
+ if (params.group && access.decision !== "allow") {
208
+ if (access.reason === "groupPolicy=disabled") logWhatsAppVerbose(params.verbose, "Blocked group message (groupPolicy: disabled)");
209
+ else if (access.reason === "groupPolicy=allowlist (empty allowlist)") logWhatsAppVerbose(params.verbose, "Blocked group message (groupPolicy: allowlist, no groupAllowFrom)");
210
+ else logWhatsAppVerbose(params.verbose, `Blocked group message from ${params.senderE164 ?? "unknown sender"} (groupPolicy: allowlist)`);
211
+ return {
212
+ allowed: false,
213
+ shouldMarkRead: false,
214
+ isSelfChat: policy.isSelfChat,
215
+ resolvedAccountId: policy.account.accountId
216
+ };
217
+ }
218
+ if (!params.group) {
219
+ if (params.isFromMe && !policy.isSamePhone(params.from)) {
220
+ logWhatsAppVerbose(params.verbose, "Skipping outbound DM (fromMe); no pairing reply needed.");
221
+ return {
222
+ allowed: false,
223
+ shouldMarkRead: false,
224
+ isSelfChat: policy.isSelfChat,
225
+ resolvedAccountId: policy.account.accountId
226
+ };
227
+ }
228
+ if (access.decision === "block" && access.reason === "dmPolicy=disabled") {
229
+ logWhatsAppVerbose(params.verbose, "Blocked dm (dmPolicy: disabled)");
230
+ return {
231
+ allowed: false,
232
+ shouldMarkRead: false,
233
+ isSelfChat: policy.isSelfChat,
234
+ resolvedAccountId: policy.account.accountId
235
+ };
236
+ }
237
+ if (access.decision === "pairing" && !policy.isSamePhone(params.from)) {
238
+ const candidate = params.from;
239
+ if (suppressPairingReply) logWhatsAppVerbose(params.verbose, `Skipping pairing reply for historical DM from ${candidate}.`);
240
+ else await createChannelPairingChallengeIssuer({
241
+ channel: "whatsapp",
242
+ upsertPairingRequest: async ({ id, meta }) => await upsertChannelPairingRequest({
243
+ channel: "whatsapp",
244
+ id,
245
+ accountId: policy.account.accountId,
246
+ meta
247
+ })
248
+ })({
249
+ senderId: candidate,
250
+ senderIdLine: `Your WhatsApp phone number: ${candidate}`,
251
+ meta: { name: (params.pushName ?? "").trim() || void 0 },
252
+ onCreated: () => {
253
+ logWhatsAppVerbose(params.verbose, `whatsapp pairing request sender=${candidate} name=${params.pushName ?? "unknown"}`);
254
+ },
255
+ sendPairingReply: async (text) => {
256
+ await params.sock.sendMessage(params.remoteJid, { text });
257
+ },
258
+ onReplyError: (err) => {
259
+ logWhatsAppVerbose(params.verbose, `whatsapp pairing reply failed for ${candidate}: ${String(err)}`);
260
+ }
261
+ });
262
+ return {
263
+ allowed: false,
264
+ shouldMarkRead: false,
265
+ isSelfChat: policy.isSelfChat,
266
+ resolvedAccountId: policy.account.accountId
267
+ };
268
+ }
269
+ if (access.decision !== "allow") {
270
+ logWhatsAppVerbose(params.verbose, `Blocked unauthorized sender ${params.from} (dmPolicy=${policy.dmPolicy})`);
271
+ return {
272
+ allowed: false,
273
+ shouldMarkRead: false,
274
+ isSelfChat: policy.isSelfChat,
275
+ resolvedAccountId: policy.account.accountId
276
+ };
277
+ }
278
+ }
279
+ return {
280
+ allowed: true,
281
+ shouldMarkRead: true,
282
+ isSelfChat: policy.isSelfChat,
283
+ resolvedAccountId: policy.account.accountId
284
+ };
285
+ }
286
+ const __testing = { resolveWhatsAppInboundPolicy };
287
+ //#endregion
288
+ export { resolveWhatsAppInboundPolicy as i, checkInboundAccessControl as n, resolveWhatsAppCommandAuthorized as r, __testing as t };
@@ -0,0 +1,47 @@
1
+ import { DEFAULT_ACCOUNT_ID, mergeAccountConfig, resolveAccountEntry, resolveMergedAccountConfig } from "openclaw/plugin-sdk/account-core";
2
+ import { resolveChannelStreamingBlockEnabled, resolveChannelStreamingChunkMode } from "openclaw/plugin-sdk/channel-streaming";
3
+ //#region extensions/whatsapp/src/account-config.ts
4
+ function resolveWhatsAppDefaultAccountSharedConfig(cfg) {
5
+ const defaultAccount = resolveAccountEntry(cfg.channels?.whatsapp?.accounts, DEFAULT_ACCOUNT_ID);
6
+ if (!defaultAccount) return;
7
+ const { enabled: _ignoredEnabled, name: _ignoredName, authDir: _ignoredAuthDir, selfChatMode: _ignoredSelfChatMode, ...sharedDefaults } = defaultAccount;
8
+ return sharedDefaults;
9
+ }
10
+ function _resolveWhatsAppAccountConfig(cfg, accountId) {
11
+ return resolveAccountEntry(cfg.channels?.whatsapp?.accounts, accountId);
12
+ }
13
+ function resolveMergedNamedWhatsAppAccountConfig(params) {
14
+ const rootCfg = params.cfg.channels?.whatsapp;
15
+ const accountConfig = _resolveWhatsAppAccountConfig(params.cfg, params.accountId);
16
+ return {
17
+ ...mergeAccountConfig({
18
+ channelConfig: rootCfg,
19
+ accountConfig: void 0,
20
+ omitKeys: ["defaultAccount"]
21
+ }),
22
+ ...resolveWhatsAppDefaultAccountSharedConfig(params.cfg),
23
+ ...accountConfig
24
+ };
25
+ }
26
+ function resolveMergedWhatsAppAccountConfig(params) {
27
+ const rootCfg = params.cfg.channels?.whatsapp;
28
+ const accountId = params.accountId?.trim() || rootCfg?.defaultAccount || DEFAULT_ACCOUNT_ID;
29
+ const base = resolveMergedAccountConfig({
30
+ channelConfig: rootCfg,
31
+ accounts: rootCfg?.accounts,
32
+ accountId,
33
+ omitKeys: ["defaultAccount"]
34
+ });
35
+ const merged = accountId === DEFAULT_ACCOUNT_ID ? base : resolveMergedNamedWhatsAppAccountConfig({
36
+ cfg: params.cfg,
37
+ accountId
38
+ });
39
+ return {
40
+ accountId,
41
+ ...merged,
42
+ chunkMode: resolveChannelStreamingChunkMode(merged) ?? merged.chunkMode,
43
+ blockStreaming: resolveChannelStreamingBlockEnabled(merged) ?? merged.blockStreaming
44
+ };
45
+ }
46
+ //#endregion
47
+ export { resolveMergedWhatsAppAccountConfig as t };
@@ -0,0 +1,5 @@
1
+ import { createAccountListHelpers } from "openclaw/plugin-sdk/account-core";
2
+ //#region extensions/whatsapp/src/account-ids.ts
3
+ const { listConfiguredAccountIds, listAccountIds, resolveDefaultAccountId: resolveDefaultWhatsAppAccountId } = createAccountListHelpers("whatsapp");
4
+ //#endregion
5
+ export { listConfiguredAccountIds as n, resolveDefaultWhatsAppAccountId as r, listAccountIds as t };
@@ -0,0 +1,116 @@
1
+ import { t as resolveMergedWhatsAppAccountConfig } from "./account-config-CNQ33oav.js";
2
+ import { n as listConfiguredAccountIds, r as resolveDefaultWhatsAppAccountId, t as listAccountIds } from "./account-ids-DG18xddX.js";
3
+ import { t as hasWebCredsSync } from "./creds-files-_2V8jzQa.js";
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+ import { DEFAULT_ACCOUNT_ID, normalizeAccountId, resolveUserPath } from "openclaw/plugin-sdk/account-core";
7
+ import { resolveOAuthDir } from "openclaw/plugin-sdk/state-paths";
8
+ import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
9
+ //#region extensions/whatsapp/src/accounts.ts
10
+ const DEFAULT_WHATSAPP_MEDIA_MAX_MB = 50;
11
+ function listWhatsAppAuthDirs(cfg) {
12
+ const oauthDir = resolveOAuthDir();
13
+ const whatsappDir = path.join(oauthDir, "whatsapp");
14
+ const authDirs = new Set([oauthDir, path.join(whatsappDir, DEFAULT_ACCOUNT_ID)]);
15
+ const accountIds = listConfiguredAccountIds(cfg);
16
+ for (const accountId of accountIds) authDirs.add(resolveWhatsAppAuthDir({
17
+ cfg,
18
+ accountId
19
+ }).authDir);
20
+ try {
21
+ const entries = fs.readdirSync(whatsappDir, { withFileTypes: true });
22
+ for (const entry of entries) {
23
+ if (!entry.isDirectory()) continue;
24
+ authDirs.add(path.join(whatsappDir, entry.name));
25
+ }
26
+ } catch {}
27
+ return Array.from(authDirs);
28
+ }
29
+ function hasAnyWhatsAppAuth(cfg) {
30
+ return listWhatsAppAuthDirs(cfg).some((authDir) => hasWebCredsSync(authDir));
31
+ }
32
+ function resolveDefaultAuthDir(accountId) {
33
+ return path.join(resolveOAuthDir(), "whatsapp", normalizeAccountId(accountId));
34
+ }
35
+ function resolveLegacyAuthDir() {
36
+ return resolveOAuthDir();
37
+ }
38
+ function legacyAuthExists(authDir) {
39
+ try {
40
+ return fs.existsSync(path.join(authDir, "creds.json"));
41
+ } catch {
42
+ return false;
43
+ }
44
+ }
45
+ function resolveWhatsAppAuthDir(params) {
46
+ const accountId = params.accountId.trim() || DEFAULT_ACCOUNT_ID;
47
+ const configured = resolveMergedWhatsAppAccountConfig({
48
+ cfg: params.cfg,
49
+ accountId
50
+ })?.authDir?.trim();
51
+ if (configured) return {
52
+ authDir: resolveUserPath(configured),
53
+ isLegacy: false
54
+ };
55
+ const defaultDir = resolveDefaultAuthDir(accountId);
56
+ if (accountId === DEFAULT_ACCOUNT_ID) {
57
+ const legacyDir = resolveLegacyAuthDir();
58
+ if (legacyAuthExists(legacyDir) && !legacyAuthExists(defaultDir)) return {
59
+ authDir: legacyDir,
60
+ isLegacy: true
61
+ };
62
+ }
63
+ return {
64
+ authDir: defaultDir,
65
+ isLegacy: false
66
+ };
67
+ }
68
+ function resolveWhatsAppAccount(params) {
69
+ const merged = resolveMergedWhatsAppAccountConfig({
70
+ cfg: params.cfg,
71
+ accountId: params.accountId?.trim() || resolveDefaultWhatsAppAccountId(params.cfg)
72
+ });
73
+ const accountId = merged.accountId;
74
+ const enabled = merged.enabled !== false;
75
+ const { authDir, isLegacy } = resolveWhatsAppAuthDir({
76
+ cfg: params.cfg,
77
+ accountId
78
+ });
79
+ return {
80
+ accountId,
81
+ name: normalizeOptionalString(merged.name),
82
+ enabled,
83
+ sendReadReceipts: merged.sendReadReceipts ?? true,
84
+ messagePrefix: merged.messagePrefix ?? params.cfg.messages?.messagePrefix,
85
+ defaultTo: merged.defaultTo,
86
+ authDir,
87
+ isLegacyAuthDir: isLegacy,
88
+ selfChatMode: merged.selfChatMode,
89
+ dmPolicy: merged.dmPolicy,
90
+ allowFrom: merged.allowFrom,
91
+ groupAllowFrom: merged.groupAllowFrom,
92
+ groupPolicy: merged.groupPolicy,
93
+ historyLimit: merged.historyLimit,
94
+ textChunkLimit: merged.textChunkLimit,
95
+ chunkMode: merged.chunkMode,
96
+ mediaMaxMb: merged.mediaMaxMb,
97
+ blockStreaming: merged.blockStreaming,
98
+ ackReaction: merged.ackReaction,
99
+ reactionLevel: merged.reactionLevel,
100
+ groups: merged.groups,
101
+ direct: merged.direct,
102
+ debounceMs: merged.debounceMs,
103
+ replyToMode: merged.replyToMode
104
+ };
105
+ }
106
+ function resolveWhatsAppMediaMaxBytes(account) {
107
+ return (typeof account.mediaMaxMb === "number" && account.mediaMaxMb > 0 ? account.mediaMaxMb : 50) * 1024 * 1024;
108
+ }
109
+ function listEnabledWhatsAppAccounts(cfg) {
110
+ return listAccountIds(cfg).map((accountId) => resolveWhatsAppAccount({
111
+ cfg,
112
+ accountId
113
+ })).filter((account) => account.enabled);
114
+ }
115
+ //#endregion
116
+ export { resolveWhatsAppAccount as a, listWhatsAppAuthDirs as i, hasAnyWhatsAppAuth as n, resolveWhatsAppAuthDir as o, listEnabledWhatsAppAccounts as r, resolveWhatsAppMediaMaxBytes as s, DEFAULT_WHATSAPP_MEDIA_MAX_MB as t };
@@ -0,0 +1,74 @@
1
+ import { a as resolveWhatsAppAccount } from "./accounts-BDqgpFEB.js";
2
+ import { t as resolveWhatsAppOutboundTarget } from "./resolve-outbound-target-CN-Wo6IY.js";
3
+ import { t as resolveWhatsAppReactionLevel } from "./reaction-level-CRVEVAfi.js";
4
+ import { r as sendReactionWhatsApp } from "./send-CIyLFxdZ.js";
5
+ import { ToolAuthorizationError, createActionGate, jsonResult, readReactionParams, readStringParam } from "openclaw/plugin-sdk/channel-actions";
6
+ //#region extensions/whatsapp/src/action-runtime-target-auth.ts
7
+ function resolveAuthorizedWhatsAppOutboundTarget(params) {
8
+ const account = resolveWhatsAppAccount({
9
+ cfg: params.cfg,
10
+ accountId: params.accountId
11
+ });
12
+ const resolution = resolveWhatsAppOutboundTarget({
13
+ to: params.chatJid,
14
+ allowFrom: account.allowFrom ?? [],
15
+ mode: "implicit"
16
+ });
17
+ if (!resolution.ok) throw new ToolAuthorizationError(`WhatsApp ${params.actionLabel} blocked: chatJid "${params.chatJid}" is not in the configured allowFrom list for account "${account.accountId}".`);
18
+ return {
19
+ to: resolution.to,
20
+ accountId: account.accountId
21
+ };
22
+ }
23
+ //#endregion
24
+ //#region extensions/whatsapp/src/action-runtime.ts
25
+ const whatsAppActionRuntime = {
26
+ resolveAuthorizedWhatsAppOutboundTarget,
27
+ sendReactionWhatsApp
28
+ };
29
+ async function handleWhatsAppAction(params, cfg) {
30
+ const action = readStringParam(params, "action", { required: true });
31
+ const whatsAppConfig = cfg.channels?.whatsapp;
32
+ const isActionEnabled = createActionGate(whatsAppConfig?.actions);
33
+ if (action === "react") {
34
+ const accountId = readStringParam(params, "accountId");
35
+ if (!whatsAppConfig) throw new Error("WhatsApp reactions are disabled.");
36
+ if (!isActionEnabled("reactions")) throw new Error("WhatsApp reactions are disabled.");
37
+ const reactionLevelInfo = resolveWhatsAppReactionLevel({
38
+ cfg,
39
+ accountId: accountId ?? void 0
40
+ });
41
+ if (!reactionLevelInfo.agentReactionsEnabled) throw new Error(`WhatsApp agent reactions disabled (reactionLevel="${reactionLevelInfo.level}"). Set channels.whatsapp.reactionLevel to "minimal" or "extensive" to enable.`);
42
+ const chatJid = readStringParam(params, "chatJid", { required: true });
43
+ const messageId = readStringParam(params, "messageId", { required: true });
44
+ const { emoji, remove, isEmpty } = readReactionParams(params, { removeErrorMessage: "Emoji is required to remove a WhatsApp reaction." });
45
+ const participant = readStringParam(params, "participant");
46
+ const fromMeRaw = params.fromMe;
47
+ const fromMe = typeof fromMeRaw === "boolean" ? fromMeRaw : void 0;
48
+ const resolved = whatsAppActionRuntime.resolveAuthorizedWhatsAppOutboundTarget({
49
+ cfg,
50
+ chatJid,
51
+ accountId,
52
+ actionLabel: "reaction"
53
+ });
54
+ const resolvedEmoji = remove ? "" : emoji;
55
+ await whatsAppActionRuntime.sendReactionWhatsApp(resolved.to, messageId, resolvedEmoji, {
56
+ verbose: false,
57
+ fromMe,
58
+ participant: participant ?? void 0,
59
+ accountId: resolved.accountId,
60
+ cfg
61
+ });
62
+ if (!remove && !isEmpty) return jsonResult({
63
+ ok: true,
64
+ added: emoji
65
+ });
66
+ return jsonResult({
67
+ ok: true,
68
+ removed: true
69
+ });
70
+ }
71
+ throw new Error(`Unsupported WhatsApp action: ${action}`);
72
+ }
73
+ //#endregion
74
+ export { whatsAppActionRuntime as n, handleWhatsAppAction as t };
@@ -0,0 +1,2 @@
1
+ import { t as handleWhatsAppAction } from "./action-runtime-DTGNgG-i.js";
2
+ export { handleWhatsAppAction };
@@ -0,0 +1,2 @@
1
+ import { t as handleWhatsAppAction } from "./action-runtime-DTGNgG-i.js";
2
+ export { handleWhatsAppAction };
@@ -0,0 +1,11 @@
1
+ import { r as resolveDefaultWhatsAppAccountId } from "./account-ids-DG18xddX.js";
2
+ import { t as getRegisteredWhatsAppConnectionController } from "./connection-controller-registry-D_iIGz5m.js";
3
+ //#region extensions/whatsapp/src/active-listener.ts
4
+ function resolveWebAccountId(params) {
5
+ return (params.accountId ?? "").trim() || resolveDefaultWhatsAppAccountId(params.cfg);
6
+ }
7
+ function getActiveWebListener(accountId) {
8
+ return getRegisteredWhatsAppConnectionController(accountId)?.getActiveListener() ?? null;
9
+ }
10
+ //#endregion
11
+ export { resolveWebAccountId as n, getActiveWebListener as t };
@@ -0,0 +1,89 @@
1
+ import { startWebLoginWithQr, waitForWebLogin } from "./login-qr-runtime.js";
2
+ import "./login-qr-api.js";
3
+ import { Type } from "typebox";
4
+ //#region extensions/whatsapp/src/agent-tools-login.ts
5
+ const QR_DATA_URL_MAX_LENGTH = 16384;
6
+ function readOptionalString(value) {
7
+ return typeof value === "string" && value.trim() ? value : void 0;
8
+ }
9
+ function createWhatsAppLoginTool() {
10
+ return {
11
+ label: "WhatsApp Login",
12
+ name: "whatsapp_login",
13
+ ownerOnly: true,
14
+ description: "Generate a WhatsApp QR code for linking, or wait for the scan to complete.",
15
+ parameters: Type.Object({
16
+ action: Type.Unsafe({
17
+ type: "string",
18
+ enum: ["start", "wait"]
19
+ }),
20
+ timeoutMs: Type.Optional(Type.Number()),
21
+ force: Type.Optional(Type.Boolean()),
22
+ accountId: Type.Optional(Type.String()),
23
+ currentQrDataUrl: Type.Optional(Type.String({
24
+ maxLength: QR_DATA_URL_MAX_LENGTH,
25
+ pattern: "^data:image/png;base64,"
26
+ }))
27
+ }),
28
+ execute: async (_toolCallId, args) => {
29
+ const renderQrReply = (params) => {
30
+ return {
31
+ content: [{
32
+ type: "text",
33
+ text: [
34
+ params.message,
35
+ "",
36
+ "Open WhatsApp → Linked Devices and scan:",
37
+ "",
38
+ `![whatsapp-qr](${params.qrDataUrl})`
39
+ ].join("\n")
40
+ }],
41
+ details: {
42
+ connected: params.connected ?? false,
43
+ qr: true
44
+ }
45
+ };
46
+ };
47
+ const action = args?.action ?? "start";
48
+ const accountId = readOptionalString(args.accountId);
49
+ if (action === "wait") {
50
+ const result = await waitForWebLogin({
51
+ accountId,
52
+ timeoutMs: typeof args.timeoutMs === "number" ? args.timeoutMs : void 0,
53
+ currentQrDataUrl: readOptionalString(args.currentQrDataUrl)
54
+ });
55
+ if (result.qrDataUrl) return renderQrReply({
56
+ message: result.message,
57
+ qrDataUrl: result.qrDataUrl,
58
+ connected: result.connected
59
+ });
60
+ return {
61
+ content: [{
62
+ type: "text",
63
+ text: result.message
64
+ }],
65
+ details: { connected: result.connected }
66
+ };
67
+ }
68
+ const result = await startWebLoginWithQr({
69
+ accountId,
70
+ timeoutMs: typeof args.timeoutMs === "number" ? args.timeoutMs : void 0,
71
+ force: typeof args.force === "boolean" ? args.force : false
72
+ });
73
+ if (!result.qrDataUrl) return {
74
+ content: [{
75
+ type: "text",
76
+ text: result.message
77
+ }],
78
+ details: { qr: false }
79
+ };
80
+ return renderQrReply({
81
+ message: result.message,
82
+ qrDataUrl: result.qrDataUrl,
83
+ connected: result.connected
84
+ });
85
+ }
86
+ };
87
+ }
88
+ //#endregion
89
+ export { createWhatsAppLoginTool as t };