@openclaw/whatsapp 2026.5.2-beta.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.
- package/dist/access-control-BQ3tCkH8.js +288 -0
- package/dist/account-config-CNQ33oav.js +47 -0
- package/dist/account-ids-DG18xddX.js +5 -0
- package/dist/accounts-BDqgpFEB.js +116 -0
- package/dist/action-runtime-DTGNgG-i.js +74 -0
- package/dist/action-runtime-api.js +2 -0
- package/dist/action-runtime.runtime.js +2 -0
- package/dist/active-listener-N7GFKsuN.js +11 -0
- package/dist/agent-tools-login-DpRxLNRB.js +89 -0
- package/dist/api.js +148 -0
- package/dist/audio-preflight.runtime-Bcdsl_ri.js +7 -0
- package/dist/auth-presence.js +32 -0
- package/dist/auth-store-BjCb50Ry.js +381 -0
- package/dist/channel-DQ-5Xoj9.js +542 -0
- package/dist/channel-config-api.js +2 -0
- package/dist/channel-plugin-api.js +2 -0
- package/dist/channel-react-action-Df20qAy9.js +42 -0
- package/dist/channel.runtime-DKXRnA8x.js +55 -0
- package/dist/channel.setup-DOHR2BGp.js +20 -0
- package/dist/command-policy-O8sRnqUV.js +8 -0
- package/dist/config-schema-Dmo66Ubb.js +27 -0
- package/dist/connection-controller-BiHAsTM8.js +596 -0
- package/dist/connection-controller-registry-D_iIGz5m.js +22 -0
- package/dist/constants-DLGCIbfl.js +4 -0
- package/dist/constants.js +2 -0
- package/dist/contract-api.js +19 -0
- package/dist/creds-files-_2V8jzQa.js +19 -0
- package/dist/directory-config-DVs4ffXu.js +37 -0
- package/dist/directory-contract-api.js +2 -0
- package/dist/doctor-A9tXm9Om.js +48 -0
- package/dist/doctor-contract-api.js +10 -0
- package/dist/group-session-contract-B8QBn0I2.js +15 -0
- package/dist/identity-QHAlV7Fu.js +75 -0
- package/dist/index.js +18 -0
- package/dist/legacy-session-surface-api.js +8 -0
- package/dist/legacy-state-migrations-api.js +2 -0
- package/dist/light-runtime-api.js +5 -0
- package/dist/login-DymdrKca.js +52 -0
- package/dist/login-qr-DIS0Iv-7.js +378 -0
- package/dist/login-qr-api.js +2 -0
- package/dist/login-qr-runtime.js +16 -0
- package/dist/monitor-C4Fhg_lD.js +3349 -0
- package/dist/normalize-CWYiGkXw.js +2 -0
- package/dist/normalize-target-BPVHNsM5.js +74 -0
- package/dist/outbound-adapter-BssVnZdz.js +29 -0
- package/dist/outbound-base-Bq1UYEK5.js +119 -0
- package/dist/outbound-media-contract-CGss_QHy.js +163 -0
- package/dist/outbound-payload-test-api.js +2 -0
- package/dist/quoted-message-TENQzyxV.js +108 -0
- package/dist/reaction-level-CRVEVAfi.js +16 -0
- package/dist/reply-resolver.runtime-BRCgoO4C.js +2 -0
- package/dist/resolve-outbound-target-CN-Wo6IY.js +39 -0
- package/dist/rolldown-runtime-RkAeH_Qm.js +27 -0
- package/dist/runtime-6fZ67abR.js +8 -0
- package/dist/runtime-api.js +15 -0
- package/dist/runtime-group-policy-Gp1lQ0at.js +11 -0
- package/dist/secret-contract-api.js +5 -0
- package/dist/security-contract-DqH8JDX6.js +26 -0
- package/dist/security-contract-api.js +2 -0
- package/dist/send-CIyLFxdZ.js +234 -0
- package/dist/session-contract-B0efQf9P.js +27 -0
- package/dist/session-errors-CSuKZPub.js +63 -0
- package/dist/session.runtime-C1eSE_KK.js +13 -0
- package/dist/setup-core-DZKvpzbH.js +46 -0
- package/dist/setup-entry.js +23 -0
- package/dist/setup-plugin-api.js +2 -0
- package/dist/setup-surface-ieFnIW4g.js +344 -0
- package/dist/shared-D_wzSVar.js +307 -0
- package/dist/state-migrations-DnCdvoYD.js +39 -0
- package/dist/targets.js +2 -0
- package/dist/test-api.js +3 -0
- package/dist/text-runtime-C1zNiZeO.js +116 -0
- package/package.json +14 -6
- package/action-runtime-api.ts +0 -1
- package/action-runtime.runtime.ts +0 -1
- package/api.ts +0 -213
- package/auth-presence.ts +0 -80
- package/channel-config-api.ts +0 -1
- package/channel-plugin-api.ts +0 -3
- package/config-api.ts +0 -4
- package/constants.ts +0 -1
- package/contract-api.ts +0 -29
- package/directory-contract-api.ts +0 -4
- package/doctor-contract-api.ts +0 -8
- package/index.test.ts +0 -13
- package/index.ts +0 -16
- package/legacy-session-surface-api.ts +0 -6
- package/legacy-state-migrations-api.ts +0 -1
- package/light-runtime-api.ts +0 -12
- package/login-qr-api.ts +0 -1
- package/login-qr-runtime.ts +0 -23
- package/outbound-payload-test-api.ts +0 -1
- package/runtime-api.ts +0 -84
- package/secret-contract-api.ts +0 -4
- package/security-contract-api.ts +0 -4
- package/setup-entry.test.ts +0 -21
- package/setup-entry.ts +0 -21
- package/setup-plugin-api.ts +0 -3
- package/src/account-config.ts +0 -77
- package/src/account-ids.ts +0 -13
- package/src/account-types.ts +0 -5
- package/src/accounts.test.ts +0 -182
- package/src/accounts.ts +0 -176
- package/src/accounts.whatsapp-auth.test.ts +0 -59
- package/src/action-runtime-target-auth.ts +0 -27
- package/src/action-runtime.test.ts +0 -330
- package/src/action-runtime.ts +0 -76
- package/src/active-listener.test.ts +0 -65
- package/src/active-listener.ts +0 -17
- package/src/agent-tools-login.test.ts +0 -81
- package/src/agent-tools-login.ts +0 -113
- package/src/approval-auth.test.ts +0 -24
- package/src/approval-auth.ts +0 -27
- package/src/auth-store.runtime.ts +0 -1
- package/src/auth-store.test.ts +0 -311
- package/src/auth-store.ts +0 -502
- package/src/auto-reply/config.runtime.ts +0 -16
- package/src/auto-reply/constants.ts +0 -1
- package/src/auto-reply/deliver-reply.test.ts +0 -843
- package/src/auto-reply/deliver-reply.ts +0 -279
- package/src/auto-reply/loggers.ts +0 -6
- package/src/auto-reply/mentions.ts +0 -131
- package/src/auto-reply/monitor/ack-reaction.test.ts +0 -170
- package/src/auto-reply/monitor/ack-reaction.ts +0 -99
- package/src/auto-reply/monitor/audio-preflight.runtime.ts +0 -9
- package/src/auto-reply/monitor/broadcast.ts +0 -153
- package/src/auto-reply/monitor/commands.ts +0 -19
- package/src/auto-reply/monitor/echo.ts +0 -64
- package/src/auto-reply/monitor/group-activation.runtime.ts +0 -1
- package/src/auto-reply/monitor/group-activation.test.ts +0 -189
- package/src/auto-reply/monitor/group-activation.ts +0 -73
- package/src/auto-reply/monitor/group-gating.audio-preflight.test.ts +0 -103
- package/src/auto-reply/monitor/group-gating.runtime.ts +0 -8
- package/src/auto-reply/monitor/group-gating.ts +0 -217
- package/src/auto-reply/monitor/group-members.test.ts +0 -56
- package/src/auto-reply/monitor/group-members.ts +0 -65
- package/src/auto-reply/monitor/inbound-context.test.ts +0 -97
- package/src/auto-reply/monitor/inbound-context.ts +0 -92
- package/src/auto-reply/monitor/inbound-dispatch.runtime.ts +0 -21
- package/src/auto-reply/monitor/inbound-dispatch.test.ts +0 -895
- package/src/auto-reply/monitor/inbound-dispatch.ts +0 -422
- package/src/auto-reply/monitor/last-route.test.ts +0 -37
- package/src/auto-reply/monitor/last-route.ts +0 -61
- package/src/auto-reply/monitor/message-line.runtime.ts +0 -38
- package/src/auto-reply/monitor/message-line.ts +0 -54
- package/src/auto-reply/monitor/on-message.audio-preflight.test.ts +0 -354
- package/src/auto-reply/monitor/on-message.ts +0 -291
- package/src/auto-reply/monitor/peer.ts +0 -17
- package/src/auto-reply/monitor/process-message.audio-preflight.test.ts +0 -420
- package/src/auto-reply/monitor/process-message.test.ts +0 -355
- package/src/auto-reply/monitor/process-message.ts +0 -531
- package/src/auto-reply/monitor/runtime-api.ts +0 -30
- package/src/auto-reply/monitor-state.test.ts +0 -64
- package/src/auto-reply/monitor-state.ts +0 -106
- package/src/auto-reply/monitor.ts +0 -600
- package/src/auto-reply/reply-resolver.runtime.ts +0 -1
- package/src/auto-reply/types.ts +0 -48
- package/src/auto-reply/util.ts +0 -63
- package/src/auto-reply/web-auto-reply-monitor.test.ts +0 -687
- package/src/auto-reply/web-auto-reply-utils.test.ts +0 -392
- package/src/auto-reply.broadcast-groups.combined.test.ts +0 -246
- package/src/auto-reply.broadcast-groups.test-harness.ts +0 -47
- package/src/auto-reply.impl.ts +0 -6
- package/src/auto-reply.test-harness.ts +0 -421
- package/src/auto-reply.ts +0 -1
- package/src/auto-reply.web-auto-reply.compresses-common-formats-jpeg-cap.test.ts +0 -427
- package/src/auto-reply.web-auto-reply.connection-and-logging.e2e.test.ts +0 -908
- package/src/auto-reply.web-auto-reply.last-route.test.ts +0 -184
- package/src/channel-actions.runtime.ts +0 -7
- package/src/channel-actions.test.ts +0 -216
- package/src/channel-actions.ts +0 -84
- package/src/channel-outbound.test.ts +0 -131
- package/src/channel-outbound.ts +0 -36
- package/src/channel-react-action.runtime.ts +0 -7
- package/src/channel-react-action.test.ts +0 -294
- package/src/channel-react-action.ts +0 -84
- package/src/channel.runtime.ts +0 -117
- package/src/channel.setup.test.ts +0 -461
- package/src/channel.setup.ts +0 -28
- package/src/channel.ts +0 -334
- package/src/command-policy.ts +0 -7
- package/src/config-accessors.test.ts +0 -34
- package/src/config-accessors.ts +0 -22
- package/src/config-schema.test.ts +0 -121
- package/src/config-schema.ts +0 -6
- package/src/config-ui-hints.ts +0 -24
- package/src/connection-controller-registry.test.ts +0 -27
- package/src/connection-controller-registry.ts +0 -49
- package/src/connection-controller.test.ts +0 -282
- package/src/connection-controller.ts +0 -679
- package/src/creds-files.ts +0 -19
- package/src/creds-persistence.ts +0 -102
- package/src/directory-config.test.ts +0 -60
- package/src/directory-config.ts +0 -40
- package/src/directory-contract.test.ts +0 -56
- package/src/doctor-contract.ts +0 -11
- package/src/doctor.test.ts +0 -74
- package/src/doctor.ts +0 -56
- package/src/group-intro.ts +0 -15
- package/src/group-policy.test.ts +0 -36
- package/src/group-policy.ts +0 -40
- package/src/group-session-contract.ts +0 -20
- package/src/group-session-key.test.ts +0 -53
- package/src/group-session-key.ts +0 -41
- package/src/heartbeat.ts +0 -34
- package/src/identity.ts +0 -164
- package/src/inbound/access-control.test-harness.ts +0 -37
- package/src/inbound/access-control.test.ts +0 -375
- package/src/inbound/access-control.ts +0 -237
- package/src/inbound/dedupe.ts +0 -132
- package/src/inbound/extract.test.ts +0 -282
- package/src/inbound/extract.ts +0 -488
- package/src/inbound/lifecycle.ts +0 -39
- package/src/inbound/media.node.test.ts +0 -83
- package/src/inbound/media.ts +0 -102
- package/src/inbound/monitor.ts +0 -890
- package/src/inbound/runtime-api.ts +0 -7
- package/src/inbound/save-media.runtime.ts +0 -1
- package/src/inbound/send-api.test.ts +0 -307
- package/src/inbound/send-api.ts +0 -141
- package/src/inbound/send-result.ts +0 -61
- package/src/inbound/types.ts +0 -106
- package/src/inbound-context.contract.test.ts +0 -32
- package/src/inbound-policy.ts +0 -231
- package/src/inbound.media.test.ts +0 -320
- package/src/inbound.test.ts +0 -290
- package/src/inbound.ts +0 -9
- package/src/login-qr.test.ts +0 -483
- package/src/login-qr.ts +0 -542
- package/src/login.coverage.test.ts +0 -133
- package/src/login.test.ts +0 -89
- package/src/login.ts +0 -70
- package/src/logout.test.ts +0 -162
- package/src/media.test.ts +0 -480
- package/src/media.ts +0 -10
- package/src/monitor-inbox.allows-messages-from-senders-allowfrom-list.test-support.ts +0 -400
- package/src/monitor-inbox.append-upsert.test-support.ts +0 -133
- package/src/monitor-inbox.behavior.test.ts +0 -5
- package/src/monitor-inbox.blocks-messages-from-unauthorized-senders-not-allowfrom.test-support.ts +0 -362
- package/src/monitor-inbox.captures-media-path-image-messages.test-support.ts +0 -306
- package/src/monitor-inbox.streams-inbound-messages.test-support.ts +0 -729
- package/src/monitor-inbox.test-harness.ts +0 -304
- package/src/normalize-target.ts +0 -112
- package/src/normalize.ts +0 -6
- package/src/outbound-adapter.poll.test.ts +0 -62
- package/src/outbound-adapter.sendpayload.test.ts +0 -195
- package/src/outbound-adapter.ts +0 -36
- package/src/outbound-base.test.ts +0 -560
- package/src/outbound-base.ts +0 -244
- package/src/outbound-media-contract.ts +0 -278
- package/src/outbound-media.runtime.ts +0 -36
- package/src/outbound-payload.contract.test.ts +0 -61
- package/src/outbound-send-deps.ts +0 -1
- package/src/outbound-test-support.ts +0 -16
- package/src/pairing-security.test-harness.ts +0 -59
- package/src/qr-image.ts +0 -1
- package/src/qr-terminal.ts +0 -1
- package/src/quoted-message.test.ts +0 -83
- package/src/quoted-message.ts +0 -184
- package/src/reaction-level.test.ts +0 -94
- package/src/reaction-level.ts +0 -21
- package/src/reconnect.test.ts +0 -51
- package/src/reconnect.ts +0 -55
- package/src/resolve-outbound-target.test.ts +0 -265
- package/src/resolve-outbound-target.ts +0 -54
- package/src/resolve-target.test.ts +0 -97
- package/src/runtime-api.ts +0 -59
- package/src/runtime-group-policy.ts +0 -16
- package/src/runtime.ts +0 -9
- package/src/security-contract.ts +0 -47
- package/src/security-fix.ts +0 -71
- package/src/send.test.ts +0 -515
- package/src/send.ts +0 -287
- package/src/session-contract.test.ts +0 -31
- package/src/session-contract.ts +0 -43
- package/src/session-errors.ts +0 -125
- package/src/session-route.ts +0 -26
- package/src/session.runtime.ts +0 -8
- package/src/session.test.ts +0 -559
- package/src/session.ts +0 -330
- package/src/setup-core.ts +0 -52
- package/src/setup-finalize.ts +0 -446
- package/src/setup-surface.test.ts +0 -367
- package/src/setup-surface.ts +0 -69
- package/src/setup-test-helpers.ts +0 -216
- package/src/shared.ts +0 -291
- package/src/socket-timing.test.ts +0 -49
- package/src/socket-timing.ts +0 -38
- package/src/state-migrations.ts +0 -54
- package/src/status-issues.test.ts +0 -137
- package/src/status-issues.ts +0 -185
- package/src/system-prompt.test.ts +0 -199
- package/src/system-prompt.ts +0 -31
- package/src/targets-runtime.ts +0 -180
- package/src/test-helpers.ts +0 -690
- package/src/text-runtime.test.ts +0 -162
- package/src/text-runtime.ts +0 -11
- package/src/vcard.ts +0 -84
- package/targets.ts +0 -5
- package/test-api.ts +0 -2
- 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,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
|
+
``
|
|
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 };
|