@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 {
|
|
2
|
-
import { t as WHATSAPP_CONNECTION_CONTROLLER_CAPABILITY } from "./connection-controller-runtime-context-
|
|
3
|
-
import { c as logoutWeb, f as readWebAuthExistsForDecision, r as WhatsAppAuthUnstableError } from "./auth-store-
|
|
4
|
-
import { c as resolveComparableIdentity } from "./identity-
|
|
5
|
-
import {
|
|
1
|
+
import { r as getWhatsAppChannelRuntime } from "./runtime-BLlToOi6.js";
|
|
2
|
+
import { n as WHATSAPP_CONNECTION_OWNER_PENDING_CAPABILITY, t as WHATSAPP_CONNECTION_CONTROLLER_CAPABILITY } from "./connection-controller-runtime-context-DG0tuYuw.js";
|
|
3
|
+
import { c as logoutWeb, f as readWebAuthExistsForDecision, r as WhatsAppAuthUnstableError, w as waitForCredsSaveQueueWithTimeout } from "./auth-store-DirYMTbo.js";
|
|
4
|
+
import { c as resolveComparableIdentity } from "./identity-BM4_wZeM.js";
|
|
5
|
+
import { a as waitForWaConnection, m as acquireWhatsAppGatewayConnectionOwner, o as DEFAULT_WHATSAPP_SOCKET_TIMING, r as createWaSocket, t as closeWhatsAppSocketAndWait } from "./socket-close-BoSHhQNJ.js";
|
|
6
6
|
import { n as getStatusCode, t as formatError } from "./session-errors-JuazczrA.js";
|
|
7
7
|
import { computeBackoff, info, sleepWithAbort } from "openclaw/plugin-sdk/runtime-env";
|
|
8
8
|
import { registerChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runtime-context";
|
|
@@ -18,16 +18,14 @@ const DEFAULT_RECONNECT_POLICY = {
|
|
|
18
18
|
maxAttempts: 12
|
|
19
19
|
};
|
|
20
20
|
function resolveHeartbeatSeconds(cfg, overrideSeconds) {
|
|
21
|
-
const candidate = overrideSeconds
|
|
21
|
+
const candidate = overrideSeconds;
|
|
22
22
|
if (typeof candidate === "number" && candidate > 0) return candidate;
|
|
23
23
|
return DEFAULT_HEARTBEAT_SECONDS;
|
|
24
24
|
}
|
|
25
25
|
function resolveReconnectPolicy(cfg, overrides) {
|
|
26
|
-
const reconnectOverrides = cfg.web?.reconnect ?? {};
|
|
27
26
|
const overrideConfig = overrides ?? {};
|
|
28
27
|
const merged = {
|
|
29
28
|
...DEFAULT_RECONNECT_POLICY,
|
|
30
|
-
...reconnectOverrides,
|
|
31
29
|
...overrideConfig
|
|
32
30
|
};
|
|
33
31
|
merged.initialMs = Math.max(250, merged.initialMs);
|
|
@@ -89,17 +87,28 @@ function createLiveConnection(params) {
|
|
|
89
87
|
openedAfterRecentInbound: params.openedAfterRecentInbound,
|
|
90
88
|
backgroundTasks: /* @__PURE__ */ new Set(),
|
|
91
89
|
closePromise,
|
|
92
|
-
resolveClose: resolveClosePromise
|
|
90
|
+
resolveClose: resolveClosePromise,
|
|
91
|
+
socketClosed: false
|
|
93
92
|
};
|
|
94
93
|
}
|
|
94
|
+
async function closeWebSocketBestEffort(sock) {
|
|
95
|
+
try {
|
|
96
|
+
await sock.ws?.close?.();
|
|
97
|
+
} catch {}
|
|
98
|
+
}
|
|
95
99
|
function closeWaSocket(sock) {
|
|
96
100
|
try {
|
|
97
101
|
if (typeof sock?.end === "function") {
|
|
98
|
-
sock.end(/* @__PURE__ */ new Error("OpenClaw WhatsApp socket close"));
|
|
102
|
+
Promise.resolve(sock.end(/* @__PURE__ */ new Error("OpenClaw WhatsApp socket close"))).catch(async () => await closeWebSocketBestEffort(sock));
|
|
99
103
|
return;
|
|
100
104
|
}
|
|
101
|
-
sock
|
|
102
|
-
} catch {
|
|
105
|
+
if (sock) closeWebSocketBestEffort(sock);
|
|
106
|
+
} catch {
|
|
107
|
+
if (sock) closeWebSocketBestEffort(sock);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function stoppedControllerError() {
|
|
111
|
+
return /* @__PURE__ */ new Error("WhatsApp connection controller is shutting down");
|
|
103
112
|
}
|
|
104
113
|
function closeWaSocketSoon(sock, delayMs = 500) {
|
|
105
114
|
setTimeout(() => {
|
|
@@ -229,6 +238,15 @@ var WhatsAppConnectionController = class {
|
|
|
229
238
|
this.disconnectRetryController = new AbortController();
|
|
230
239
|
this.current = null;
|
|
231
240
|
this.runtimeContextLease = null;
|
|
241
|
+
this.pendingOwnerContextLease = null;
|
|
242
|
+
this.connectionOwnerLease = null;
|
|
243
|
+
this.retainedOwnerReleaseLease = null;
|
|
244
|
+
this.connectionOwnerLeasePromise = null;
|
|
245
|
+
this.connectionSetupPromise = null;
|
|
246
|
+
this.pendingSocketCleanup = null;
|
|
247
|
+
this.shuttingDown = false;
|
|
248
|
+
this.ownerAcquireAbortController = new AbortController();
|
|
249
|
+
this.setupAbortController = new AbortController();
|
|
232
250
|
this.reconnectAttempts = 0;
|
|
233
251
|
this.lastHandledInboundAt = null;
|
|
234
252
|
this.accountId = params.accountId;
|
|
@@ -249,11 +267,17 @@ var WhatsAppConnectionController = class {
|
|
|
249
267
|
...params.socketTiming
|
|
250
268
|
};
|
|
251
269
|
this.socketRef = { current: null };
|
|
252
|
-
|
|
253
|
-
|
|
270
|
+
const abortSignal = params.abortSignal;
|
|
271
|
+
if (abortSignal) this.abortPromise = new Promise((resolve) => {
|
|
272
|
+
const stop = () => {
|
|
273
|
+
resolve("aborted");
|
|
274
|
+
this.stopDisconnectRetries();
|
|
275
|
+
this.ownerAcquireAbortController.abort(abortSignal.reason);
|
|
276
|
+
this.setupAbortController.abort(abortSignal.reason);
|
|
277
|
+
};
|
|
278
|
+
if (abortSignal.aborted) stop();
|
|
279
|
+
else abortSignal.addEventListener("abort", stop, { once: true });
|
|
254
280
|
});
|
|
255
|
-
if (params.abortSignal?.aborted) this.stopDisconnectRetries();
|
|
256
|
-
else params.abortSignal?.addEventListener("abort", () => this.stopDisconnectRetries(), { once: true });
|
|
257
281
|
}
|
|
258
282
|
getActiveListener() {
|
|
259
283
|
return this.current?.listener ?? null;
|
|
@@ -322,7 +346,23 @@ var WhatsAppConnectionController = class {
|
|
|
322
346
|
this.current.unregisterUnhandled = unregister;
|
|
323
347
|
}
|
|
324
348
|
async openConnection(params) {
|
|
349
|
+
if (this.shuttingDown) throw stoppedControllerError();
|
|
350
|
+
if (this.connectionSetupPromise) throw new Error("WhatsApp connection setup is already in progress");
|
|
351
|
+
const setupPromise = this.openConnectionOwned(params);
|
|
352
|
+
this.connectionSetupPromise = setupPromise;
|
|
353
|
+
try {
|
|
354
|
+
return await setupPromise;
|
|
355
|
+
} finally {
|
|
356
|
+
if (this.connectionSetupPromise === setupPromise) this.connectionSetupPromise = null;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
async openConnectionOwned(params) {
|
|
360
|
+
await this.ensureConnectionOwnership();
|
|
361
|
+
this.throwIfSetupStopped();
|
|
362
|
+
await this.finishPendingSocketCleanup();
|
|
363
|
+
this.throwIfSetupStopped();
|
|
325
364
|
if (this.current) await this.closeCurrentConnection();
|
|
365
|
+
this.throwIfSetupStopped();
|
|
326
366
|
let sock = null;
|
|
327
367
|
let connection = null;
|
|
328
368
|
try {
|
|
@@ -332,8 +372,9 @@ var WhatsAppConnectionController = class {
|
|
|
332
372
|
...params.getMessage ? { getMessage: params.getMessage } : {},
|
|
333
373
|
...params.cachedGroupMetadata ? { cachedGroupMetadata: params.cachedGroupMetadata } : {}
|
|
334
374
|
});
|
|
335
|
-
|
|
336
|
-
|
|
375
|
+
this.throwIfSetupStopped();
|
|
376
|
+
await this.waitForSetupStep(waitForWaConnection(sock, { timeoutMs: this.socketTiming.connectTimeoutMs }));
|
|
377
|
+
this.throwIfSetupStopped();
|
|
337
378
|
this.socketRef.current = sock;
|
|
338
379
|
connection = createLiveConnection({
|
|
339
380
|
connectionId: params.connectionId,
|
|
@@ -341,16 +382,24 @@ var WhatsAppConnectionController = class {
|
|
|
341
382
|
listener: {},
|
|
342
383
|
openedAfterRecentInbound: this.isOpeningAfterRecentInbound()
|
|
343
384
|
});
|
|
344
|
-
const
|
|
385
|
+
const listenerTask = params.createListener({
|
|
345
386
|
sock,
|
|
346
387
|
connection
|
|
347
388
|
});
|
|
389
|
+
let listener;
|
|
390
|
+
try {
|
|
391
|
+
listener = await this.waitForSetupStep(listenerTask);
|
|
392
|
+
} catch (error) {
|
|
393
|
+
if (this.setupAbortController.signal.aborted) listenerTask.then((lateListener) => lateListener.close?.()).catch(() => {});
|
|
394
|
+
throw error;
|
|
395
|
+
}
|
|
348
396
|
connection.listener = listener;
|
|
397
|
+
this.throwIfSetupStopped();
|
|
349
398
|
this.current = connection;
|
|
350
399
|
connection.unregisterTransportActivity = this.attachTransportActivityListener(sock);
|
|
351
400
|
const previousRuntimeContextLease = this.runtimeContextLease;
|
|
352
401
|
this.runtimeContextLease = registerChannelRuntimeContext({
|
|
353
|
-
channelRuntime,
|
|
402
|
+
channelRuntime: getWhatsAppChannelRuntime(),
|
|
354
403
|
channelId: "whatsapp",
|
|
355
404
|
accountId: this.accountId,
|
|
356
405
|
capability: WHATSAPP_CONNECTION_CONTROLLER_CAPABILITY,
|
|
@@ -358,16 +407,38 @@ var WhatsAppConnectionController = class {
|
|
|
358
407
|
abortSignal: this.abortSignal
|
|
359
408
|
});
|
|
360
409
|
previousRuntimeContextLease?.dispose();
|
|
410
|
+
this.pendingOwnerContextLease?.dispose();
|
|
411
|
+
this.pendingOwnerContextLease = null;
|
|
361
412
|
this.startTimers(connection, {
|
|
362
413
|
onHeartbeat: params.onHeartbeat,
|
|
363
414
|
onWatchdogTimeout: params.onWatchdogTimeout
|
|
364
415
|
});
|
|
365
416
|
return connection;
|
|
366
417
|
} catch (err) {
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
418
|
+
try {
|
|
419
|
+
if (connection && this.current === connection) await this.closeCurrentConnection();
|
|
420
|
+
else {
|
|
421
|
+
try {
|
|
422
|
+
await connection?.listener.close?.();
|
|
423
|
+
} catch {}
|
|
424
|
+
if (this.socketRef.current === sock) this.socketRef.current = null;
|
|
425
|
+
if (sock) {
|
|
426
|
+
const cleanup = connection ?? {
|
|
427
|
+
sock,
|
|
428
|
+
socketClosed: false
|
|
429
|
+
};
|
|
430
|
+
await this.finishSocketCleanup(cleanup);
|
|
431
|
+
}
|
|
432
|
+
if (connection?.unregisterUnhandled) connection.unregisterUnhandled();
|
|
433
|
+
connection?.unregisterTransportActivity?.();
|
|
434
|
+
}
|
|
435
|
+
} catch (closeError) {
|
|
436
|
+
if (sock && (!connection || this.current !== connection)) this.pendingSocketCleanup = connection ?? {
|
|
437
|
+
sock,
|
|
438
|
+
socketClosed: false
|
|
439
|
+
};
|
|
440
|
+
throw new AggregateError([err, closeError], "WhatsApp connection setup and close failed", { cause: err });
|
|
441
|
+
}
|
|
371
442
|
throw err;
|
|
372
443
|
}
|
|
373
444
|
}
|
|
@@ -460,6 +531,7 @@ var WhatsAppConnectionController = class {
|
|
|
460
531
|
const connection = this.current;
|
|
461
532
|
if (!connection) return;
|
|
462
533
|
this.current = null;
|
|
534
|
+
this.pendingSocketCleanup = connection;
|
|
463
535
|
if (this.socketRef.current === connection.sock) this.socketRef.current = null;
|
|
464
536
|
connection.unregisterUnhandled?.();
|
|
465
537
|
connection.unregisterTransportActivity?.();
|
|
@@ -472,16 +544,103 @@ var WhatsAppConnectionController = class {
|
|
|
472
544
|
try {
|
|
473
545
|
await connection.listener.close?.();
|
|
474
546
|
} catch {}
|
|
475
|
-
|
|
547
|
+
await this.finishSocketCleanup(connection);
|
|
548
|
+
if (this.pendingSocketCleanup === connection) this.pendingSocketCleanup = null;
|
|
476
549
|
}
|
|
477
550
|
async waitBeforeRetry(delayMs) {
|
|
478
551
|
await this.sleep(delayMs, this.abortSignal);
|
|
479
552
|
}
|
|
480
553
|
async shutdown() {
|
|
554
|
+
this.shuttingDown = true;
|
|
555
|
+
const stoppedError = stoppedControllerError();
|
|
556
|
+
this.ownerAcquireAbortController.abort(stoppedError);
|
|
557
|
+
this.setupAbortController.abort(stoppedError);
|
|
481
558
|
this.stopDisconnectRetries();
|
|
559
|
+
await this.connectionSetupPromise?.catch(() => {});
|
|
560
|
+
await this.connectionOwnerLeasePromise?.catch(() => {});
|
|
482
561
|
await this.closeCurrentConnection();
|
|
483
|
-
this.
|
|
484
|
-
|
|
562
|
+
await this.finishPendingSocketCleanup();
|
|
563
|
+
try {
|
|
564
|
+
this.runtimeContextLease?.dispose();
|
|
565
|
+
} finally {
|
|
566
|
+
this.runtimeContextLease = null;
|
|
567
|
+
try {
|
|
568
|
+
this.pendingOwnerContextLease?.dispose();
|
|
569
|
+
} finally {
|
|
570
|
+
this.pendingOwnerContextLease = null;
|
|
571
|
+
if (this.connectionOwnerLease) {
|
|
572
|
+
await this.connectionOwnerLease.release();
|
|
573
|
+
this.connectionOwnerLease = null;
|
|
574
|
+
}
|
|
575
|
+
if (this.retainedOwnerReleaseLease) {
|
|
576
|
+
await this.retainedOwnerReleaseLease.release();
|
|
577
|
+
this.retainedOwnerReleaseLease = null;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
async finishSocketCleanup(cleanup) {
|
|
583
|
+
if (!cleanup.socketClosed) {
|
|
584
|
+
await closeWhatsAppSocketAndWait(cleanup.sock, "OpenClaw WhatsApp socket close");
|
|
585
|
+
cleanup.socketClosed = true;
|
|
586
|
+
}
|
|
587
|
+
if (await waitForCredsSaveQueueWithTimeout(this.authDir) === "timed_out") throw new Error("WhatsApp credential persistence did not drain before owner release");
|
|
588
|
+
}
|
|
589
|
+
async finishPendingSocketCleanup() {
|
|
590
|
+
const cleanup = this.pendingSocketCleanup;
|
|
591
|
+
if (!cleanup) return;
|
|
592
|
+
await this.finishSocketCleanup(cleanup);
|
|
593
|
+
if (this.pendingSocketCleanup === cleanup) this.pendingSocketCleanup = null;
|
|
594
|
+
}
|
|
595
|
+
throwIfSetupStopped() {
|
|
596
|
+
if (this.shuttingDown || this.setupAbortController.signal.aborted) throw stoppedControllerError();
|
|
597
|
+
}
|
|
598
|
+
async waitForSetupStep(task) {
|
|
599
|
+
this.throwIfSetupStopped();
|
|
600
|
+
const signal = this.setupAbortController.signal;
|
|
601
|
+
let onAbort;
|
|
602
|
+
const aborted = new Promise((_resolve, reject) => {
|
|
603
|
+
onAbort = () => reject(stoppedControllerError());
|
|
604
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
605
|
+
});
|
|
606
|
+
try {
|
|
607
|
+
return await Promise.race([task, aborted]);
|
|
608
|
+
} finally {
|
|
609
|
+
if (onAbort) signal.removeEventListener("abort", onAbort);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
async ensureConnectionOwnership() {
|
|
613
|
+
if (this.retainedOwnerReleaseLease) {
|
|
614
|
+
await this.retainedOwnerReleaseLease.release();
|
|
615
|
+
this.retainedOwnerReleaseLease = null;
|
|
616
|
+
}
|
|
617
|
+
if (this.connectionOwnerLease) return;
|
|
618
|
+
if (!this.connectionOwnerLeasePromise) this.connectionOwnerLeasePromise = (async () => {
|
|
619
|
+
const ownerLease = await acquireWhatsAppGatewayConnectionOwner(this.authDir, this.ownerAcquireAbortController.signal);
|
|
620
|
+
try {
|
|
621
|
+
if (this.shuttingDown) throw stoppedControllerError();
|
|
622
|
+
this.pendingOwnerContextLease = registerChannelRuntimeContext({
|
|
623
|
+
channelRuntime: getWhatsAppChannelRuntime(),
|
|
624
|
+
channelId: "whatsapp",
|
|
625
|
+
accountId: this.accountId,
|
|
626
|
+
capability: WHATSAPP_CONNECTION_OWNER_PENDING_CAPABILITY,
|
|
627
|
+
context: true,
|
|
628
|
+
abortSignal: this.abortSignal
|
|
629
|
+
});
|
|
630
|
+
this.connectionOwnerLease = ownerLease;
|
|
631
|
+
} catch (error) {
|
|
632
|
+
try {
|
|
633
|
+
await ownerLease.release();
|
|
634
|
+
} catch (releaseError) {
|
|
635
|
+
this.retainedOwnerReleaseLease = ownerLease;
|
|
636
|
+
throw new AggregateError([error, releaseError], "WhatsApp connection ownership setup and release failed", { cause: error });
|
|
637
|
+
}
|
|
638
|
+
throw error;
|
|
639
|
+
}
|
|
640
|
+
})().finally(() => {
|
|
641
|
+
this.connectionOwnerLeasePromise = null;
|
|
642
|
+
});
|
|
643
|
+
await this.connectionOwnerLeasePromise;
|
|
485
644
|
}
|
|
486
645
|
startTimers(connection, hooks) {
|
|
487
646
|
if (!this.keepAlive) return;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { t as getOptionalWhatsAppChannelRuntime } from "./runtime-BLlToOi6.js";
|
|
2
|
+
import { getChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runtime-context";
|
|
3
|
+
//#region extensions/whatsapp/src/connection-controller-runtime-context.ts
|
|
4
|
+
const WHATSAPP_CONNECTION_CONTROLLER_CAPABILITY = "connection-controller";
|
|
5
|
+
const WHATSAPP_CONNECTION_OWNER_PENDING_CAPABILITY = "connection-owner-pending";
|
|
6
|
+
function getWhatsAppConnectionController(accountId) {
|
|
7
|
+
return getChannelRuntimeContext({
|
|
8
|
+
channelRuntime: getOptionalWhatsAppChannelRuntime() ?? void 0,
|
|
9
|
+
channelId: "whatsapp",
|
|
10
|
+
accountId,
|
|
11
|
+
capability: "connection-controller"
|
|
12
|
+
}) ?? null;
|
|
13
|
+
}
|
|
14
|
+
function hasPendingWhatsAppConnectionOwner(accountId) {
|
|
15
|
+
return Boolean(getChannelRuntimeContext({
|
|
16
|
+
channelRuntime: getOptionalWhatsAppChannelRuntime() ?? void 0,
|
|
17
|
+
channelId: "whatsapp",
|
|
18
|
+
accountId,
|
|
19
|
+
capability: WHATSAPP_CONNECTION_OWNER_PENDING_CAPABILITY
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { hasPendingWhatsAppConnectionOwner as i, WHATSAPP_CONNECTION_OWNER_PENDING_CAPABILITY as n, getWhatsAppConnectionController as r, WHATSAPP_CONNECTION_CONTROLLER_CAPABILITY as t };
|
package/dist/contract-api.js
CHANGED
|
@@ -2,7 +2,7 @@ import { c as normalizeWhatsAppTarget$1, t as isWhatsAppGroupJid$1 } from "./nor
|
|
|
2
2
|
import { t as whatsappCommandPolicy$1 } from "./command-policy-BIOSHySD.js";
|
|
3
3
|
import { t as resolveLegacyGroupSessionKey$1 } from "./group-session-contract-DDnZSsJ1.js";
|
|
4
4
|
import { r as isLegacyGroupSessionKey$1, t as canonicalizeLegacySessionKey$1 } from "./session-contract-DMTm6Q_L.js";
|
|
5
|
-
import { a as resolveWhatsAppRuntimeGroupPolicy$1, n as testing } from "./access-control-
|
|
5
|
+
import { a as resolveWhatsAppRuntimeGroupPolicy$1, n as testing } from "./access-control-CRz_v6bR.js";
|
|
6
6
|
//#region extensions/whatsapp/contract-api.ts
|
|
7
7
|
const canonicalizeLegacySessionKey = canonicalizeLegacySessionKey$1;
|
|
8
8
|
const isLegacyGroupSessionKey = isLegacyGroupSessionKey$1;
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
+
import { c as resolveMergedWhatsAppAccountConfig, o as resolveWhatsAppAuthDir } from "./accounts-CxPuEFi-.js";
|
|
3
|
+
import { c as normalizeWhatsAppTarget, t as isWhatsAppGroupJid } from "./normalize-target-DSZnHkKF.js";
|
|
4
|
+
import { i as hasPendingWhatsAppConnectionOwner, r as getWhatsAppConnectionController } from "./connection-controller-runtime-context-DG0tuYuw.js";
|
|
5
|
+
import "./normalize-C-Z16y7Q.js";
|
|
6
|
+
import { f as readWebAuthExistsForDecision, w as waitForCredsSaveQueueWithTimeout } from "./auth-store-DirYMTbo.js";
|
|
7
|
+
import { n as resolveWebAccountId } from "./active-listener-BEjWsCNM.js";
|
|
8
|
+
import { a as waitForWaConnection, h as acquireWhatsAppStandaloneConnectionOwner, n as createWaDirectorySocket, p as WhatsAppConnectionOwnerBusyError, t as closeWhatsAppSocketAndWait } from "./socket-close-BoSHhQNJ.js";
|
|
9
|
+
import { listResolvedDirectoryGroupEntriesFromMapKeys, listResolvedDirectoryUserEntriesFromAllowFrom } from "openclaw/plugin-sdk/directory-config-runtime";
|
|
10
|
+
//#region extensions/whatsapp/src/directory-config.ts
|
|
11
|
+
var directory_config_exports = /* @__PURE__ */ __exportAll({
|
|
12
|
+
WHATSAPP_DIRECTORY_UNAVAILABLE_CODE: () => WHATSAPP_DIRECTORY_UNAVAILABLE_CODE,
|
|
13
|
+
WhatsAppDirectoryUnavailableError: () => WhatsAppDirectoryUnavailableError,
|
|
14
|
+
listWhatsAppDirectoryGroupsFromConfig: () => listWhatsAppDirectoryGroupsFromConfig,
|
|
15
|
+
listWhatsAppDirectoryGroupsLive: () => listWhatsAppDirectoryGroupsLive,
|
|
16
|
+
listWhatsAppDirectoryPeersFromConfig: () => listWhatsAppDirectoryPeersFromConfig
|
|
17
|
+
});
|
|
18
|
+
function resolveWhatsAppDirectoryAccount(cfg, accountId) {
|
|
19
|
+
return resolveMergedWhatsAppAccountConfig({
|
|
20
|
+
cfg,
|
|
21
|
+
accountId
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
async function listWhatsAppDirectoryPeersFromConfig(params) {
|
|
25
|
+
return listResolvedDirectoryUserEntriesFromAllowFrom({
|
|
26
|
+
...params,
|
|
27
|
+
resolveAccount: resolveWhatsAppDirectoryAccount,
|
|
28
|
+
resolveAllowFrom: (account) => account.allowFrom,
|
|
29
|
+
normalizeId: (entry) => {
|
|
30
|
+
const normalized = normalizeWhatsAppTarget(entry);
|
|
31
|
+
if (!normalized || isWhatsAppGroupJid(normalized)) return null;
|
|
32
|
+
return normalized;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
async function listWhatsAppDirectoryGroupsFromConfig(params) {
|
|
37
|
+
return listResolvedDirectoryGroupEntriesFromMapKeys({
|
|
38
|
+
...params,
|
|
39
|
+
resolveAccount: resolveWhatsAppDirectoryAccount,
|
|
40
|
+
resolveGroups: (account) => account.groups
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
const WHATSAPP_DIRECTORY_UNAVAILABLE_CODE = "whatsapp_directory_unavailable";
|
|
44
|
+
var WhatsAppDirectoryUnavailableError = class extends Error {
|
|
45
|
+
constructor(reason, message, options) {
|
|
46
|
+
super(message, options);
|
|
47
|
+
this.reason = reason;
|
|
48
|
+
this.code = WHATSAPP_DIRECTORY_UNAVAILABLE_CODE;
|
|
49
|
+
this.name = "WhatsAppDirectoryUnavailableError";
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
async function fetchLiveGroups(sock, params) {
|
|
53
|
+
const groups = await sock.groupFetchAllParticipating();
|
|
54
|
+
const query = params.query?.trim().toLowerCase() ?? "";
|
|
55
|
+
const limit = typeof params.limit === "number" && params.limit > 0 ? params.limit : void 0;
|
|
56
|
+
const entries = Object.entries(groups).map(([jid, metadata]) => ({
|
|
57
|
+
kind: "group",
|
|
58
|
+
id: jid,
|
|
59
|
+
name: metadata?.subject?.trim() || void 0
|
|
60
|
+
})).filter((entry) => {
|
|
61
|
+
if (!query) return true;
|
|
62
|
+
return entry.id.toLowerCase().includes(query) || entry.name?.toLowerCase().includes(query);
|
|
63
|
+
}).toSorted((left, right) => left.id.localeCompare(right.id));
|
|
64
|
+
return limit ? entries.slice(0, limit) : entries;
|
|
65
|
+
}
|
|
66
|
+
function unavailable(reason, message, cause) {
|
|
67
|
+
return new WhatsAppDirectoryUnavailableError(reason, message, cause ? { cause } : void 0);
|
|
68
|
+
}
|
|
69
|
+
const pendingStandaloneCleanups = /* @__PURE__ */ new Map();
|
|
70
|
+
const STANDALONE_CLEANUP_RETRY_MS = 1e3;
|
|
71
|
+
async function completeStandaloneCleanup(cleanup) {
|
|
72
|
+
if (cleanup.sock && !cleanup.socketClosed) {
|
|
73
|
+
await closeWhatsAppSocketAndWait(cleanup.sock, "OpenClaw WhatsApp standalone directory socket close");
|
|
74
|
+
cleanup.socketClosed = true;
|
|
75
|
+
}
|
|
76
|
+
if (cleanup.sock) {
|
|
77
|
+
if (await waitForCredsSaveQueueWithTimeout(cleanup.authDir) === "timed_out") throw new Error("WhatsApp credential persistence did not drain before socket release");
|
|
78
|
+
}
|
|
79
|
+
await cleanup.ownerLease.release();
|
|
80
|
+
if (pendingStandaloneCleanups.get(cleanup.authDir) === cleanup) pendingStandaloneCleanups.delete(cleanup.authDir);
|
|
81
|
+
if (cleanup.retryTimer) {
|
|
82
|
+
clearTimeout(cleanup.retryTimer);
|
|
83
|
+
cleanup.retryTimer = null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function runStandaloneCleanup(cleanup) {
|
|
87
|
+
if (cleanup.inFlight) return cleanup.inFlight;
|
|
88
|
+
const task = completeStandaloneCleanup(cleanup).finally(() => {
|
|
89
|
+
if (cleanup.inFlight === task) cleanup.inFlight = null;
|
|
90
|
+
});
|
|
91
|
+
cleanup.inFlight = task;
|
|
92
|
+
return task;
|
|
93
|
+
}
|
|
94
|
+
function scheduleStandaloneCleanupRetry(cleanup) {
|
|
95
|
+
if (cleanup.retryTimer) return;
|
|
96
|
+
cleanup.retryTimer = setTimeout(() => {
|
|
97
|
+
cleanup.retryTimer = null;
|
|
98
|
+
runStandaloneCleanup(cleanup).catch(() => {
|
|
99
|
+
scheduleStandaloneCleanupRetry(cleanup);
|
|
100
|
+
});
|
|
101
|
+
}, STANDALONE_CLEANUP_RETRY_MS);
|
|
102
|
+
cleanup.retryTimer.unref?.();
|
|
103
|
+
}
|
|
104
|
+
function retainStandaloneCleanup(cleanup) {
|
|
105
|
+
pendingStandaloneCleanups.set(cleanup.authDir, cleanup);
|
|
106
|
+
scheduleStandaloneCleanupRetry(cleanup);
|
|
107
|
+
}
|
|
108
|
+
async function finishStandaloneCleanupOrThrow(cleanup, operationError) {
|
|
109
|
+
try {
|
|
110
|
+
await runStandaloneCleanup(cleanup);
|
|
111
|
+
} catch (cleanupError) {
|
|
112
|
+
retainStandaloneCleanup(cleanup);
|
|
113
|
+
throw cleanupUnavailable(operationError === void 0 ? cleanupError : new AggregateError([operationError, cleanupError], "WhatsApp live group lookup and cleanup failed", { cause: operationError }));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function cleanupUnavailable(error) {
|
|
117
|
+
return unavailable("cleanup_failed", "WhatsApp live group lookup could not safely close its standalone connection.", error);
|
|
118
|
+
}
|
|
119
|
+
async function finishPriorStandaloneCleanup(authDir) {
|
|
120
|
+
const cleanup = pendingStandaloneCleanups.get(authDir);
|
|
121
|
+
if (!cleanup) return;
|
|
122
|
+
try {
|
|
123
|
+
await runStandaloneCleanup(cleanup);
|
|
124
|
+
} catch (error) {
|
|
125
|
+
scheduleStandaloneCleanupRetry(cleanup);
|
|
126
|
+
throw cleanupUnavailable(error);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
async function listGroupsThroughStandaloneOwner(params) {
|
|
130
|
+
const account = resolveWhatsAppDirectoryAccount(params.cfg, params.accountId);
|
|
131
|
+
const authDir = resolveWhatsAppAuthDir({
|
|
132
|
+
cfg: params.cfg,
|
|
133
|
+
accountId: account.accountId
|
|
134
|
+
}).authDir;
|
|
135
|
+
await finishPriorStandaloneCleanup(authDir);
|
|
136
|
+
let ownerLease;
|
|
137
|
+
try {
|
|
138
|
+
ownerLease = await acquireWhatsAppStandaloneConnectionOwner(authDir);
|
|
139
|
+
} catch (error) {
|
|
140
|
+
if (error instanceof WhatsAppConnectionOwnerBusyError) throw unavailable("connection_owner_busy", "WhatsApp live groups are unavailable because the account is owned by another process.", error);
|
|
141
|
+
throw unavailable("connection_failed", "WhatsApp live groups are unavailable because connection ownership failed.", error);
|
|
142
|
+
}
|
|
143
|
+
const cleanup = {
|
|
144
|
+
authDir,
|
|
145
|
+
inFlight: null,
|
|
146
|
+
ownerLease,
|
|
147
|
+
retryTimer: null,
|
|
148
|
+
sock: null,
|
|
149
|
+
socketClosed: true
|
|
150
|
+
};
|
|
151
|
+
let groups;
|
|
152
|
+
try {
|
|
153
|
+
let authState;
|
|
154
|
+
try {
|
|
155
|
+
authState = await readWebAuthExistsForDecision(authDir);
|
|
156
|
+
} catch (error) {
|
|
157
|
+
throw unavailable("auth_unstable", "WhatsApp live groups are unavailable because linked credentials could not be read.", error);
|
|
158
|
+
}
|
|
159
|
+
if (authState.outcome === "unstable") throw unavailable("auth_unstable", "WhatsApp live groups are unavailable while linked credentials are changing.");
|
|
160
|
+
if (!authState.exists) throw unavailable("not_linked", "WhatsApp live groups are unavailable because this account is not linked.");
|
|
161
|
+
try {
|
|
162
|
+
cleanup.sock = await createWaDirectorySocket(authDir);
|
|
163
|
+
cleanup.socketClosed = false;
|
|
164
|
+
await waitForWaConnection(cleanup.sock, { timeoutMs: 3e4 });
|
|
165
|
+
} catch (error) {
|
|
166
|
+
throw unavailable("connection_failed", "WhatsApp live groups are unavailable because the standalone connection failed.", error);
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
groups = await fetchLiveGroups(cleanup.sock, params);
|
|
170
|
+
} catch (error) {
|
|
171
|
+
throw unavailable("lookup_failed", "WhatsApp live group lookup failed.", error);
|
|
172
|
+
}
|
|
173
|
+
} catch (error) {
|
|
174
|
+
await finishStandaloneCleanupOrThrow(cleanup, error);
|
|
175
|
+
throw error;
|
|
176
|
+
}
|
|
177
|
+
await finishStandaloneCleanupOrThrow(cleanup);
|
|
178
|
+
return groups;
|
|
179
|
+
}
|
|
180
|
+
async function listWhatsAppDirectoryGroupsLive(params) {
|
|
181
|
+
const accountId = resolveWebAccountId({
|
|
182
|
+
cfg: params.cfg,
|
|
183
|
+
accountId: params.accountId
|
|
184
|
+
});
|
|
185
|
+
const controller = getWhatsAppConnectionController(accountId);
|
|
186
|
+
if (!controller && !hasPendingWhatsAppConnectionOwner(accountId)) return await listGroupsThroughStandaloneOwner(params);
|
|
187
|
+
const sock = controller?.getCurrentSock();
|
|
188
|
+
if (!sock) throw unavailable("active_owner_unavailable", "WhatsApp live groups are unavailable while the gateway connection is offline.");
|
|
189
|
+
try {
|
|
190
|
+
return await fetchLiveGroups(sock, params);
|
|
191
|
+
} catch (error) {
|
|
192
|
+
throw unavailable("lookup_failed", "WhatsApp live group lookup failed.", error);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
//#endregion
|
|
196
|
+
export { listWhatsAppDirectoryGroupsFromConfig as n, listWhatsAppDirectoryPeersFromConfig as r, directory_config_exports as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as listWhatsAppDirectoryGroupsFromConfig, r as listWhatsAppDirectoryPeersFromConfig } from "./directory-config-
|
|
1
|
+
import { n as listWhatsAppDirectoryGroupsFromConfig, r as listWhatsAppDirectoryPeersFromConfig } from "./directory-config-BTbJkV1W.js";
|
|
2
2
|
//#region extensions/whatsapp/directory-contract-api.ts
|
|
3
3
|
const whatsappDirectoryContractPlugin = {
|
|
4
4
|
id: "whatsapp",
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region extensions/whatsapp/src/doctor.ts
|
|
2
|
+
function normalizeCompatibilityConfig({ cfg }) {
|
|
3
|
+
return {
|
|
4
|
+
config: cfg,
|
|
5
|
+
changes: []
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
const whatsappDoctor = { normalizeCompatibilityConfig };
|
|
9
|
+
//#endregion
|
|
10
|
+
export { whatsappDoctor as n, normalizeCompatibilityConfig as t };
|