@openclaw/whatsapp 2026.7.1 → 2026.7.2-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/{access-control-DYE5dXna.js → access-control-DazDX3RB.js} +4 -4
  2. package/dist/{account-config-6PTOSfaI.js → account-config-LiT9wWH9.js} +4 -8
  3. package/dist/{accounts-4YgwroRU.js → accounts-CKOFMPf-.js} +2 -3
  4. package/dist/{action-runtime-DPahAqxV.js → action-runtime-Bf-12TIH.js} +3 -3
  5. package/dist/action-runtime-api.js +1 -1
  6. package/dist/action-runtime.runtime.js +1 -1
  7. package/dist/{active-listener-B4SDebQ6.js → active-listener-5kHap439.js} +2 -2
  8. package/dist/{agent-tools-login-BX7eHgDm.js → agent-tools-login-DfyToBpG.js} +1 -4
  9. package/dist/api.js +17 -18
  10. package/dist/{approval-handler.runtime-DNWS4aYQ.js → approval-handler.runtime-CBiGQuZ5.js} +19 -13
  11. package/dist/approval-reactions-BGQoz25s.js +373 -0
  12. package/dist/{approval-resolver-DF-lu8k5.js → approval-resolver-DoeBBt22.js} +2 -1
  13. package/dist/{auth-store-Db-wfApd.js → auth-store-BQi9pZqQ.js} +31 -19
  14. package/dist/call-tool-api.js +6 -14
  15. package/dist/{channel-BWp7h1uY.js → channel-DbadDUDD.js} +84 -52
  16. package/dist/channel-config-api.js +1 -1
  17. package/dist/channel-plugin-api.js +1 -1
  18. package/dist/{channel-react-action-CKJHL_Wf.js → channel-react-action-PoRWfP9x.js} +7 -7
  19. package/dist/{channel.runtime-CAssfx9p.js → channel.runtime-BDDy4Lhz.js} +5 -5
  20. package/dist/{channel.setup-CURc5rEt.js → channel.setup-BZ-po8fg.js} +4 -5
  21. package/dist/config-schema-BZ8h1hWA.js +40 -0
  22. package/dist/{connection-controller-DkbrFSIn.js → connection-controller-C1rwfWb4.js} +52 -12
  23. package/dist/connection-controller-runtime-context-CbTsqmPT.js +14 -0
  24. package/dist/contract-api.js +2 -2
  25. package/dist/{directory-config-Dijefxc3.js → directory-config-CLBQrjtC.js} +3 -3
  26. package/dist/directory-contract-api.js +1 -1
  27. package/dist/doctor-contract-api.js +89 -4
  28. package/dist/{group-session-key-BhC1RQOE.js → group-session-key-CLTZeH_F.js} +31 -3
  29. package/dist/{identity-Dqft3mFA.js → identity-D7L8LCuH.js} +2 -2
  30. package/dist/legacy-state-migrations-api.js +1 -1
  31. package/dist/light-runtime-api.js +4 -4
  32. package/dist/{login-C48y0jlx.js → login-DGIoToX8.js} +48 -8
  33. package/dist/{login-qr-BjId7dll.js → login-qr-X-CZHOk9.js} +6 -7
  34. package/dist/login-qr-runtime.js +1 -1
  35. package/dist/{monitor-DD8bXohk.js → monitor-BZ8QvCeV.js} +145 -188
  36. package/dist/normalize-C-Z16y7Q.js +2 -0
  37. package/dist/{normalize-target-bVWjgftN.js → normalize-target-DSZnHkKF.js} +14 -10
  38. package/dist/{resolve-outbound-target-CcdugbDf.js → resolve-outbound-target-BR97fAbB.js} +1 -1
  39. package/dist/runtime-api.js +10 -10
  40. package/dist/{send-C5CpFcBG.js → send-D9Ydnn4o.js} +25 -320
  41. package/dist/{send-api-DLlXl8CH.js → send-api-W33lI2nR.js} +28 -88
  42. package/dist/{session-errors-BAj9D2La.js → session-errors-JuazczrA.js} +2 -1
  43. package/dist/{session-DriaHt7V.js → session-mxWFn0eS.js} +181 -19
  44. package/dist/session.runtime-Nsqaehbd.js +16 -0
  45. package/dist/{setup-core-DH-DFPLY.js → setup-core-3aSOoK2T.js} +18 -33
  46. package/dist/{setup-finalize-c8dl34sO.js → setup-finalize-DBf1jjBj.js} +41 -11
  47. package/dist/setup-plugin-api.js +1 -1
  48. package/dist/{setup-surface-DlWb0Z09.js → setup-surface-CiKGdNJv.js} +3 -3
  49. package/dist/{state-migrations-D_BmQUR9.js → state-migrations-CAMTrs2U.js} +1 -8
  50. package/dist/{targets-runtime-C-GiVn6Y.js → targets-runtime-Bsh0HR9y.js} +13 -6
  51. package/dist/text-runtime-BTGkMN0o.js +4 -0
  52. package/npm-shrinkwrap.json +3 -3
  53. package/openclaw.plugin.json +72 -48
  54. package/package.json +4 -4
  55. package/dist/config-schema-mBX2nmn1.js +0 -47
  56. package/dist/connection-controller-registry-TSX_udJp.js +0 -22
  57. package/dist/constants.js +0 -2
  58. package/dist/normalize-Bxwqo-bW.js +0 -2
  59. package/dist/session.runtime-CyooSQvj.js +0 -12
  60. package/dist/socket-timing-DhbVFjah.js +0 -77
  61. package/dist/targets.js +0 -2
  62. package/dist/text-runtime-DdX6-mC_.js +0 -4
@@ -1,22 +1,22 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
2
  import { a as readWebCredsJsonRawSync, c as statWebCredsFileSync, i as readWebCredsJsonRaw, o as resolveWebCredsBackupPath, s as resolveWebCredsPath, t as assertWebCredsPathRegularFileOrMissing } from "./creds-files-B1kSWtBg.js";
3
- import { r as resolveUserPath } from "./text-runtime-DdX6-mC_.js";
4
- import { c as resolveComparableIdentity } from "./identity-Dqft3mFA.js";
3
+ import { r as resolveUserPath } from "./text-runtime-BTGkMN0o.js";
4
+ import { c as resolveComparableIdentity } from "./identity-D7L8LCuH.js";
5
5
  import path from "node:path";
