@openclaw/whatsapp 2026.7.2-beta.2 → 2026.7.2-beta.4
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-DazDX3RB.js → access-control-CRz_v6bR.js} +4 -5
- package/dist/{accounts-CKOFMPf-.js → accounts-CxPuEFi-.js} +44 -4
- package/dist/{action-runtime-Bf-12TIH.js → action-runtime-CHU7xb6o.js} +2 -2
- package/dist/action-runtime-api.js +1 -1
- package/dist/action-runtime.runtime.js +1 -1
- package/dist/{active-listener-5kHap439.js → active-listener-BEjWsCNM.js} +1 -1
- package/dist/api.js +12 -15
- package/dist/{approval-handler.runtime-CBiGQuZ5.js → approval-handler.runtime-C4ddB7Kc.js} +4 -4
- package/dist/{approval-reactions-BGQoz25s.js → approval-reactions-P2HXjmln.js} +3 -3
- package/dist/{auth-store-BQi9pZqQ.js → auth-store-DirYMTbo.js} +4 -3
- package/dist/call-tool-api.js +4 -4
- package/dist/{channel-DbadDUDD.js → channel-B9xjrOGG.js} +37 -19
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel-react-action-PoRWfP9x.js → channel-react-action-CBW-PA8q.js} +10 -13
- package/dist/{channel.runtime-BDDy4Lhz.js → channel.runtime-DdKuhlNu.js} +5 -5
- package/dist/{channel.setup-BZ-po8fg.js → channel.setup-DXUCPHel.js} +3 -6
- package/dist/{config-schema-BZ8h1hWA.js → config-schema-C6IeKIC0.js} +6 -0
- package/dist/{connection-controller-C1rwfWb4.js → connection-controller-BVRExqrB.js} +186 -27
- package/dist/connection-controller-runtime-context-DG0tuYuw.js +23 -0
- package/dist/contract-api.js +1 -1
- package/dist/directory-config-BTbJkV1W.js +196 -0
- package/dist/directory-contract-api.js +1 -1
- package/dist/doctor-CwzVXKoE.js +10 -0
- package/dist/doctor-contract-api.js +35 -79
- package/dist/{group-session-key-CLTZeH_F.js → group-session-key-DJSdYfnb.js} +9 -4
- package/dist/{identity-D7L8LCuH.js → identity-BM4_wZeM.js} +2 -2
- package/dist/light-runtime-api.js +2 -2
- package/dist/{login-DGIoToX8.js → login-BKUm7KSk.js} +6 -7
- package/dist/{login-qr-X-CZHOk9.js → login-qr-DagJvMbg.js} +7 -8
- package/dist/login-qr-runtime.js +1 -1
- package/dist/{monitor-BZ8QvCeV.js → monitor-CBVNJ2lb.js} +623 -400
- package/dist/question-reactions-CaOrSYzU.js +142 -0
- package/dist/runtime-BLlToOi6.js +21 -0
- package/dist/runtime-api.js +10 -10
- package/dist/runtime-setter-api.js +1 -1
- package/dist/{send-D9Ydnn4o.js → send-DhJVN30g.js} +38 -85
- package/dist/{send-api-W33lI2nR.js → send-api-CpHwbor_.js} +38 -32
- package/dist/{setup-finalize-DBf1jjBj.js → setup-finalize-9XzKdFq6.js} +3 -3
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{setup-surface-CiKGdNJv.js → setup-surface-Kv3mPki2.js} +3 -3
- package/dist/{setup-core-3aSOoK2T.js → shared-CuqHFnKd.js} +78 -56
- package/dist/{session-mxWFn0eS.js → socket-close-BoSHhQNJ.js} +226 -7
- package/dist/{targets-runtime-Bsh0HR9y.js → targets-runtime-CKFrhoX4.js} +142 -29
- package/dist/text-runtime-CU_IlbK5.js +4 -0
- package/node_modules/@protobufjs/utf8/CHANGELOG.md +8 -0
- package/node_modules/@protobufjs/utf8/index.js +29 -18
- package/node_modules/@protobufjs/utf8/package.json +2 -2
- package/node_modules/@protobufjs/utf8/tests/index.js +5 -0
- package/node_modules/@thi.ng/bitstream/package.json +4 -4
- package/node_modules/@thi.ng/errors/package.json +4 -4
- package/node_modules/@types/node/README.md +1 -1
- package/node_modules/@types/node/fs/promises.d.ts +16 -6
- package/node_modules/@types/node/package.json +2 -2
- package/node_modules/audio-type/package.json +3 -2
- package/node_modules/lru-cache/dist/commonjs/browser/index.d.ts.map +1 -1
- package/node_modules/lru-cache/dist/commonjs/browser/index.js +11 -4
- package/node_modules/lru-cache/dist/commonjs/browser/index.js.map +1 -1
- package/node_modules/lru-cache/dist/commonjs/browser/index.min.js +1 -1
- package/node_modules/lru-cache/dist/commonjs/browser/index.min.js.map +3 -3
- package/node_modules/lru-cache/dist/commonjs/index.d.ts.map +1 -1
- package/node_modules/lru-cache/dist/commonjs/index.js +11 -4
- package/node_modules/lru-cache/dist/commonjs/index.js.map +1 -1
- package/node_modules/lru-cache/dist/commonjs/index.min.js +1 -1
- package/node_modules/lru-cache/dist/commonjs/index.min.js.map +3 -3
- package/node_modules/lru-cache/dist/commonjs/node/index.d.ts.map +1 -1
- package/node_modules/lru-cache/dist/commonjs/node/index.js +11 -4
- package/node_modules/lru-cache/dist/commonjs/node/index.js.map +1 -1
- package/node_modules/lru-cache/dist/commonjs/node/index.min.js +1 -1
- package/node_modules/lru-cache/dist/commonjs/node/index.min.js.map +3 -3
- package/node_modules/lru-cache/dist/esm/browser/index.d.ts.map +1 -1
- package/node_modules/lru-cache/dist/esm/browser/index.js +11 -4
- package/node_modules/lru-cache/dist/esm/browser/index.js.map +1 -1
- package/node_modules/lru-cache/dist/esm/browser/index.min.js +1 -1
- package/node_modules/lru-cache/dist/esm/browser/index.min.js.map +3 -3
- package/node_modules/lru-cache/dist/esm/index.d.ts.map +1 -1
- package/node_modules/lru-cache/dist/esm/index.js +11 -4
- package/node_modules/lru-cache/dist/esm/index.js.map +1 -1
- package/node_modules/lru-cache/dist/esm/index.min.js +1 -1
- package/node_modules/lru-cache/dist/esm/index.min.js.map +3 -3
- package/node_modules/lru-cache/dist/esm/node/index.d.ts.map +1 -1
- package/node_modules/lru-cache/dist/esm/node/index.js +11 -4
- package/node_modules/lru-cache/dist/esm/node/index.js.map +1 -1
- package/node_modules/lru-cache/dist/esm/node/index.min.js +1 -1
- package/node_modules/lru-cache/dist/esm/node/index.min.js.map +3 -3
- package/node_modules/lru-cache/package.json +1 -1
- package/node_modules/music-metadata/lib/common/Util.d.ts +1 -1
- package/node_modules/music-metadata/lib/common/Util.js +7 -1
- package/node_modules/music-metadata/lib/id3v2/FrameHeader.js +23 -3
- package/node_modules/music-metadata/lib/id3v2/FrameParser.js +2 -2
- package/node_modules/music-metadata/lib/id3v2/ID3v2Token.js +1 -1
- package/node_modules/music-metadata/lib/mp4/AtomToken.js +38 -13
- package/node_modules/music-metadata/lib/mpeg/MpegParser.js +1 -1
- package/node_modules/music-metadata/package.json +6 -6
- package/node_modules/p-queue/dist/index.js +17 -6
- package/node_modules/p-queue/package.json +1 -1
- package/node_modules/protobufjs/dist/light/protobuf.js +145 -188
- package/node_modules/protobufjs/dist/light/protobuf.js.map +1 -1
- package/node_modules/protobufjs/dist/light/protobuf.min.js +3 -3
- package/node_modules/protobufjs/dist/light/protobuf.min.js.map +1 -1
- package/node_modules/protobufjs/dist/minimal/protobuf.js +33 -76
- package/node_modules/protobufjs/dist/minimal/protobuf.js.map +1 -1
- package/node_modules/protobufjs/dist/minimal/protobuf.min.js +3 -3
- package/node_modules/protobufjs/dist/minimal/protobuf.min.js.map +1 -1
- package/node_modules/protobufjs/dist/protobuf.js +168 -208
- package/node_modules/protobufjs/dist/protobuf.js.map +1 -1
- package/node_modules/protobufjs/dist/protobuf.min.js +3 -3
- package/node_modules/protobufjs/dist/protobuf.min.js.map +1 -1
- package/node_modules/protobufjs/index.d.ts +0 -8
- package/node_modules/protobufjs/package.json +2 -3
- package/node_modules/protobufjs/src/parse.js +3 -0
- package/node_modules/protobufjs/src/util/minimal.js +0 -3
- package/node_modules/typebox/build/compile/validator.d.mts +1 -4
- package/node_modules/typebox/build/guard/guard.d.mts +1 -1
- package/node_modules/typebox/build/guard/guard.mjs +5 -2
- package/node_modules/typebox/build/guard/string.mjs +16 -4
- package/node_modules/typebox/build/schema/engine/_functions.mjs +34 -15
- package/node_modules/typebox/build/type/action/readonly_object.d.mts +5 -0
- package/node_modules/typebox/build/type/action/readonly_object.mjs +8 -0
- package/node_modules/typebox/build/typebox.d.mts +1 -1
- package/node_modules/typebox/build/typebox.mjs +1 -1
- package/node_modules/typebox/package.json +1 -1
- package/node_modules/typebox/readme.md +29 -32
- package/node_modules/ws/lib/receiver.js +15 -32
- package/node_modules/ws/lib/websocket-server.js +4 -4
- package/node_modules/ws/lib/websocket.js +4 -4
- package/node_modules/ws/package.json +5 -1
- package/npm-shrinkwrap.json +41 -45
- package/openclaw.plugin.json +139 -179
- package/package.json +21 -11
- package/dist/account-config-LiT9wWH9.js +0 -43
- package/dist/connection-controller-runtime-context-CbTsqmPT.js +0 -14
- package/dist/directory-config-CLBQrjtC.js +0 -37
- package/dist/doctor-By3SB4lm.js +0 -48
- package/dist/runtime-BfAdAEYT.js +0 -8
- package/dist/text-runtime-BTGkMN0o.js +0 -4
- package/node_modules/@protobufjs/inquire/CHANGELOG.md +0 -8
- package/node_modules/@protobufjs/inquire/LICENSE +0 -26
- package/node_modules/@protobufjs/inquire/README.md +0 -13
- package/node_modules/@protobufjs/inquire/index.d.ts +0 -10
- package/node_modules/@protobufjs/inquire/index.js +0 -38
- package/node_modules/@protobufjs/inquire/package.json +0 -21
- package/node_modules/@protobufjs/inquire/tests/data/array.js +0 -1
- package/node_modules/@protobufjs/inquire/tests/data/emptyArray.js +0 -1
- package/node_modules/@protobufjs/inquire/tests/data/emptyObject.js +0 -1
- package/node_modules/@protobufjs/inquire/tests/data/object.js +0 -1
- package/node_modules/@protobufjs/inquire/tests/index.js +0 -20
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { a as resolveWhatsAppAccount, n as hasAnyWhatsAppAuth } from "./accounts-CxPuEFi-.js";
|
|
1
2
|
import { r as resolveDefaultWhatsAppAccountId, t as listAccountIds } from "./account-ids-CB5SOWjc.js";
|
|
2
|
-
import { a as resolveWhatsAppAccount, n as hasAnyWhatsAppAuth } from "./accounts-CKOFMPf-.js";
|
|
3
3
|
import { a as normalizeWhatsAppAllowFromEntries } from "./normalize-target-DSZnHkKF.js";
|
|
4
|
-
import { t as WhatsAppChannelConfigSchema } from "./config-schema-
|
|
5
|
-
import { n as whatsappDoctor } from "./doctor-
|
|
4
|
+
import { t as WhatsAppChannelConfigSchema } from "./config-schema-C6IeKIC0.js";
|
|
5
|
+
import { n as whatsappDoctor } from "./doctor-CwzVXKoE.js";
|
|
6
6
|
import { t as resolveWhatsAppConfigPath } from "./group-config-path-BGyzT9Lg.js";
|
|
7
7
|
import { t as resolveLegacyGroupSessionKey } from "./group-session-contract-DDnZSsJ1.js";
|
|
8
8
|
import { n as unsupportedSecretRefSurfacePatterns, t as collectUnsupportedSecretRefConfigCandidates } from "./security-contract-nAzD945y.js";
|
|
@@ -11,12 +11,24 @@ import { normalizeUniqueStringEntries } from "openclaw/plugin-sdk/string-coerce-
|
|
|
11
11
|
import { normalizeE164 } from "openclaw/plugin-sdk/account-resolution";
|
|
12
12
|
import { createChannelPluginBase } from "openclaw/plugin-sdk/core";
|
|
13
13
|
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
|
|
14
|
+
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
14
15
|
import { buildChannelGroupsScopeTree, collectOpenGroupPolicyRouteAllowlistWarnings, createAllowlistProviderGroupPolicyWarningCollector, resolveScopeRequireMention, resolveScopeToolsPolicy } from "openclaw/plugin-sdk/channel-policy";
|
|
16
|
+
import { defineChannelSetupContract } from "openclaw/plugin-sdk/channel-setup";
|
|
17
|
+
import { applyAccountNameToChannelSection, migrateBaseNameToDefaultAccount, normalizeAccountId as normalizeAccountId$1 } from "openclaw/plugin-sdk/setup";
|
|
15
18
|
import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
16
19
|
import { adaptScopedAccountAccessor, createScopedChannelConfigAdapter, createScopedDmSecurityResolver } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
17
20
|
import { createDelegatedSetupWizardProxy } from "openclaw/plugin-sdk/setup-runtime";
|
|
18
21
|
import { readChannelAllowFromStore } from "openclaw/plugin-sdk/channel-pairing";
|
|
19
|
-
|
|
22
|
+
//#region extensions/whatsapp/src/channel-runtime-loader.ts
|
|
23
|
+
const loadWhatsAppAuthStore = createLazyRuntimeModule(() => import("./auth-store-DirYMTbo.js").then((n) => n.i));
|
|
24
|
+
async function isWhatsAppAuthConfigured(authDir) {
|
|
25
|
+
return await (await loadWhatsAppAuthStore()).readWebAuthState(authDir) === "linked";
|
|
26
|
+
}
|
|
27
|
+
const loadWhatsAppChannelRuntime = createLazyRuntimeModule(async () => {
|
|
28
|
+
await loadWhatsAppAuthStore();
|
|
29
|
+
return await import("./channel.runtime-DdKuhlNu.js");
|
|
30
|
+
});
|
|
31
|
+
//#endregion
|
|
20
32
|
//#region extensions/whatsapp/src/config-accessors.ts
|
|
21
33
|
function formatWhatsAppConfigAllowFromEntries(allowFrom) {
|
|
22
34
|
return normalizeWhatsAppAllowFromEntries(allowFrom);
|
|
@@ -41,6 +53,62 @@ function resolveWhatsAppGroupToolPolicy(params) {
|
|
|
41
53
|
});
|
|
42
54
|
}
|
|
43
55
|
//#endregion
|
|
56
|
+
//#region extensions/whatsapp/src/setup-core.ts
|
|
57
|
+
const channel = "whatsapp";
|
|
58
|
+
const whatsappSetupAdapter = {
|
|
59
|
+
singleAccountKeysToMove: ["authDir"],
|
|
60
|
+
resolveAccountId: ({ accountId }) => normalizeAccountId$1(accountId),
|
|
61
|
+
applyAccountName: ({ cfg, accountId, name }) => applyAccountNameToChannelSection({
|
|
62
|
+
cfg,
|
|
63
|
+
channelKey: channel,
|
|
64
|
+
accountId,
|
|
65
|
+
name,
|
|
66
|
+
alwaysUseAccounts: true
|
|
67
|
+
}),
|
|
68
|
+
applyAccountConfig: ({ cfg, accountId, input }) => {
|
|
69
|
+
const setupInput = input;
|
|
70
|
+
const next = migrateBaseNameToDefaultAccount({
|
|
71
|
+
cfg: applyAccountNameToChannelSection({
|
|
72
|
+
cfg,
|
|
73
|
+
channelKey: channel,
|
|
74
|
+
accountId,
|
|
75
|
+
name: setupInput.name,
|
|
76
|
+
alwaysUseAccounts: true
|
|
77
|
+
}),
|
|
78
|
+
channelKey: channel,
|
|
79
|
+
alwaysUseAccounts: true
|
|
80
|
+
});
|
|
81
|
+
const entry = {
|
|
82
|
+
...next.channels?.whatsapp?.accounts?.[accountId],
|
|
83
|
+
...setupInput.authDir ? { authDir: setupInput.authDir } : {},
|
|
84
|
+
enabled: true
|
|
85
|
+
};
|
|
86
|
+
return {
|
|
87
|
+
...next,
|
|
88
|
+
channels: {
|
|
89
|
+
...next.channels,
|
|
90
|
+
whatsapp: {
|
|
91
|
+
...next.channels?.whatsapp,
|
|
92
|
+
accounts: {
|
|
93
|
+
...next.channels?.whatsapp?.accounts,
|
|
94
|
+
[accountId]: entry
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const whatsappSetupContract = defineChannelSetupContract({
|
|
102
|
+
fields: { authDir: {
|
|
103
|
+
kind: "string",
|
|
104
|
+
cli: {
|
|
105
|
+
flags: "--auth-dir <path>",
|
|
106
|
+
description: "WhatsApp auth directory override"
|
|
107
|
+
}
|
|
108
|
+
} },
|
|
109
|
+
legacyAdapter: whatsappSetupAdapter
|
|
110
|
+
});
|
|
111
|
+
//#endregion
|
|
44
112
|
//#region extensions/whatsapp/src/security-fix.ts
|
|
45
113
|
function applyGroupAllowFromFromStore(params) {
|
|
46
114
|
const next = structuredClone(params.cfg ?? {});
|
|
@@ -83,11 +151,8 @@ async function applyWhatsAppSecurityConfigFixes(params) {
|
|
|
83
151
|
//#endregion
|
|
84
152
|
//#region extensions/whatsapp/src/shared.ts
|
|
85
153
|
const WHATSAPP_CHANNEL = "whatsapp";
|
|
86
|
-
async function loadWhatsAppChannelRuntime() {
|
|
87
|
-
return await import("./channel.runtime-BDDy4Lhz.js");
|
|
88
|
-
}
|
|
89
154
|
async function loadWhatsAppSetupSurface() {
|
|
90
|
-
return await import("./setup-surface-
|
|
155
|
+
return await import("./setup-surface-Kv3mPki2.js");
|
|
91
156
|
}
|
|
92
157
|
const whatsappSetupWizardProxy = createWhatsAppSetupWizardProxy(async () => (await loadWhatsAppSetupSurface()).whatsappSetupWizard);
|
|
93
158
|
const whatsappConfigAdapter = createScopedChannelConfigAdapter({
|
|
@@ -191,7 +256,7 @@ function createWhatsAppPluginBase(params) {
|
|
|
191
256
|
docsLabel: "whatsapp",
|
|
192
257
|
blurb: "works with your own number; recommend a separate phone + eSIM.",
|
|
193
258
|
systemImage: "message",
|
|
194
|
-
|
|
259
|
+
exposure: { configured: false },
|
|
195
260
|
quickstartAllowFrom: true,
|
|
196
261
|
forceAccountBinding: true,
|
|
197
262
|
preferSessionLookupForAnnounceTarget: true
|
|
@@ -213,7 +278,7 @@ function createWhatsAppPluginBase(params) {
|
|
|
213
278
|
},
|
|
214
279
|
reload: {
|
|
215
280
|
configPrefixes: [
|
|
216
|
-
"
|
|
281
|
+
"channels.whatsapp.enabled",
|
|
217
282
|
"channels.whatsapp.accounts",
|
|
218
283
|
"channels.whatsapp.selfChatMode"
|
|
219
284
|
],
|
|
@@ -223,7 +288,7 @@ function createWhatsAppPluginBase(params) {
|
|
|
223
288
|
configSchema: WhatsAppChannelConfigSchema,
|
|
224
289
|
config: {
|
|
225
290
|
...whatsappConfigAdapter,
|
|
226
|
-
isEnabled: (account
|
|
291
|
+
isEnabled: (account) => account.enabled,
|
|
227
292
|
disabledReason: () => "disabled",
|
|
228
293
|
isConfigured: params.isConfigured,
|
|
229
294
|
hasPersistedAuthState: ({ cfg }) => hasAnyWhatsAppAuth(cfg),
|
|
@@ -245,6 +310,7 @@ function createWhatsAppPluginBase(params) {
|
|
|
245
310
|
},
|
|
246
311
|
doctor: whatsappDoctor,
|
|
247
312
|
setup: params.setup,
|
|
313
|
+
...params.setupContract ? { setupContract: params.setupContract } : {},
|
|
248
314
|
groups: params.groups
|
|
249
315
|
});
|
|
250
316
|
return {
|
|
@@ -274,48 +340,4 @@ function createWhatsAppPluginBase(params) {
|
|
|
274
340
|
};
|
|
275
341
|
}
|
|
276
342
|
//#endregion
|
|
277
|
-
|
|
278
|
-
const channel = "whatsapp";
|
|
279
|
-
const whatsappSetupAdapter = {
|
|
280
|
-
resolveAccountId: ({ accountId }) => normalizeAccountId$1(accountId),
|
|
281
|
-
applyAccountName: ({ cfg, accountId, name }) => applyAccountNameToChannelSection({
|
|
282
|
-
cfg,
|
|
283
|
-
channelKey: channel,
|
|
284
|
-
accountId,
|
|
285
|
-
name,
|
|
286
|
-
alwaysUseAccounts: true
|
|
287
|
-
}),
|
|
288
|
-
applyAccountConfig: ({ cfg, accountId, input }) => {
|
|
289
|
-
const next = migrateBaseNameToDefaultAccount({
|
|
290
|
-
cfg: applyAccountNameToChannelSection({
|
|
291
|
-
cfg,
|
|
292
|
-
channelKey: channel,
|
|
293
|
-
accountId,
|
|
294
|
-
name: input.name,
|
|
295
|
-
alwaysUseAccounts: true
|
|
296
|
-
}),
|
|
297
|
-
channelKey: channel,
|
|
298
|
-
alwaysUseAccounts: true
|
|
299
|
-
});
|
|
300
|
-
const entry = {
|
|
301
|
-
...next.channels?.whatsapp?.accounts?.[accountId],
|
|
302
|
-
...input.authDir ? { authDir: input.authDir } : {},
|
|
303
|
-
enabled: true
|
|
304
|
-
};
|
|
305
|
-
return {
|
|
306
|
-
...next,
|
|
307
|
-
channels: {
|
|
308
|
-
...next.channels,
|
|
309
|
-
whatsapp: {
|
|
310
|
-
...next.channels?.whatsapp,
|
|
311
|
-
accounts: {
|
|
312
|
-
...next.channels?.whatsapp?.accounts,
|
|
313
|
-
[accountId]: entry
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
};
|
|
318
|
-
}
|
|
319
|
-
};
|
|
320
|
-
//#endregion
|
|
321
|
-
export { resolveWhatsAppGroupRequireMention as a, whatsappSetupWizardProxy as i, createWhatsAppPluginBase as n, resolveWhatsAppGroupToolPolicy as o, loadWhatsAppChannelRuntime as r, formatWhatsAppConfigAllowFromEntries as s, whatsappSetupAdapter as t };
|
|
343
|
+
export { resolveWhatsAppGroupRequireMention as a, isWhatsAppAuthConfigured as c, whatsappSetupContract as i, loadWhatsAppChannelRuntime as l, whatsappSetupWizardProxy as n, resolveWhatsAppGroupToolPolicy as o, whatsappSetupAdapter as r, formatWhatsAppConfigAllowFromEntries as s, createWhatsAppPluginBase as t };
|
|
@@ -1,14 +1,166 @@
|
|
|
1
1
|
import { o as resolveWebCredsBackupPath, s as resolveWebCredsPath, t as assertWebCredsPathRegularFileOrMissing } from "./creds-files-B1kSWtBg.js";
|
|
2
|
-
import { E as writeWebCredsRawAtomically, S as enqueueCredsSave, T as writeCredsJsonAtomically, b as restoreCredsFromBackupIfNeeded, u as readCredsJsonRaw, w as waitForCredsSaveQueueWithTimeout, y as resolveDefaultWebAuthDir } from "./auth-store-
|
|
2
|
+
import { E as writeWebCredsRawAtomically, S as enqueueCredsSave, T as writeCredsJsonAtomically, b as restoreCredsFromBackupIfNeeded, u as readCredsJsonRaw, w as waitForCredsSaveQueueWithTimeout, y as resolveDefaultWebAuthDir } from "./auth-store-DirYMTbo.js";
|
|
3
3
|
import { n as getStatusCode } from "./session-errors-JuazczrA.js";
|
|
4
4
|
import { a as makeWASocket, i as makeCacheableSignalKeyStore, n as createBaileysSignalRepository, r as fetchLatestBaileysVersion, s as useMultiFileAuthState } from "./session.runtime-Nsqaehbd.js";
|
|
5
5
|
import { VERSION, formatCliCommand } from "openclaw/plugin-sdk/cli-runtime";
|
|
6
6
|
import { danger, getChildLogger, success, toPinoLikeLogger } from "openclaw/plugin-sdk/runtime-env";
|
|
7
7
|
import { renderQrTerminal } from "openclaw/plugin-sdk/media-runtime";
|
|
8
8
|
import { ensureDir, resolveUserPath } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
9
|
+
import fs from "node:fs/promises";
|
|
9
10
|
import { parseStrictPositiveInteger, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
11
|
+
import { FILE_LOCK_STALE_ERROR_CODE, FILE_LOCK_TIMEOUT_ERROR_CODE, acquireFileLock } from "openclaw/plugin-sdk/file-lock";
|
|
10
12
|
import { randomUUID } from "node:crypto";
|
|
11
13
|
import { createHttp1EnvHttpProxyAgent, createHttp1ProxyAgent, createNodeProxyAgent } from "openclaw/plugin-sdk/fetch-runtime";
|
|
14
|
+
//#region extensions/whatsapp/src/connection-owner.ts
|
|
15
|
+
const WHATSAPP_CONNECTION_OWNER_BUSY_CODE = "whatsapp_connection_owner_busy";
|
|
16
|
+
var WhatsAppConnectionOwnerBusyError = class extends Error {
|
|
17
|
+
constructor(authDir, options) {
|
|
18
|
+
super("Another process owns this WhatsApp connection.", options);
|
|
19
|
+
this.authDir = authDir;
|
|
20
|
+
this.code = WHATSAPP_CONNECTION_OWNER_BUSY_CODE;
|
|
21
|
+
this.name = "WhatsAppConnectionOwnerBusyError";
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const OWNER_LOCK_STALE_MS = 5 * 6e4;
|
|
25
|
+
const GATEWAY_LOCAL_OWNER_WAIT_MS = 15e4;
|
|
26
|
+
const processOwners = /* @__PURE__ */ new Map();
|
|
27
|
+
function ownershipCancelledError(signal) {
|
|
28
|
+
const reason = signal?.reason;
|
|
29
|
+
return reason instanceof Error ? reason : new Error("WhatsApp connection ownership cancelled", reason === void 0 ? {} : { cause: reason });
|
|
30
|
+
}
|
|
31
|
+
async function waitForAbortableDelay(delayMs, signal) {
|
|
32
|
+
if (signal?.aborted) throw ownershipCancelledError(signal);
|
|
33
|
+
await new Promise((resolve, reject) => {
|
|
34
|
+
const onAbort = () => {
|
|
35
|
+
clearTimeout(timer);
|
|
36
|
+
reject(ownershipCancelledError(signal));
|
|
37
|
+
};
|
|
38
|
+
const timer = setTimeout(() => {
|
|
39
|
+
signal?.removeEventListener("abort", onAbort);
|
|
40
|
+
resolve();
|
|
41
|
+
}, delayMs);
|
|
42
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
async function reserveProcessOwner(params) {
|
|
46
|
+
while (true) {
|
|
47
|
+
if (params.signal?.aborted) throw ownershipCancelledError(params.signal);
|
|
48
|
+
const current = processOwners.get(params.ownerPath);
|
|
49
|
+
if (!current) {
|
|
50
|
+
let resolveReleased = () => {};
|
|
51
|
+
const owner = {
|
|
52
|
+
released: new Promise((resolve) => {
|
|
53
|
+
resolveReleased = resolve;
|
|
54
|
+
}),
|
|
55
|
+
resolveReleased,
|
|
56
|
+
token: Symbol(params.ownerPath)
|
|
57
|
+
};
|
|
58
|
+
processOwners.set(params.ownerPath, owner);
|
|
59
|
+
return owner;
|
|
60
|
+
}
|
|
61
|
+
if (!params.waitForLocalOwner) throw new WhatsAppConnectionOwnerBusyError(params.authDir);
|
|
62
|
+
let timer;
|
|
63
|
+
let onAbort;
|
|
64
|
+
const outcome = await Promise.race([
|
|
65
|
+
current.released.then(() => "released"),
|
|
66
|
+
new Promise((resolve) => {
|
|
67
|
+
timer = setTimeout(() => resolve("timed_out"), GATEWAY_LOCAL_OWNER_WAIT_MS);
|
|
68
|
+
timer.unref?.();
|
|
69
|
+
}),
|
|
70
|
+
new Promise((resolve) => {
|
|
71
|
+
onAbort = () => resolve("aborted");
|
|
72
|
+
params.signal?.addEventListener("abort", onAbort, { once: true });
|
|
73
|
+
})
|
|
74
|
+
]).finally(() => {
|
|
75
|
+
if (timer) clearTimeout(timer);
|
|
76
|
+
if (onAbort) params.signal?.removeEventListener("abort", onAbort);
|
|
77
|
+
});
|
|
78
|
+
if (outcome === "aborted") throw ownershipCancelledError(params.signal);
|
|
79
|
+
if (outcome === "timed_out") throw new WhatsAppConnectionOwnerBusyError(params.authDir);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function abandonProcessOwner(ownerPath, owner) {
|
|
83
|
+
if (processOwners.get(ownerPath)?.token !== owner.token) return;
|
|
84
|
+
processOwners.delete(ownerPath);
|
|
85
|
+
owner.resolveReleased();
|
|
86
|
+
}
|
|
87
|
+
async function acquireOwnerLease(params) {
|
|
88
|
+
const resolvedOwnerPath = resolveUserPath(params.authDir);
|
|
89
|
+
await fs.mkdir(resolvedOwnerPath, { recursive: true });
|
|
90
|
+
const ownerPath = await fs.realpath(resolvedOwnerPath);
|
|
91
|
+
const processOwner = await reserveProcessOwner({
|
|
92
|
+
authDir: params.authDir,
|
|
93
|
+
ownerPath,
|
|
94
|
+
signal: params.signal,
|
|
95
|
+
waitForLocalOwner: params.waitForLocalOwner
|
|
96
|
+
});
|
|
97
|
+
let fileLock;
|
|
98
|
+
let attempt = 0;
|
|
99
|
+
while (true) {
|
|
100
|
+
if (params.signal?.aborted) {
|
|
101
|
+
abandonProcessOwner(ownerPath, processOwner);
|
|
102
|
+
throw ownershipCancelledError(params.signal);
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
fileLock = await acquireFileLock(ownerPath, {
|
|
106
|
+
retries: {
|
|
107
|
+
retries: 0,
|
|
108
|
+
factor: 1,
|
|
109
|
+
minTimeout: 1,
|
|
110
|
+
maxTimeout: 1
|
|
111
|
+
},
|
|
112
|
+
stale: OWNER_LOCK_STALE_MS,
|
|
113
|
+
staleRecovery: "remove-if-unchanged"
|
|
114
|
+
});
|
|
115
|
+
break;
|
|
116
|
+
} catch (error) {
|
|
117
|
+
const code = error.code;
|
|
118
|
+
if (code === FILE_LOCK_STALE_ERROR_CODE) {
|
|
119
|
+
abandonProcessOwner(ownerPath, processOwner);
|
|
120
|
+
throw new WhatsAppConnectionOwnerBusyError(params.authDir, { cause: error });
|
|
121
|
+
}
|
|
122
|
+
if (code !== FILE_LOCK_TIMEOUT_ERROR_CODE || attempt >= params.retries) {
|
|
123
|
+
abandonProcessOwner(ownerPath, processOwner);
|
|
124
|
+
if (code === FILE_LOCK_TIMEOUT_ERROR_CODE) throw new WhatsAppConnectionOwnerBusyError(params.authDir, { cause: error });
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
const delayMs = Math.min(100 * 1.5 ** attempt, 1e3);
|
|
128
|
+
attempt += 1;
|
|
129
|
+
await waitForAbortableDelay(delayMs, params.signal).catch((delayError) => {
|
|
130
|
+
abandonProcessOwner(ownerPath, processOwner);
|
|
131
|
+
throw delayError;
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
let releasePromise = null;
|
|
136
|
+
return { release: async () => {
|
|
137
|
+
if (!releasePromise) releasePromise = fileLock.release().then(() => {
|
|
138
|
+
abandonProcessOwner(ownerPath, processOwner);
|
|
139
|
+
}).catch((releaseError) => {
|
|
140
|
+
releasePromise = null;
|
|
141
|
+
throw releaseError;
|
|
142
|
+
});
|
|
143
|
+
await releasePromise;
|
|
144
|
+
} };
|
|
145
|
+
}
|
|
146
|
+
/** Gateway owner waits for a bounded standalone lookup to finish before startup. */
|
|
147
|
+
async function acquireWhatsAppGatewayConnectionOwner(authDir, signal) {
|
|
148
|
+
return await acquireOwnerLease({
|
|
149
|
+
authDir,
|
|
150
|
+
retries: 150,
|
|
151
|
+
signal,
|
|
152
|
+
waitForLocalOwner: true
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
/** Standalone lookup fails quickly when a gateway already owns the account. */
|
|
156
|
+
async function acquireWhatsAppStandaloneConnectionOwner(authDir) {
|
|
157
|
+
return await acquireOwnerLease({
|
|
158
|
+
authDir,
|
|
159
|
+
retries: 3,
|
|
160
|
+
waitForLocalOwner: false
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
//#endregion
|
|
12
164
|
//#region extensions/whatsapp/src/socket-timing.ts
|
|
13
165
|
const socketSendMessageQueueTails = /* @__PURE__ */ new WeakMap();
|
|
14
166
|
const DEFAULT_WHATSAPP_SOCKET_TIMING = {
|
|
@@ -25,12 +177,11 @@ var WhatsAppSocketOperationTimeoutError = class extends Error {
|
|
|
25
177
|
this.name = "WhatsAppSocketOperationTimeoutError";
|
|
26
178
|
}
|
|
27
179
|
};
|
|
28
|
-
function resolveWhatsAppSocketTiming(
|
|
29
|
-
const configured = cfg.web?.whatsapp;
|
|
180
|
+
function resolveWhatsAppSocketTiming(overrides) {
|
|
30
181
|
return {
|
|
31
|
-
keepAliveIntervalMs: parseStrictPositiveInteger(overrides?.keepAliveIntervalMs) ??
|
|
32
|
-
connectTimeoutMs: parseStrictPositiveInteger(overrides?.connectTimeoutMs) ??
|
|
33
|
-
defaultQueryTimeoutMs: parseStrictPositiveInteger(overrides?.defaultQueryTimeoutMs) ??
|
|
182
|
+
keepAliveIntervalMs: parseStrictPositiveInteger(overrides?.keepAliveIntervalMs) ?? DEFAULT_WHATSAPP_SOCKET_TIMING.keepAliveIntervalMs,
|
|
183
|
+
connectTimeoutMs: parseStrictPositiveInteger(overrides?.connectTimeoutMs) ?? DEFAULT_WHATSAPP_SOCKET_TIMING.connectTimeoutMs,
|
|
184
|
+
defaultQueryTimeoutMs: parseStrictPositiveInteger(overrides?.defaultQueryTimeoutMs) ?? DEFAULT_WHATSAPP_SOCKET_TIMING.defaultQueryTimeoutMs
|
|
34
185
|
};
|
|
35
186
|
}
|
|
36
187
|
function isWhatsAppSocketOperationTimeoutError(error) {
|
|
@@ -170,6 +321,9 @@ function resolveEnvWaWebSocketUrl() {
|
|
|
170
321
|
* Consumers can opt into QR printing for interactive login flows.
|
|
171
322
|
*/
|
|
172
323
|
async function createWaSocket(printQr, verbose, opts = {}) {
|
|
324
|
+
return await createWaSocketInternal(printQr, verbose, opts, "normal");
|
|
325
|
+
}
|
|
326
|
+
async function createWaSocketInternal(printQr, verbose, opts, receiveMode) {
|
|
173
327
|
const logger = toPinoLikeLogger(getChildLogger({ module: "baileys" }, { level: verbose ? "info" : "silent" }), verbose ? "info" : "silent");
|
|
174
328
|
const authDir = resolveUserPath(opts.authDir ?? resolveDefaultWebAuthDir());
|
|
175
329
|
await rejectUnsafeWebCredsPath(authDir);
|
|
@@ -261,6 +415,7 @@ async function createWaSocket(printQr, verbose, opts = {}) {
|
|
|
261
415
|
VERSION
|
|
262
416
|
],
|
|
263
417
|
syncFullHistory: false,
|
|
418
|
+
fireInitQueries: receiveMode !== "directory",
|
|
264
419
|
markOnlineOnConnect: false,
|
|
265
420
|
...socketTiming,
|
|
266
421
|
agent,
|
|
@@ -270,6 +425,19 @@ async function createWaSocket(printQr, verbose, opts = {}) {
|
|
|
270
425
|
...opts.getMessage ? { getMessage: opts.getMessage } : {},
|
|
271
426
|
...opts.cachedGroupMetadata ? { cachedGroupMetadata: opts.cachedGroupMetadata } : {}
|
|
272
427
|
});
|
|
428
|
+
if (receiveMode === "directory") for (const event of [
|
|
429
|
+
"CB:message",
|
|
430
|
+
"CB:call",
|
|
431
|
+
"CB:receipt",
|
|
432
|
+
"CB:notification",
|
|
433
|
+
"CB:ack,class:message",
|
|
434
|
+
"CB:presence",
|
|
435
|
+
"CB:chatstate",
|
|
436
|
+
"CB:ib,,dirty",
|
|
437
|
+
"CB:ib,,offline_preview",
|
|
438
|
+
"CB:ib,,offline",
|
|
439
|
+
"CB:ib,,edge_routing"
|
|
440
|
+
]) sock.ws.removeAllListeners(event);
|
|
273
441
|
socketRef.current = sock;
|
|
274
442
|
if (pendingSocketAbort) abortSocketAfterCredentialPersistenceFailure(sock, pendingSocketAbort.error);
|
|
275
443
|
sock.ev.on("creds.update", () => enqueueSaveCreds(authDir, saveCreds, sessionLogger, {
|
|
@@ -303,6 +471,9 @@ async function createWaSocket(printQr, verbose, opts = {}) {
|
|
|
303
471
|
});
|
|
304
472
|
return sock;
|
|
305
473
|
}
|
|
474
|
+
async function createWaDirectorySocket(authDir) {
|
|
475
|
+
return await createWaSocketInternal(false, false, { authDir }, "directory");
|
|
476
|
+
}
|
|
306
477
|
async function resolveEnvProxyAgent(logger) {
|
|
307
478
|
try {
|
|
308
479
|
const agent = createNodeProxyAgent({
|
|
@@ -400,4 +571,52 @@ function createConnectionTimeoutError(timeoutMs) {
|
|
|
400
571
|
return error;
|
|
401
572
|
}
|
|
402
573
|
//#endregion
|
|
403
|
-
|
|
574
|
+
//#region extensions/whatsapp/src/socket-close.ts
|
|
575
|
+
const SOCKET_CLOSE_TIMEOUT_MS = 15e3;
|
|
576
|
+
async function withCloseTimeout(task, operationName) {
|
|
577
|
+
let timer;
|
|
578
|
+
await Promise.race([task, new Promise((_resolve, reject) => {
|
|
579
|
+
timer = setTimeout(() => reject(/* @__PURE__ */ new Error(`WhatsApp ${operationName} timed out`)), SOCKET_CLOSE_TIMEOUT_MS);
|
|
580
|
+
})]).finally(() => {
|
|
581
|
+
if (timer) clearTimeout(timer);
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
async function waitForTransportClose(ws, operation, operationName) {
|
|
585
|
+
let onClose;
|
|
586
|
+
const closed = ws.isClosed ? Promise.resolve() : new Promise((resolve) => {
|
|
587
|
+
onClose = resolve;
|
|
588
|
+
ws.once("close", onClose);
|
|
589
|
+
if (ws.isClosed) onClose();
|
|
590
|
+
});
|
|
591
|
+
try {
|
|
592
|
+
await withCloseTimeout(Promise.all([Promise.resolve(operation), closed]), operationName);
|
|
593
|
+
} finally {
|
|
594
|
+
if (onClose) ws.removeListener("close", onClose);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
/** Close Baileys and verify the transport state before connection ownership moves. */
|
|
598
|
+
async function closeWhatsAppSocketAndWait(sock, reason) {
|
|
599
|
+
const errors = [];
|
|
600
|
+
try {
|
|
601
|
+
const endResult = sock.end(new Error(reason));
|
|
602
|
+
if (sock.ws.isClosed) {
|
|
603
|
+
await waitForTransportClose(sock.ws, endResult, "socket end");
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
if (sock.ws.isClosing) await waitForTransportClose(sock.ws, endResult, "socket end");
|
|
607
|
+
else await withCloseTimeout(Promise.resolve(endResult), "socket end");
|
|
608
|
+
} catch (error) {
|
|
609
|
+
errors.push(error);
|
|
610
|
+
}
|
|
611
|
+
if (sock.ws.isClosed) return;
|
|
612
|
+
try {
|
|
613
|
+
const closeResult = sock.ws.close();
|
|
614
|
+
await waitForTransportClose(sock.ws, closeResult, "WebSocket close");
|
|
615
|
+
} catch (error) {
|
|
616
|
+
errors.push(error);
|
|
617
|
+
}
|
|
618
|
+
if (sock.ws.isClosed) return;
|
|
619
|
+
throw new AggregateError(errors, "WhatsApp socket close could not be confirmed");
|
|
620
|
+
}
|
|
621
|
+
//#endregion
|
|
622
|
+
export { waitForWaConnection as a, isWhatsAppSocketOperationTimeoutError as c, withWhatsAppSocketOperationTimeout as d, renderQrTerminal as f, acquireWhatsAppStandaloneConnectionOwner as h, newConnectionId as i, resolveWhatsAppSocketOperationTimeoutMs as l, acquireWhatsAppGatewayConnectionOwner as m, createWaDirectorySocket as n, DEFAULT_WHATSAPP_SOCKET_TIMING as o, WhatsAppConnectionOwnerBusyError as p, createWaSocket as r, createWhatsAppSocketOperationTimeoutAdapter as s, closeWhatsAppSocketAndWait as t, resolveWhatsAppSocketTiming as u };
|
|
@@ -1,12 +1,66 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { normalizeE164 } from "openclaw/plugin-sdk/account-resolution";
|
|
4
|
+
import { chunkMarkdownTextWithMode } from "openclaw/plugin-sdk/reply-chunking";
|
|
4
5
|
import { logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env";
|
|
5
|
-
import {
|
|
6
|
+
import { markdownToIRWithMeta, renderMarkdownIRChunksWithinLimit, renderMarkdownWithMarkers, sliceMarkdownIR } from "openclaw/plugin-sdk/text-chunking";
|
|
7
|
+
import { CONFIG_DIR, resolveUserPath as resolveUserPath$1 } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
6
8
|
//#region extensions/whatsapp/src/targets-runtime.ts
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
const WHATSAPP_FORMAT_CAPABILITIES = {
|
|
10
|
+
mechanism: "markdown",
|
|
11
|
+
constructs: {
|
|
12
|
+
bold: "native",
|
|
13
|
+
italic: "native",
|
|
14
|
+
underline: "strip",
|
|
15
|
+
strikethrough: "native",
|
|
16
|
+
spoiler: "fallback",
|
|
17
|
+
codeInline: "native",
|
|
18
|
+
codeBlock: "native",
|
|
19
|
+
codeLanguage: "fallback",
|
|
20
|
+
linkLabel: "fallback",
|
|
21
|
+
heading: "fallback",
|
|
22
|
+
bulletList: "native",
|
|
23
|
+
orderedList: "native",
|
|
24
|
+
taskList: "fallback",
|
|
25
|
+
table: "fallback",
|
|
26
|
+
blockquote: "native",
|
|
27
|
+
image: "fallback",
|
|
28
|
+
mention: "native"
|
|
29
|
+
},
|
|
30
|
+
chunk: {
|
|
31
|
+
limit: 4096,
|
|
32
|
+
unit: "chars"
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const WHATSAPP_STYLE_MARKERS = {
|
|
36
|
+
bold: {
|
|
37
|
+
open: "*",
|
|
38
|
+
close: "*"
|
|
39
|
+
},
|
|
40
|
+
italic: {
|
|
41
|
+
open: "_",
|
|
42
|
+
close: "_"
|
|
43
|
+
},
|
|
44
|
+
strikethrough: {
|
|
45
|
+
open: "~",
|
|
46
|
+
close: "~"
|
|
47
|
+
},
|
|
48
|
+
code: {
|
|
49
|
+
open: "```",
|
|
50
|
+
close: "```"
|
|
51
|
+
},
|
|
52
|
+
code_block: {
|
|
53
|
+
open: "```\n",
|
|
54
|
+
close: "```"
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const WHATSAPP_INDENT_GUARD = "";
|
|
58
|
+
const WHATSAPP_MARKERS = [
|
|
59
|
+
"*",
|
|
60
|
+
"_",
|
|
61
|
+
"~",
|
|
62
|
+
"`"
|
|
63
|
+
];
|
|
10
64
|
function assertWebChannel(input) {
|
|
11
65
|
if (input !== "web") throw new Error("Web channel must be 'web'");
|
|
12
66
|
}
|
|
@@ -165,31 +219,90 @@ async function resolveJidToE164(jid, opts) {
|
|
|
165
219
|
return null;
|
|
166
220
|
}
|
|
167
221
|
}
|
|
168
|
-
function
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
222
|
+
function protectWhatsAppEscapedMarkers(text) {
|
|
223
|
+
const placeholders = [];
|
|
224
|
+
for (const [start, end] of [[57344, 63743], [983040, 1048573]]) for (let codePoint = start; codePoint <= end && placeholders.length < WHATSAPP_MARKERS.length; codePoint += 1) {
|
|
225
|
+
const candidate = String.fromCodePoint(codePoint);
|
|
226
|
+
if (!text.includes(candidate)) placeholders.push(candidate);
|
|
227
|
+
}
|
|
228
|
+
if (placeholders.length < WHATSAPP_MARKERS.length) throw new Error("Unable to reserve WhatsApp formatting placeholders");
|
|
229
|
+
const markers = WHATSAPP_MARKERS.map((marker, index) => ({
|
|
230
|
+
source: `\\${marker}`,
|
|
231
|
+
placeholder: placeholders[index] ?? ""
|
|
232
|
+
}));
|
|
233
|
+
let protectedText = text;
|
|
234
|
+
for (const { source, placeholder } of markers) protectedText = protectedText.replaceAll(source, placeholder);
|
|
235
|
+
return {
|
|
236
|
+
text: protectedText,
|
|
237
|
+
markers
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
function restoreWhatsAppEscapedMarkers(text, markers) {
|
|
241
|
+
let restored = text;
|
|
242
|
+
for (const { source, placeholder } of markers) restored = restored.replaceAll(placeholder, source);
|
|
243
|
+
return restored;
|
|
244
|
+
}
|
|
245
|
+
function renderWhatsAppMarkdownIR(ir, escapedMarkers) {
|
|
246
|
+
return renderMarkdownWithMarkers(ir, {
|
|
247
|
+
styleMarkers: WHATSAPP_STYLE_MARKERS,
|
|
248
|
+
escapeText: (value) => restoreWhatsAppEscapedMarkers(value, escapedMarkers)
|
|
249
|
+
}, WHATSAPP_FORMAT_CAPABILITIES);
|
|
250
|
+
}
|
|
251
|
+
function prepareWhatsAppMarkdown(text, tableMode) {
|
|
252
|
+
const guardedIndent = /^[\t ]/u.test(text);
|
|
253
|
+
const escaped = protectWhatsAppEscapedMarkers(text);
|
|
254
|
+
const markdown = guardedIndent ? `${WHATSAPP_INDENT_GUARD}${escaped.text}` : escaped.text;
|
|
255
|
+
const trailingWhitespace = text.match(/\s+$/u)?.[0] ?? "";
|
|
256
|
+
const { ir: parsedIr, hasTables } = markdownToIRWithMeta(markdown, {
|
|
257
|
+
linkify: false,
|
|
258
|
+
autolink: false,
|
|
259
|
+
enableSpoilers: true,
|
|
260
|
+
enableHtmlUnderline: true,
|
|
261
|
+
enableTaskLists: true,
|
|
262
|
+
headingStyle: "rich",
|
|
263
|
+
blockquotePrefix: "> ",
|
|
264
|
+
tableMode: tableMode === "block" ? "code" : tableMode,
|
|
265
|
+
preserveSourceBlockSpacing: true
|
|
179
266
|
});
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
267
|
+
let ir = parsedIr;
|
|
268
|
+
if (guardedIndent && ir.text.startsWith(WHATSAPP_INDENT_GUARD)) ir = sliceMarkdownIR(ir, 1, ir.text.length);
|
|
269
|
+
if (!hasTables && trailingWhitespace) ir.text = `${ir.text.trimEnd()}${trailingWhitespace}`;
|
|
270
|
+
return {
|
|
271
|
+
ir,
|
|
272
|
+
escapedMarkers: escaped.markers
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
function splitWhatsAppIRForChunkMode(ir, limit, chunkMode) {
|
|
276
|
+
if (chunkMode !== "newline") return [ir];
|
|
277
|
+
const chunkTexts = chunkMarkdownTextWithMode(ir.text, limit, chunkMode);
|
|
278
|
+
const chunks = [];
|
|
279
|
+
let cursor = 0;
|
|
280
|
+
for (const text of chunkTexts) {
|
|
281
|
+
const start = ir.text.indexOf(text, cursor);
|
|
282
|
+
if (start < 0) return [ir];
|
|
283
|
+
const end = start + text.length;
|
|
284
|
+
chunks.push(sliceMarkdownIR(ir, start, end));
|
|
285
|
+
cursor = end;
|
|
286
|
+
}
|
|
287
|
+
return chunks;
|
|
288
|
+
}
|
|
289
|
+
function markdownToWhatsAppChunks(text, limit, tableMode = "bullets", chunkMode = "length") {
|
|
290
|
+
if (!text) return [];
|
|
291
|
+
if (!text.trim()) return chunkMarkdownTextWithMode(text, limit, chunkMode);
|
|
292
|
+
const { ir, escapedMarkers } = prepareWhatsAppMarkdown(text, tableMode);
|
|
293
|
+
const render = (chunk) => renderWhatsAppMarkdownIR(chunk, escapedMarkers);
|
|
294
|
+
const rendered = render(ir);
|
|
295
|
+
let chunks = ir.styles.length === 0 && ir.links.length === 0 ? chunkMarkdownTextWithMode(rendered, limit, chunkMode) : splitWhatsAppIRForChunkMode(ir, limit, chunkMode).flatMap((source) => renderMarkdownIRChunksWithinLimit({
|
|
296
|
+
ir: source,
|
|
297
|
+
limit,
|
|
298
|
+
renderChunk: render,
|
|
299
|
+
measureRendered: (value) => value.length
|
|
300
|
+
}).map((chunk) => chunk.rendered));
|
|
301
|
+
if (chunkMode === "newline") chunks = chunks.map((chunk) => chunk.trimEnd()).filter(Boolean);
|
|
302
|
+
return chunks;
|
|
303
|
+
}
|
|
304
|
+
function markdownToWhatsApp(text, tableMode = "bullets") {
|
|
305
|
+
return markdownToWhatsAppChunks(text, Number.POSITIVE_INFINITY, tableMode).join("");
|
|
193
306
|
}
|
|
194
307
|
//#endregion
|
|
195
|
-
export {
|
|
308
|
+
export { markdownToWhatsAppChunks as a, toWhatsappJid as c, markdownToWhatsApp as i, toWhatsappJidWithLid as l, isSelfChatMode as n, resolveEquivalentWhatsAppDirectChatJids as o, jidToE164 as r, resolveJidToE164 as s, assertWebChannel as t };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import "./targets-runtime-CKFrhoX4.js";
|
|
2
|
+
import { sanitizeAssistantVisibleText, sanitizeAssistantVisibleTextWithProfile, stripToolCallXmlTags } from "openclaw/plugin-sdk/text-chunking";
|
|
3
|
+
import { normalizeE164, resolveUserPath as resolveUserPath$1 } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
4
|
+
export { stripToolCallXmlTags as a, sanitizeAssistantVisibleTextWithProfile as i, resolveUserPath$1 as n, sanitizeAssistantVisibleText as r, normalizeE164 as t };
|