6
6
  import { resolveOAuthDir as resolveOAuthDir$1 } from "openclaw/plugin-sdk/state-paths";
7
7
  import { replaceFileAtomic } from "openclaw/plugin-sdk/security-runtime";
8
8
  import { formatCliCommand } from "openclaw/plugin-sdk/cli-runtime";
9
9
  import { defaultRuntime, getChildLogger, info, success } from "openclaw/plugin-sdk/runtime-env";
10
- import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
11
10
  import fs from "node:fs/promises";
12
11
  import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/routing";
13
12
  import { enqueueKeyedTask } from "openclaw/plugin-sdk/keyed-async-queue";
13
+ import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
14
14
  //#region extensions/whatsapp/src/creds-persistence.ts
15
15
  const CREDS_FILE_MODE = 384;
16
16
  const CREDS_SAVE_FLUSH_TIMEOUT_MS = 15e3;
17
17
  const credsSaveQueues = /* @__PURE__ */ new Map();
18
18
  async function stringifyCreds(creds) {
19
- const { BufferJSON } = await import("./session.runtime-CyooSQvj.js").then((n) => n.a);
19
+ const { BufferJSON } = await import("./session.runtime-Nsqaehbd.js").then((n) => n.o);
20
20
  return JSON.stringify(creds, BufferJSON.replacer);
21
21
  }
22
22
  async function writeWebCredsRawAtomically(params) {
@@ -130,8 +130,9 @@ function isValidJson(raw) {
130
130
  return false;
131
131
  }
132
132
  }
133
- async function restoreCredsFromBackupIfNeeded(authDir) {
133
+ async function restoreCredsFromBackupIfNeeded(authDir, options) {
134
134
  const logger = getChildLogger({ module: "web-session" });
135
+ let restore;
135
136
  try {
136
137
  const credsPath = resolveWebCredsPath(authDir);
137
138
  const backupPath = resolveWebCredsBackupPath(authDir);
@@ -144,12 +145,21 @@ async function restoreCredsFromBackupIfNeeded(authDir) {
144
145
  if (raw && isValidJson(raw)) return false;
145
146
  const backupRaw = readCredsJsonRaw(backupPath);
146
147
  if (!backupRaw || !isValidJson(backupRaw)) return false;
147
- await writeWebCredsRawAtomically({
148
- filePath: credsPath,
148
+ restore = {
149
149
  content: backupRaw,
150
+ credsPath
151
+ };
152
+ } catch {
153
+ return false;
154
+ }
155
+ await options?.beforeCredentialPersistence?.();
156
+ try {
157
+ await writeWebCredsRawAtomically({
158
+ filePath: restore.credsPath,
159
+ content: restore.content,
150
160
  tempPrefix: ".creds.restore"
151
161
  });
152
- logger.warn({ credsPath }, "restored corrupted WhatsApp creds.json from backup");
162
+ logger.warn({ credsPath: restore.credsPath }, "restored corrupted WhatsApp creds.json from backup");
153
163
  return true;
154
164
  } catch {}
155
165
  return false;
@@ -230,13 +240,13 @@ function isBaileysAuthFileName(name) {
230
240
  if (!name.endsWith(".json")) return false;
231
241
  return /^(app-state-sync|session|sender-key|pre-key)-/.test(name);
232
242
  }
233
- async function clearBaileysAuthFiles(authDir) {
243
+ async function clearBaileysAuthFiles(authDir, beforeCredentialPersistence) {
234
244
  const rootStats = await fs.lstat(authDir).catch(() => null);
235
245
  if (!rootStats?.isDirectory() || rootStats.isSymbolicLink()) return;
236
- const entries = await fs.readdir(authDir, { withFileTypes: true });
237
- await Promise.all(entries.map(async (entry) => {
238
- if (!entry.isFile()) return;
239
- if (!isBaileysAuthFileName(entry.name)) return;
246
+ const credentialFiles = (await fs.readdir(authDir, { withFileTypes: true })).filter((entry) => entry.isFile() && isBaileysAuthFileName(entry.name));
247
+ if (credentialFiles.length === 0) return;
248
+ await beforeCredentialPersistence?.();
249
+ await Promise.all(credentialFiles.map(async (entry) => {
240
250
  await fs.rm(path.join(authDir, entry.name), { force: true });
241
251
  }));
242
252
  }
@@ -302,14 +312,16 @@ async function logoutWeb(params) {
302
312
  runtime.log(info("Skipped WhatsApp Web credential cleanup outside the managed legacy auth directory."));
303
313
  return false;
304
314
  }
305
- await clearBaileysAuthFiles(resolvedAuthDir);
315
+ await clearBaileysAuthFiles(resolvedAuthDir, params.beforeCredentialPersistence);
306
316
  } else {
307
317
  const ownership = await classifyWebAuthDirOwnership(resolvedAuthDir);
308
- if (ownership.kind === "owned") await fs.rm(ownership.authDir, {
309
- recursive: true,
310
- force: true
311
- });
312
- else if (ownership.kind === "unsafe-owned") {
318
+ if (ownership.kind === "owned") {
319
+ await params.beforeCredentialPersistence?.();
320
+ await fs.rm(ownership.authDir, {
321
+ recursive: true,
322
+ force: true
323
+ });
324
+ } else if (ownership.kind === "unsafe-owned") {
313
325
  runtime.log(info("Skipped WhatsApp Web credential cleanup because the auth directory crosses a symlink boundary."));
314
326
  return false;
315
327
  } else {
@@ -1,6 +1,6 @@
1
- import { a as resolveWhatsAppAccount } from "./accounts-4YgwroRU.js";
2
- import { t as getRegisteredWhatsAppConnectionController } from "./connection-controller-registry-TSX_udJp.js";
3
- import { o as resolveJidToE164 } from "./targets-runtime-C-GiVn6Y.js";
1
+ import { a as resolveWhatsAppAccount } from "./accounts-CKOFMPf-.js";
2
+ import { n as getWhatsAppConnectionController } from "./connection-controller-runtime-context-CbTsqmPT.js";
3
+ import { o as resolveJidToE164 } from "./targets-runtime-Bsh0HR9y.js";
4
4
  import { createActionGate, stringEnum } from "openclaw/plugin-sdk/channel-actions";
5
5
  import path from "node:path";
6
6
  import { resolveOAuthDir } from "openclaw/plugin-sdk/state-paths";
@@ -11,6 +11,7 @@ import { Type } from "typebox";
11
11
  import fs from "node:fs/promises";
12
12
  import { mulawToPcm } from "openclaw/plugin-sdk/realtime-voice";
13
13
  import { detectBinary } from "openclaw/plugin-sdk/setup-tools";
14
+ import { jsonResult as jsonResult$1 } from "openclaw/plugin-sdk/tool-results";
14
15
  //#region extensions/whatsapp/src/agent-tools-call.ts
15
16
  const MEOWCALLER_COMMAND = "meowcaller";
16
17
  const SESSION_DATABASE = "wa-voip.db";
@@ -33,15 +34,6 @@ const defaultDependencies = {
33
34
  detectMeowCaller: () => detectBinary(MEOWCALLER_COMMAND),
34
35
  resolveStateDir: (accountId) => path.join(resolveOAuthDir(), "whatsapp-calls", normalizeAccountId(accountId))
35
36
  };
36
- function jsonResult$1(payload) {
37
- return {
38
- content: [{
39
- type: "text",
40
- text: JSON.stringify(payload, null, 2)
41
- }],
42
- details: payload
43
- };
44
- }
45
37
  async function isRegularFile(filePath) {
46
38
  try {
47
39
  return (await fs.stat(filePath)).isFile();
@@ -101,14 +93,14 @@ async function resolveRequesterE164(params) {
101
93
  cfg: params.cfg,
102
94
  accountId: params.accountId
103
95
  });
104
- const lidLookup = getRegisteredWhatsAppConnectionController(params.accountId)?.getCurrentSock()?.signalRepository.lidMapping;
96
+ const lidLookup = getWhatsAppConnectionController(params.accountId)?.getCurrentSock()?.signalRepository.lidMapping;
105
97
  return await resolveJidToE164(senderId, {
106
98
  authDir: account.authDir,
107
99
  lidLookup
108
100
  });
109
101
  }
110
102
  async function resolveLinkedWhatsAppSelfE164(params) {
111
- const controller = getRegisteredWhatsAppConnectionController(params.accountId);
103
+ const controller = getWhatsAppConnectionController(params.accountId);
112
104
  if (!controller) return null;
113
105
  const identity = controller.getSelfIdentity();
114
106
  if (!identity) return null;
@@ -1,36 +1,37 @@
1
1
  import { r as resolveDefaultWhatsAppAccountId, t as listAccountIds } from "./account-ids-CB5SOWjc.js";
2
- import { a as resolveWhatsAppAccount } from "./accounts-4YgwroRU.js";
3
- import { c as normalizeWhatsAppTarget, i as looksLikeWhatsAppTargetId, n as isWhatsAppNewsletterJid, o as normalizeWhatsAppAllowFromEntry, s as normalizeWhatsAppMessagingTarget, t as isWhatsAppGroupJid } from "./normalize-target-bVWjgftN.js";
4
- import { t as resolveWhatsAppOutboundTarget } from "./resolve-outbound-target-CcdugbDf.js";
5
- import { a as normalizeWhatsAppOutboundPayload, g as resolveWhatsAppReactionLevel, h as whatsappApprovalAuth, i as sendTypingWhatsApp, m as getWhatsAppApprovalApprovers, n as sendPollWhatsApp, o as normalizeWhatsAppPayloadText, s as normalizeWhatsAppPayloadTextPreservingIndentation, t as sendMessageWhatsApp } from "./send-C5CpFcBG.js";
6
- import "./normalize-Bxwqo-bW.js";
2
+ import { a as resolveWhatsAppAccount } from "./accounts-CKOFMPf-.js";
3
+ import { c as normalizeWhatsAppTarget, i as looksLikeWhatsAppTargetId, n as isWhatsAppNewsletterJid, o as normalizeWhatsAppAllowFromEntry, s as normalizeWhatsAppMessagingTarget, t as isWhatsAppGroupJid } from "./normalize-target-DSZnHkKF.js";
4
+ import { t as resolveWhatsAppOutboundTarget } from "./resolve-outbound-target-BR97fAbB.js";
5
+ import { a as normalizeWhatsAppOutboundPayload, i as sendTypingWhatsApp, n as sendPollWhatsApp, o as normalizeWhatsAppPayloadText, s as normalizeWhatsAppPayloadTextPreservingIndentation, t as sendMessageWhatsApp, u as resolveWhatsAppReactionLevel } from "./send-D9Ydnn4o.js";
7
6
  import { n as getWhatsAppRuntime } from "./runtime-BfAdAEYT.js";
8
- import { s as toWhatsappJid } from "./targets-runtime-C-GiVn6Y.js";
9
- import "./text-runtime-DdX6-mC_.js";
10
- import { t as createWhatsAppLoginTool } from "./agent-tools-login-BX7eHgDm.js";
11
- import { s as lookupInboundMessageMetaForTarget, t as resolveWhatsAppGroupSessionKey } from "./group-session-key-BhC1RQOE.js";
7
+ import "./normalize-C-Z16y7Q.js";
8
+ import { s as toWhatsappJid } from "./targets-runtime-Bsh0HR9y.js";
9
+ import "./text-runtime-BTGkMN0o.js";
10
+ import { t as createWhatsAppLoginTool } from "./agent-tools-login-DfyToBpG.js";
11
+ import { c as getWhatsAppApprovalApprovers, l as whatsappApprovalAuth, s as lookupInboundMessageMetaForTarget, t as resolveWhatsAppGroupSessionKey } from "./group-session-key-CLTZeH_F.js";
12
12
  import { t as whatsappCommandPolicy } from "./command-policy-BIOSHySD.js";
13
- import { a as resolveWhatsAppGroupRequireMention, c as resolveWhatsAppMentionStripRegexes, i as whatsappSetupWizardProxy, l as formatWhatsAppConfigAllowFromEntries, n as createWhatsAppPluginBase, o as resolveWhatsAppGroupToolPolicy, r as loadWhatsAppChannelRuntime, s as resolveWhatsAppGroupIntroHint, t as whatsappSetupAdapter } from "./setup-core-DH-DFPLY.js";
14
- import { f as readWebAuthExistsForDecision, n as WHATSAPP_AUTH_UNSTABLE_CODE } from "./auth-store-Db-wfApd.js";
15
- import { t as detectWhatsAppLegacyStateMigrations } from "./state-migrations-D_BmQUR9.js";
13
+ import { a as resolveWhatsAppGroupRequireMention, i as whatsappSetupWizardProxy, n as createWhatsAppPluginBase, o as resolveWhatsAppGroupToolPolicy, r as loadWhatsAppChannelRuntime, s as formatWhatsAppConfigAllowFromEntries, t as whatsappSetupAdapter } from "./setup-core-3aSOoK2T.js";
14
+ import { f as readWebAuthExistsForDecision, n as WHATSAPP_AUTH_UNSTABLE_CODE } from "./auth-store-BQi9pZqQ.js";
15
+ import { t as detectWhatsAppLegacyStateMigrations } from "./state-migrations-CAMTrs2U.js";
16
16
  import { createActionGate as createActionGate$1 } from "openclaw/plugin-sdk/channel-actions";
17
- import { DEFAULT_ACCOUNT_ID, listCombinedAccountIds, normalizeOptionalAccountId, resolveListedDefaultAccountId } from "openclaw/plugin-sdk/account-core";
17
+ import { normalizeOptionalAccountId } from "openclaw/plugin-sdk/account-core";
18
18
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
19
- import { createMessageReceiptFromOutboundResults, defineChannelMessageAdapter, resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-outbound";
20
- import { asString, collectIssuesForEnabledAccounts, createAsyncComputedAccountStatusAdapter, createDefaultChannelRuntimeState, isRecord as isRecord$1 } from "openclaw/plugin-sdk/status-helpers";
19
+ import { asString, collectIssuesForEnabledAccounts, createAsyncComputedAccountStatusAdapter, createDefaultChannelRuntimeState, isRecord as isRecord$1, readAccountStatusSnapshot } from "openclaw/plugin-sdk/status-helpers";
21
20
  import { formatCliCommand } from "openclaw/plugin-sdk/cli-runtime";
22
21
  import { buildChannelOutboundSessionRoute } from "openclaw/plugin-sdk/core";
23
- import { buildApprovalReactionPromptPayloadForRequest } from "openclaw/plugin-sdk/approval-reaction-runtime";
24
- import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
22
+ import { createMessageReceiptFromOutboundResults, defineChannelMessageAdapter, resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-outbound";
23
+ import { sendTextMediaPayload } from "openclaw/plugin-sdk/reply-payload";
25
24
  import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1 } from "openclaw/plugin-sdk/account-id";
26
25
  import { buildDmGroupAccountAllowlistAdapter } from "openclaw/plugin-sdk/allowlist-config-edit";
27
26
  import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
27
+ import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
28
28
  import { createChannelApprovalCapability } from "openclaw/plugin-sdk/approval-delivery-runtime";
29
29
  import { createLazyChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-adapter-runtime";
30
30
  import { createChannelApproverDmTargetResolver, createChannelNativeOriginTargetResolver, createNativeApprovalChannelRouteGates, createNativeApprovalForwardingFallbackSuppressor } from "openclaw/plugin-sdk/approval-native-runtime";
31
+ import { buildApprovalReactionPromptPayloadForRequest } from "openclaw/plugin-sdk/approval-reaction-runtime";
32
+ import { buildTypedApprovalPresentation } from "openclaw/plugin-sdk/approval-reply-runtime";
31
33
  import { chunkText } from "openclaw/plugin-sdk/reply-chunking";
32
34
  import { attachChannelToResult, createAttachedChannelResultAdapter } from "openclaw/plugin-sdk/channel-send-result";
33
- import { sendTextMediaPayload } from "openclaw/plugin-sdk/reply-payload";
34
35
  //#region extensions/whatsapp/src/approval-native.ts
35
36
  const DEFAULT_APPROVAL_FORWARDING_MODE = "session";
36
37
  function isWhatsAppApprovalTransportEnabled(params) {
@@ -122,10 +123,26 @@ const shouldSuppressWhatsAppForwardingFallback = createNativeApprovalForwardingF
122
123
  resolveApproverDmTargets: resolveWhatsAppApproverDmTargets
123
124
  });
124
125
  function buildWhatsAppExecPendingPayload(params) {
125
- return buildApprovalReactionPromptPayloadForRequest(params);
126
+ const payload = buildApprovalReactionPromptPayloadForRequest(params);
127
+ return {
128
+ ...payload,
129
+ presentation: buildTypedApprovalPresentation({
130
+ approvalId: params.request.id,
131
+ approvalKind: "exec",
132
+ allowedDecisions: payload.allowedDecisions
133
+ })
134
+ };
126
135
  }
127
136
  function buildWhatsAppPluginPendingPayload(params) {
128
- return buildApprovalReactionPromptPayloadForRequest(params);
137
+ const payload = buildApprovalReactionPromptPayloadForRequest(params);
138
+ return {
139
+ ...payload,
140
+ presentation: buildTypedApprovalPresentation({
141
+ approvalId: params.request.id,
142
+ approvalKind: "plugin",
143
+ allowedDecisions: payload.allowedDecisions
144
+ })
145
+ };
129
146
  }
130
147
  const whatsappApprovalCapability = createChannelApprovalCapability({
131
148
  ...whatsappApprovalAuth,
@@ -201,12 +218,13 @@ const whatsappApprovalCapability = createChannelApprovalCapability({
201
218
  accountId,
202
219
  nativeSessionOnly: true
203
220
  }),
204
- shouldHandle: ({ cfg, accountId, context, request }) => Boolean(context) && shouldHandleWhatsAppApprovalRequest({
221
+ shouldHandle: ({ cfg, accountId, context, approvalKind, request }) => Boolean(context) && shouldHandleWhatsAppApprovalRequest({
205
222
  cfg,
206
223
  accountId,
224
+ approvalKind,
207
225
  request
208
226
  }),
209
- load: async () => (await import("./approval-handler.runtime-DNWS4aYQ.js")).whatsappApprovalNativeRuntime
227
+ load: async () => (await import("./approval-handler.runtime-CBiGQuZ5.js")).whatsappApprovalNativeRuntime
210
228
  })
211
229
  });
212
230
  //#endregion
@@ -262,14 +280,7 @@ const WHATSAPP_LEGACY_OUTBOUND_SEND_DEP_KEYS = ["sendWhatsApp"];
262
280
  function resolveQuoteLookupAccountId(cfg, accountId) {
263
281
  const explicitAccountId = normalizeOptionalAccountId(accountId);
264
282
  if (explicitAccountId) return explicitAccountId;
265
- const channelCfg = cfg?.channels?.whatsapp;
266
- return resolveListedDefaultAccountId({
267
- accountIds: listCombinedAccountIds({
268
- configuredAccountIds: channelCfg?.accounts && typeof channelCfg.accounts === "object" ? Object.keys(channelCfg.accounts).filter(Boolean) : [],
269
- fallbackAccountIdWhenEmpty: DEFAULT_ACCOUNT_ID
270
- }),
271
- configuredDefaultAccountId: normalizeOptionalAccountId(channelCfg?.defaultAccount)
272
- });
283
+ return resolveDefaultWhatsAppAccountId(cfg ?? {});
273
284
  }
274
285
  function createWhatsAppOutboundBase({ chunker, sendMessageWhatsApp, sendPollWhatsApp, shouldLogVerbose, resolveTarget, normalizeText = normalizeWhatsAppPayloadText, skipEmptyText = true }) {
275
286
  const resolveQuotedMessageKey = (params) => {
@@ -379,6 +390,7 @@ function createWhatsAppOutboundBase({ chunker, sendMessageWhatsApp, sendPollWhat
379
390
  }
380
391
  //#endregion
381
392
  //#region extensions/whatsapp/src/channel-outbound.ts
393
+ const loadWhatsAppApprovalReactionsModule = createLazyRuntimeModule(() => import("./approval-reactions-BGQoz25s.js").then((n) => n.t));
382
394
  function normalizeWhatsAppChannelPayloadText(text) {
383
395
  return normalizeWhatsAppPayloadTextPreservingIndentation(text);
384
396
  }
@@ -386,6 +398,15 @@ function normalizeWhatsAppChannelSendText(text) {
386
398
  const normalized = normalizeWhatsAppChannelPayloadText(text);
387
399
  return normalized.trim() ? normalized : "";
388
400
  }
401
+ async function prepareWhatsAppApprovalPayloadForDelivery(params) {
402
+ return (await loadWhatsAppApprovalReactionsModule()).prepareWhatsAppApprovalPayloadForDelivery({
403
+ payload: params.payload,
404
+ presentation: params.presentation
405
+ });
406
+ }
407
+ async function registerDeliveredWhatsAppApprovalPayload(params) {
408
+ (await loadWhatsAppApprovalReactionsModule()).registerWhatsAppApprovalReactionTargetForDeliveredPayload(params);
409
+ }
389
410
  const whatsappChannelOutbound = {
390
411
  ...createWhatsAppOutboundBase({
391
412
  chunker: chunkText,
@@ -403,6 +424,8 @@ const whatsappChannelOutbound = {
403
424
  normalizeText: normalizeWhatsAppChannelSendText
404
425
  }),
405
426
  sendTextOnlyErrorPayloads: true,
427
+ renderPresentation: prepareWhatsAppApprovalPayloadForDelivery,
428
+ afterDeliverPayload: registerDeliveredWhatsAppApprovalPayload,
406
429
  normalizePayload: ({ payload }) => ({
407
430
  ...payload,
408
431
  text: normalizeWhatsAppChannelPayloadText(payload.text)
@@ -441,6 +464,23 @@ const whatsappMessageAdapter = defineChannelMessageAdapter({
441
464
  } }
442
465
  });
443
466
  //#endregion
467
+ //#region extensions/whatsapp/src/group-intro.ts
468
+ const WHATSAPP_GROUP_INTRO_HINT = "WhatsApp IDs: SenderId is the participant JID (group participant id).";
469
+ /**
470
+ * @deprecated Core never consumed the group intro hint adapter; this export
471
+ * remains only for the plugin API surface and is removed after the next
472
+ * release train together with ChannelGroupAdapter.resolveGroupIntroHint.
473
+ */
474
+ function resolveWhatsAppGroupIntroHint() {
475
+ return WHATSAPP_GROUP_INTRO_HINT;
476
+ }
477
+ function resolveWhatsAppMentionStripRegexes(ctx) {
478
+ const selfE164 = (ctx.To ?? "").replace(/^whatsapp:/i, "");
479
+ if (!selfE164) return [];
480
+ const escaped = selfE164.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
481
+ return [new RegExp(escaped, "g"), new RegExp(`@${escaped}`, "g")];
482
+ }
483
+ //#endregion
444
484
  //#region extensions/whatsapp/src/heartbeat.ts
445
485
  async function checkWhatsAppHeartbeatReady(params) {
446
486
  if (params.cfg.web?.enabled === false) return {
@@ -501,23 +541,16 @@ function resolveWhatsAppOutboundSessionRoute(params) {
501
541
  }
502
542
  //#endregion
503
543
  //#region extensions/whatsapp/src/status-issues.ts
544
+ const WHATSAPP_ACCOUNT_STATUS_FIELDS = [
545
+ "statusState",
546
+ "linked",
547
+ "reconnectAttempts",
548
+ "lastDisconnect",
549
+ "lastInboundAt",
550
+ "lastError",
551
+ "healthState"
552
+ ];
504
553
  const RECENT_DISCONNECT_WARNING_WINDOW_MS = 900 * 1e3;
505
- function readWhatsAppAccountStatus(value) {
506
- if (!isRecord$1(value)) return null;
507
- return {
508
- accountId: value.accountId,
509
- statusState: value.statusState,
510
- enabled: value.enabled,
511
- linked: value.linked,
512
- connected: value.connected,
513
- running: value.running,
514
- reconnectAttempts: value.reconnectAttempts,
515
- lastDisconnect: value.lastDisconnect,
516
- lastInboundAt: value.lastInboundAt,
517
- lastError: value.lastError,
518
- healthState: value.healthState
519
- };
520
- }
521
554
  function readLastDisconnect(value) {
522
555
  if (typeof value === "string") {
523
556
  const error = asString(value);
@@ -539,7 +572,7 @@ function isRecentDisconnect(disconnect, now = Date.now()) {
539
572
  function collectWhatsAppStatusIssues(accounts) {
540
573
  return collectIssuesForEnabledAccounts({
541
574
  accounts,
542
- readAccount: readWhatsAppAccountStatus,
575
+ readAccount: (value) => readAccountStatusSnapshot(value, WHATSAPP_ACCOUNT_STATUS_FIELDS),
543
576
  collectIssues: ({ account, accountId, issues }) => {
544
577
  const linked = account.linked === true;
545
578
  const statusState = asString(account.statusState);
@@ -624,8 +657,8 @@ function collectWhatsAppStatusIssues(accounts) {
624
657
  }
625
658
  //#endregion
626
659
  //#region extensions/whatsapp/src/channel.ts
627
- const loadWhatsAppDirectoryConfig = createLazyRuntimeModule(() => import("./directory-config-Dijefxc3.js").then((n) => n.t));
628
- const loadWhatsAppChannelReactAction = createLazyRuntimeModule(() => import("./channel-react-action-CKJHL_Wf.js"));
660
+ const loadWhatsAppDirectoryConfig = createLazyRuntimeModule(() => import("./directory-config-CLBQrjtC.js").then((n) => n.t));
661
+ const loadWhatsAppChannelReactAction = createLazyRuntimeModule(() => import("./channel-react-action-PoRWfP9x.js"));
629
662
  function resolveWhatsAppTargetInfo(raw) {
630
663
  const normalized = normalizeWhatsAppTarget(raw);
631
664
  if (!normalized) return null;
@@ -651,8 +684,7 @@ const whatsappPlugin = createChatChannelPlugin({
651
684
  ...createWhatsAppPluginBase({
652
685
  groups: {
653
686
  resolveRequireMention: resolveWhatsAppGroupRequireMention,
654
- resolveToolPolicy: resolveWhatsAppGroupToolPolicy,
655
- resolveGroupIntroHint: resolveWhatsAppGroupIntroHint
687
+ resolveToolPolicy: resolveWhatsAppGroupToolPolicy
656
688
  },
657
689
  setupWizard: whatsappSetupWizardProxy,
658
690
  setup: whatsappSetupAdapter,
@@ -895,4 +927,4 @@ const whatsappPlugin = createChatChannelPlugin({
895
927
  }
896
928
  });
897
929
  //#endregion
898
- export { WHATSAPP_LEGACY_OUTBOUND_SEND_DEP_KEYS as n, whatsappPlugin as t };
930
+ export { resolveWhatsAppGroupIntroHint as n, WHATSAPP_LEGACY_OUTBOUND_SEND_DEP_KEYS as r, whatsappPlugin as t };
@@ -1,2 +1,2 @@
1
- import { t as WhatsAppChannelConfigSchema } from "./config-schema-mBX2nmn1.js";
1
+ import { t as WhatsAppChannelConfigSchema } from "./config-schema-BZ8h1hWA.js";
2
2
  export { WhatsAppChannelConfigSchema };
@@ -1,2 +1,2 @@
1
- import { t as whatsappPlugin } from "./channel-BWp7h1uY.js";
1
+ import { t as whatsappPlugin } from "./channel-DbadDUDD.js";
2
2
  export { whatsappPlugin };
@@ -1,8 +1,8 @@
1
- import { a as resolveWhatsAppAccount, s as resolveWhatsAppMediaMaxBytes } from "./accounts-4YgwroRU.js";
2
- import { c as normalizeWhatsAppTarget, t as isWhatsAppGroupJid } from "./normalize-target-bVWjgftN.js";
3
- import { r as resolveAuthorizedWhatsAppOutboundTarget, t as handleWhatsAppAction } from "./action-runtime-DPahAqxV.js";
4
- import { t as sendMessageWhatsApp } from "./send-C5CpFcBG.js";
5
- import "./normalize-Bxwqo-bW.js";
1
+ import { a as resolveWhatsAppAccount, s as resolveWhatsAppMediaMaxBytes } from "./accounts-CKOFMPf-.js";
2
+ import { c as normalizeWhatsAppTarget, t as isWhatsAppGroupJid } from "./normalize-target-DSZnHkKF.js";
3
+ import { r as resolveAuthorizedWhatsAppOutboundTarget, t as handleWhatsAppAction } from "./action-runtime-Bf-12TIH.js";
4
+ import { t as sendMessageWhatsApp } from "./send-D9Ydnn4o.js";
5
+ import "./normalize-C-Z16y7Q.js";
6
6
  import { jsonResult, readStringOrNumberParam, readStringParam as readStringParam$1, resolveReactionMessageId } from "openclaw/plugin-sdk/channel-actions";
7
7
  import { readBooleanParam } from "openclaw/plugin-sdk/boolean-param";
8
8
  //#region extensions/whatsapp/src/channel-react-action.ts
@@ -23,8 +23,8 @@ function readWhatsAppActionChatJid(params) {
23
23
  return normalizeWhatsAppTarget(params.toolContext.currentChannelId) ?? void 0;
24
24
  }
25
25
  function extractBase64Payload(encoded) {
26
- const match = /^data:[^;]+;base64,(.*)$/i.exec(encoded.trim());
27
- return match ? match[1] : encoded;
26
+ const payload = /^data:[^;]+;base64,(.*)$/i.exec(encoded.trim())?.[1];
27
+ return payload !== void 0 ? payload : encoded;
28
28
  }
29
29
  function estimateBase64DecodedBytes(encoded) {
30
30
  const compact = extractBase64Payload(encoded).replace(/\s/g, "");
@@ -1,9 +1,9 @@
1
1
  import { startWebLoginWithQr as startWebLoginWithQr$1, waitForWebLogin as waitForWebLogin$1 } from "./login-qr-runtime.js";
2
- import { c as logoutWeb$1, d as readWebAuthExistsBestEffort$1, f as readWebAuthExistsForDecision$1, g as readWebSelfId$1, h as readWebAuthState$1, m as readWebAuthSnapshotBestEffort$1, o as getWebAuthAgeMs$1, p as readWebAuthSnapshot$1, s as logWebSelfId$1, x as webAuthExists$1 } from "./auth-store-Db-wfApd.js";
3
- import { t as getActiveWebListener$1 } from "./active-listener-B4SDebQ6.js";
4
- import { t as monitorWebChannel$1 } from "./monitor-DD8bXohk.js";
5
- import { t as loginWeb$1 } from "./login-C48y0jlx.js";
6
- import { whatsappSetupWizard as whatsappSetupWizard$1 } from "./setup-surface-DlWb0Z09.js";
2
+ import { c as logoutWeb$1, d as readWebAuthExistsBestEffort$1, f as readWebAuthExistsForDecision$1, g as readWebSelfId$1, h as readWebAuthState$1, m as readWebAuthSnapshotBestEffort$1, o as getWebAuthAgeMs$1, p as readWebAuthSnapshot$1, s as logWebSelfId$1, x as webAuthExists$1 } from "./auth-store-BQi9pZqQ.js";
3
+ import { t as getActiveWebListener$1 } from "./active-listener-5kHap439.js";
4
+ import { t as monitorWebChannel$1 } from "./monitor-BZ8QvCeV.js";
5
+ import { t as loginWeb$1 } from "./login-DGIoToX8.js";
6
+ import { whatsappSetupWizard as whatsappSetupWizard$1 } from "./setup-surface-CiKGdNJv.js";
7
7
  //#region extensions/whatsapp/src/channel.runtime.ts
8
8
  function getActiveWebListener(...args) {
9
9
  return getActiveWebListener$1(...args);
@@ -1,16 +1,15 @@
1
- import { a as resolveWhatsAppGroupRequireMention, i as whatsappSetupWizardProxy, n as createWhatsAppPluginBase, o as resolveWhatsAppGroupToolPolicy, s as resolveWhatsAppGroupIntroHint, t as whatsappSetupAdapter } from "./setup-core-DH-DFPLY.js";
2
- import { t as detectWhatsAppLegacyStateMigrations } from "./state-migrations-D_BmQUR9.js";
1
+ import { a as resolveWhatsAppGroupRequireMention, i as whatsappSetupWizardProxy, n as createWhatsAppPluginBase, o as resolveWhatsAppGroupToolPolicy, t as whatsappSetupAdapter } from "./setup-core-3aSOoK2T.js";
2
+ import { t as detectWhatsAppLegacyStateMigrations } from "./state-migrations-CAMTrs2U.js";
3
3
  //#region extensions/whatsapp/src/channel.setup.ts
4
4
  async function isWhatsAppAuthConfigured(account) {
5
- const { readWebAuthState } = await import("./auth-store-Db-wfApd.js").then((n) => n.i);
5
+ const { readWebAuthState } = await import("./auth-store-BQi9pZqQ.js").then((n) => n.i);
6
6
  return await readWebAuthState(account.authDir) === "linked";
7
7
  }
8
8
  const whatsappSetupPlugin = {
9
9
  ...createWhatsAppPluginBase({
10
10
  groups: {
11
11
  resolveRequireMention: resolveWhatsAppGroupRequireMention,
12
- resolveToolPolicy: resolveWhatsAppGroupToolPolicy,
13
- resolveGroupIntroHint: resolveWhatsAppGroupIntroHint
12
+ resolveToolPolicy: resolveWhatsAppGroupToolPolicy
14
13
  },
15
14
  setupWizard: whatsappSetupWizardProxy,
16
15
  setup: whatsappSetupAdapter,
@@ -0,0 +1,40 @@
1
+ import { createChannelConfigUiHints } from "openclaw/plugin-sdk/channel-core";
2
+ import { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-schema";
3
+ import { WhatsAppConfigSchema } from "openclaw/plugin-sdk/bundled-channel-config-schema";
4
+ //#endregion
5
+ //#region extensions/whatsapp/src/config-schema.ts
6
+ const WhatsAppChannelConfigSchema = buildChannelConfigSchema(WhatsAppConfigSchema, { uiHints: {
7
+ "": {
8
+ label: "WhatsApp",
9
+ help: "WhatsApp channel provider configuration for access policy and message batching behavior. Use this section to tune responsiveness and direct-message routing safety for WhatsApp chats."
10
+ },
11
+ ...createChannelConfigUiHints({
12
+ channelLabel: "WhatsApp",
13
+ dmPolicy: { channelKey: "whatsapp" }
14
+ }),
15
+ selfChatMode: {
16
+ label: "WhatsApp Self-Phone Mode",
17
+ help: "Same-phone setup (bot uses your personal WhatsApp number)."
18
+ },
19
+ debounceMs: {
20
+ label: "WhatsApp Message Debounce (ms)",
21
+ help: "Debounce window (ms) for batching rapid consecutive messages from the same sender (0 to disable)."
22
+ },
23
+ ...createChannelConfigUiHints({
24
+ channelLabel: "WhatsApp",
25
+ configWrites: true
26
+ }),
27
+ "actions.calls": {
28
+ label: "WhatsApp Voice Calls",
29
+ help: "Expose the experimental requester-bound WhatsApp voice-call tool. Default: false. Requires a separately paired MeowCaller CLI."
30
+ },
31
+ ...createChannelConfigUiHints({
32
+ channelLabel: "WhatsApp",
33
+ mentionPatterns: {
34
+ targetDescription: "WhatsApp conversation IDs",
35
+ policyTargetDescription: "WhatsApp conversation IDs such as 123@g.us"
36
+ }
37
+ })
38
+ } });
39
+ //#endregion
40
+ export { WhatsAppChannelConfigSchema as t };
@@ -1,12 +1,15 @@
1
- import { n as registerWhatsAppConnectionController, r as unregisterWhatsAppConnectionController } from "./connection-controller-registry-TSX_udJp.js";
2
- import { n as getStatusCode, t as formatError } from "./session-errors-BAj9D2La.js";
3
- import { t as DEFAULT_WHATSAPP_SOCKET_TIMING } from "./socket-timing-DhbVFjah.js";
4
- import { c as logoutWeb, f as readWebAuthExistsForDecision, r as WhatsAppAuthUnstableError } from "./auth-store-Db-wfApd.js";
5
- import { c as resolveComparableIdentity } from "./identity-Dqft3mFA.js";
6
- import { r as waitForWaConnection, t as createWaSocket } from "./session-DriaHt7V.js";
1
+ import { n as getWhatsAppRuntime } from "./runtime-BfAdAEYT.js";
2
+ import { t as WHATSAPP_CONNECTION_CONTROLLER_CAPABILITY } from "./connection-controller-runtime-context-CbTsqmPT.js";
3
+ import { c as logoutWeb, f as readWebAuthExistsForDecision, r as WhatsAppAuthUnstableError } from "./auth-store-BQi9pZqQ.js";
4
+ import { c as resolveComparableIdentity } from "./identity-D7L8LCuH.js";
5
+ import { i as DEFAULT_WHATSAPP_SOCKET_TIMING, r as waitForWaConnection, t as createWaSocket } from "./session-mxWFn0eS.js";
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
+ import { registerChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runtime-context";
8
9
  import { clamp } from "openclaw/plugin-sdk/text-utility-runtime";
9
10
  import { randomUUID } from "node:crypto";
11
+ //#region extensions/whatsapp/src/reconnect.ts
12
+ const DEFAULT_HEARTBEAT_SECONDS = 60;
10
13
  const DEFAULT_RECONNECT_POLICY = {
11
14
  initialMs: 2e3,
12
15
  maxMs: 3e4,
@@ -17,7 +20,7 @@ const DEFAULT_RECONNECT_POLICY = {
17
20
  function resolveHeartbeatSeconds(cfg, overrideSeconds) {
18
21
  const candidate = overrideSeconds ?? cfg.web?.heartbeatSeconds;
19
22
  if (typeof candidate === "number" && candidate > 0) return candidate;
20
- return 60;
23
+ return DEFAULT_HEARTBEAT_SECONDS;
21
24
  }
22
25
  function resolveReconnectPolicy(cfg, overrides) {
23
26
  const reconnectOverrides = cfg.web?.reconnect ?? {};
@@ -103,6 +106,21 @@ function closeWaSocketSoon(sock, delayMs = 500) {
103
106
  closeWaSocket(sock);
104
107
  }, delayMs);
105
108
  }
109
+ async function waitForLoginSocket(params) {
110
+ if (!params.credentialPersistenceFailure) {
111
+ await params.wait();
112
+ return;
113
+ }
114
+ const outcome = await Promise.race([params.wait().then(() => ({ kind: "connected" })), params.credentialPersistenceFailure.then((failure) => ({
115
+ kind: "credential-persistence-failed",
116
+ failure
117
+ }))]);
118
+ if (outcome.kind === "credential-persistence-failed") throw outcome.failure.error;
119
+ }
120
+ function throwIfCredentialPersistenceFailed(getFailure) {
121
+ const failure = getFailure?.();
122
+ if (failure) throw failure.error;
123
+ }
106
124
  async function waitForWhatsAppLoginResult(params) {
107
125
  const wait = params.waitForConnection ?? waitForWaConnection;
108
126
  const createSocket = params.createSocket ?? createWaSocket;
@@ -116,7 +134,10 @@ async function waitForWhatsAppLoginResult(params) {
116
134
  currentSock = await createSocket(false, params.verbose, {
117
135
  authDir: params.authDir,
118
136
  ...params.socketTiming,
119
- onQr: params.onQr
137
+ onQr: params.onQr,
138
+ beforeCredentialPersistence: params.beforeCredentialPersistence,
139
+ onCredentialPersistenceError: params.onCredentialPersistenceError,
140
+ onCredentialPersistenceTask: params.onCredentialPersistenceTask
120
141
  });
121
142
  params.onSocketReplaced?.(currentSock);
122
143
  return null;
@@ -130,8 +151,14 @@ async function waitForWhatsAppLoginResult(params) {
130
151
  }
131
152
  };
132
153
  while (true) try {
133
- await wait(currentSock, { timeout: "none" });
154
+ await waitForLoginSocket({
155
+ wait: async () => await wait(currentSock, { timeout: "none" }),
156
+ credentialPersistenceFailure: params.credentialPersistenceFailure
157
+ });
158
+ await params.waitForCredentialPersistence?.();
159
+ throwIfCredentialPersistenceFailed(params.getCredentialPersistenceFailure);
134
160
  const persistedAuth = await readWebAuthExistsForDecision(params.authDir);
161
+ throwIfCredentialPersistenceFailed(params.getCredentialPersistenceFailure);
135
162
  if (persistedAuth.outcome === "unstable") return {
136
163
  outcome: "failed",
137
164
  message: WHATSAPP_LOGIN_AUTH_UNSTABLE_MESSAGE,
@@ -169,7 +196,8 @@ async function waitForWhatsAppLoginResult(params) {
169
196
  if (!await logoutWeb({
170
197
  authDir: params.authDir,
171
198
  isLegacyAuthDir: params.isLegacyAuthDir,
172
- runtime: params.runtime
199
+ runtime: params.runtime,
200
+ beforeCredentialPersistence: params.beforeCredentialPersistence
173
201
  })) {
174
202
  const existingAuth = await readWebAuthExistsForDecision(params.authDir);
175
203
  if (existingAuth.outcome === "unstable") return {
@@ -200,6 +228,7 @@ var WhatsAppConnectionController = class {
200
228
  constructor(params) {
201
229
  this.disconnectRetryController = new AbortController();
202
230
  this.current = null;
231
+ this.runtimeContextLease = null;
203
232
  this.reconnectAttempts = 0;
204
233
  this.lastHandledInboundAt = null;
205
234
  this.accountId = params.accountId;
@@ -304,6 +333,7 @@ var WhatsAppConnectionController = class {
304
333
  ...params.cachedGroupMetadata ? { cachedGroupMetadata: params.cachedGroupMetadata } : {}
305
334
  });
306
335
  await waitForWaConnection(sock, { timeoutMs: this.socketTiming.connectTimeoutMs });
336
+ const channelRuntime = getWhatsAppRuntime().channel;
307
337
  this.socketRef.current = sock;
308
338
  connection = createLiveConnection({
309
339
  connectionId: params.connectionId,
@@ -318,7 +348,16 @@ var WhatsAppConnectionController = class {
318
348
  connection.listener = listener;
319
349
  this.current = connection;
320
350
  connection.unregisterTransportActivity = this.attachTransportActivityListener(sock);
321
- registerWhatsAppConnectionController(this.accountId, this);
351
+ const previousRuntimeContextLease = this.runtimeContextLease;
352
+ this.runtimeContextLease = registerChannelRuntimeContext({
353
+ channelRuntime,
354
+ channelId: "whatsapp",
355
+ accountId: this.accountId,
356
+ capability: WHATSAPP_CONNECTION_CONTROLLER_CAPABILITY,
357
+ context: this,
358
+ abortSignal: this.abortSignal
359
+ });
360
+ previousRuntimeContextLease?.dispose();
322
361
  this.startTimers(connection, {
323
362
  onHeartbeat: params.onHeartbeat,
324
363
  onWatchdogTimeout: params.onWatchdogTimeout
@@ -441,7 +480,8 @@ var WhatsAppConnectionController = class {
441
480
  async shutdown() {
442
481
  this.stopDisconnectRetries();
443
482
  await this.closeCurrentConnection();
444
- unregisterWhatsAppConnectionController(this.accountId, this);
483
+ this.runtimeContextLease?.dispose();
484
+ this.runtimeContextLease = null;
445
485
  }
446
486
  startTimers(connection, hooks) {
447
487
  if (!this.keepAlive) return;