@lofa199419/waha-v2 2026.3.4 → 2026.3.6
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/SESSION_HANDOFF_2026-03-05.md +55 -0
- package/SESSION_HANDOFF_2026-03-05_E2E_STATUS.md +84 -0
- package/index.ts +2 -2
- package/package.json +4 -2
- package/skills/waha-v2/SKILL.md +49 -10
- package/src/accounts.ts +9 -2
- package/src/channel.ts +87 -15
- package/src/client.ts +168 -25
- package/src/config-schema.ts +42 -0
- package/src/deliver.ts +70 -0
- package/src/gateway.ts +41 -11
- package/src/login.ts +9 -2
- package/src/outbound.ts +11 -3
- package/src/probe.ts +9 -2
- package/src/routes.ts +6 -4
- package/src/runtime.ts +3 -1
- package/src/types.ts +21 -0
- package/src/webhook.ts +89 -3
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# WAHA v2 Session Handoff (2026-03-05)
|
|
2
|
+
|
|
3
|
+
## 1) Scope completed
|
|
4
|
+
- Focused only on `extensions/waha-v2`.
|
|
5
|
+
- Objective was to make typing indicator + chunked sending behavior reliable and observable, then publish and verify on target host.
|
|
6
|
+
|
|
7
|
+
## 2) Local code changes made
|
|
8
|
+
|
|
9
|
+
### `src/client.ts`
|
|
10
|
+
- Improved typing presence calls (`startTyping` / `stopTyping`) so non-2xx HTTP responses are treated as failures.
|
|
11
|
+
- Added response-context error reporting for easier diagnosis.
|
|
12
|
+
|
|
13
|
+
### `src/webhook.ts`
|
|
14
|
+
- Added debug logs around typing/chunk lifecycle to make runtime behavior visible.
|
|
15
|
+
- Ensured inter-chunk typing start failures do **not** break chunk sending.
|
|
16
|
+
- Updated behavior to trigger typing before first chunk and added a short first-chunk delay (`700ms`) to make typing indicator visible.
|
|
17
|
+
|
|
18
|
+
## 3) Publish
|
|
19
|
+
- Published npm package: `@lofa199419/waha-v2@2026.3.5`.
|
|
20
|
+
- Registry was verified to reflect `2026.3.5`.
|
|
21
|
+
|
|
22
|
+
## 4) Remote deployment performed
|
|
23
|
+
Target host used:
|
|
24
|
+
- `ubuntu@100.106.66.110`
|
|
25
|
+
|
|
26
|
+
State found before fix:
|
|
27
|
+
- Host still had `waha-v2@2026.3.4` in `~/.openclaw/extensions/waha-v2`.
|
|
28
|
+
- Typing config block not set.
|
|
29
|
+
|
|
30
|
+
Actions performed:
|
|
31
|
+
- Updated extension on host to `2026.3.5`.
|
|
32
|
+
- Set config values:
|
|
33
|
+
- `channels.waha-v2.typing.enabled=true`
|
|
34
|
+
- `channels.waha-v2.typing.chunking=true`
|
|
35
|
+
- `channels.waha-v2.typing.charsPerSecond=25`
|
|
36
|
+
- `channels.waha-v2.typing.maxChunkLength=220`
|
|
37
|
+
- Restarted gateway.
|
|
38
|
+
|
|
39
|
+
Post-update verification:
|
|
40
|
+
- Plugin list shows `waha-v2@2026.3.5`.
|
|
41
|
+
- Typing config present.
|
|
42
|
+
- WAHA channel/accounts probing healthy.
|
|
43
|
+
|
|
44
|
+
## 5) Remaining validation step
|
|
45
|
+
- Final observational confirmation: send a multi-paragraph prompt and verify logs show typing/chunk markers during a real message.
|
|
46
|
+
|
|
47
|
+
Suggested log check pattern:
|
|
48
|
+
- `waha-v2: send chunked reply`
|
|
49
|
+
- `waha-v2: send chunk`
|
|
50
|
+
- `typing start ok`
|
|
51
|
+
- `typing stop ok`
|
|
52
|
+
- first/inter-chunk typing start success/failure markers
|
|
53
|
+
|
|
54
|
+
## 6) Environment note
|
|
55
|
+
- On the remote host, `rg` was unavailable; use `grep`/`grep -E` for log filtering.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# WAHA v2 E2E Status Handoff (2026-03-05)
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
This note captures what was smoke tested live in this session, what is confirmed, what is partially confirmed, and what remains to verify later.
|
|
5
|
+
|
|
6
|
+
## Environment used
|
|
7
|
+
- Repo: `/home/lofa/dev/openclaw`
|
|
8
|
+
- Extension focus: `extensions/waha-v2`
|
|
9
|
+
- Active account: `default`
|
|
10
|
+
- Main WAHA session: `finaltouch`
|
|
11
|
+
|
|
12
|
+
## Code changes completed in this session
|
|
13
|
+
|
|
14
|
+
### 1) Target/action routing hardening (core)
|
|
15
|
+
- For no-target actions, accidental `target` no longer hard-fails.
|
|
16
|
+
- File: `src/infra/outbound/channel-target.ts`
|
|
17
|
+
- WAHA group/contact action target modes fixed so `target` maps correctly.
|
|
18
|
+
- File: `src/infra/outbound/message-action-spec.ts`
|
|
19
|
+
- Regression tests added/updated.
|
|
20
|
+
- File: `src/infra/outbound/message-action-runner.test.ts`
|
|
21
|
+
|
|
22
|
+
### 2) Request-code flow in WAHA v2 plugin
|
|
23
|
+
- `request-code` now enforces session prep + delay flow:
|
|
24
|
+
- Missing session: create -> start
|
|
25
|
+
- Existing active session: stop -> start (restart)
|
|
26
|
+
- Existing stopped/failed session: start
|
|
27
|
+
- Wait 5 seconds
|
|
28
|
+
- Request code
|
|
29
|
+
- File: `extensions/waha-v2/src/channel.ts`
|
|
30
|
+
|
|
31
|
+
## Live smoke tests run and result
|
|
32
|
+
|
|
33
|
+
### A) Messaging/chat/group/contact core read paths
|
|
34
|
+
- PASS: `list-chats`
|
|
35
|
+
- PASS: `get-chat-messages` (chat `154739484418169@lid`)
|
|
36
|
+
- PASS: `react` on message `false_154739484418169@lid_3A6FC76D1349CFCA7C1D` with `👍`
|
|
37
|
+
- PASS: `list-groups`
|
|
38
|
+
- PASS: `get-group`
|
|
39
|
+
- PASS: `get-group-participants`
|
|
40
|
+
- PASS: `get-group-invite-code`
|
|
41
|
+
- PASS: `list-contacts`
|
|
42
|
+
- PASS: `check-contact` for known number `573016924546`
|
|
43
|
+
- PASS: `get-contact` (known resolved contact id)
|
|
44
|
+
|
|
45
|
+
### B) Session/pairing E2E
|
|
46
|
+
- PASS: `start-session` on primary (`finaltouch`)
|
|
47
|
+
- PASS: fresh session create/start/get-qr flow
|
|
48
|
+
- temporary session: `e2e-smoke-1772739741688`
|
|
49
|
+
- PASS: request-code sequence with 5s delay for number `905382188346`
|
|
50
|
+
- temporary session: `pair-code-1772740042905`
|
|
51
|
+
- returned code: `J7CR-WTK7`
|
|
52
|
+
- NOTE: `startSession` on a fresh non-existent session fails first with `Resource not found` (expected), then succeeds after create.
|
|
53
|
+
|
|
54
|
+
## Not fully confirmed / lower confidence areas
|
|
55
|
+
|
|
56
|
+
### WAHA server-side failures seen (likely backend/permission/input related, not mapping)
|
|
57
|
+
- `promote-group-admin` / `demote-group-admin` on real group + participant returned WAHA 500.
|
|
58
|
+
- mutation ops with fake/nonexistent ids returned WAHA 500 (expected pattern).
|
|
59
|
+
- `check-contact` for obviously unknown number returned WAHA 500 (not a clean false response).
|
|
60
|
+
|
|
61
|
+
### Explicitly not required right now (per user)
|
|
62
|
+
- block/unblock round-trip verification
|
|
63
|
+
|
|
64
|
+
## 100% verified for current priority (practical)
|
|
65
|
+
Priority list from user context:
|
|
66
|
+
- Start a Session -> verified
|
|
67
|
+
- Get QR Code for Pairing -> verified
|
|
68
|
+
- Request Pairing Code -> verified (with required wait behavior)
|
|
69
|
+
- Send a Message -> verified
|
|
70
|
+
- React to a Message -> verified
|
|
71
|
+
- List Conversations -> verified
|
|
72
|
+
- Check Contact Status -> verified on known-valid contact
|
|
73
|
+
|
|
74
|
+
## Remaining to double-check later (if needed)
|
|
75
|
+
1. `request-code` through the full OpenClaw message action runner path (not only direct wrapper script) after publishing latest plugin/core changes everywhere.
|
|
76
|
+
2. clean handling expectations for unknown numbers in `check-contact` (whether WAHA should return false vs 500; depends on backend behavior).
|
|
77
|
+
3. admin-role mutation behavior (`promote/demote`) with a dedicated controlled test group where bot permissions are guaranteed.
|
|
78
|
+
|
|
79
|
+
## Operational notes
|
|
80
|
+
- Temporary sessions created during tests were stopped.
|
|
81
|
+
- Last active primary session remains `finaltouch`.
|
|
82
|
+
- Existing older summary file remains:
|
|
83
|
+
- `extensions/waha-v2/SESSION_HANDOFF_2026-03-05.md`
|
|
84
|
+
|
package/index.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
2
2
|
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
|
3
3
|
import { wahaV2Plugin } from "./src/channel.js";
|
|
4
|
-
import { setWahaV2Runtime } from "./src/runtime.js";
|
|
5
|
-
import { handleWahaV2WebhookRequest } from "./src/webhook.js";
|
|
6
4
|
import {
|
|
7
5
|
handleWahaV2QrRoute,
|
|
8
6
|
handleWahaV2RequestCodeRoute,
|
|
@@ -15,7 +13,9 @@ import {
|
|
|
15
13
|
WAHA_V2_ROUTE_STATUS,
|
|
16
14
|
WAHA_V2_ROUTE_WAIT,
|
|
17
15
|
} from "./src/routes.js";
|
|
16
|
+
import { setWahaV2Runtime } from "./src/runtime.js";
|
|
18
17
|
import { WAHA_V2_WEBHOOK_BASE } from "./src/types.js";
|
|
18
|
+
import { handleWahaV2WebhookRequest } from "./src/webhook.js";
|
|
19
19
|
|
|
20
20
|
const plugin = {
|
|
21
21
|
id: "waha-v2",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lofa199419/waha-v2",
|
|
3
|
-
"version": "2026.3.
|
|
3
|
+
"version": "2026.3.6",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "OpenClaw WAHA v2 channel plugin — independent WhatsApp HTTP API integration",
|
|
6
6
|
"type": "module",
|
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
"openclaw": ">=2026.0.0"
|
|
14
14
|
},
|
|
15
15
|
"peerDependenciesMeta": {
|
|
16
|
-
"openclaw": {
|
|
16
|
+
"openclaw": {
|
|
17
|
+
"optional": true
|
|
18
|
+
}
|
|
17
19
|
},
|
|
18
20
|
"openclaw": {
|
|
19
21
|
"extensions": [
|
package/skills/waha-v2/SKILL.md
CHANGED
|
@@ -19,43 +19,74 @@ Use the `message` tool with `channel: "waha-v2"`. You have complete WhatsApp acc
|
|
|
19
19
|
|
|
20
20
|
## Session States
|
|
21
21
|
|
|
22
|
-
| State
|
|
23
|
-
|
|
24
|
-
| `WORKING` / `CONNECTED`
|
|
25
|
-
| `STOPPED` / `FAILED`
|
|
22
|
+
| State | Meaning |
|
|
23
|
+
| -------------------------- | ----------------------------------------- |
|
|
24
|
+
| `WORKING` / `CONNECTED` | Ready — go ahead |
|
|
25
|
+
| `STOPPED` / `FAILED` | Call `start-session` first |
|
|
26
26
|
| `SCAN_QR_CODE` / `PAIRING` | Waiting for user to scan QR or enter code |
|
|
27
|
-
| `CONNECTING`
|
|
27
|
+
| `CONNECTING` | Starting up — wait briefly |
|
|
28
28
|
|
|
29
29
|
---
|
|
30
30
|
|
|
31
31
|
## Sending Messages
|
|
32
32
|
|
|
33
33
|
### Text
|
|
34
|
+
|
|
34
35
|
```json
|
|
35
36
|
{ "action": "send", "channel": "waha-v2", "to": "15550001234@c.us", "message": "Hello!" }
|
|
36
37
|
```
|
|
37
38
|
|
|
38
39
|
### Media (image / video / audio / file)
|
|
40
|
+
|
|
39
41
|
```json
|
|
40
|
-
{
|
|
42
|
+
{
|
|
43
|
+
"action": "send",
|
|
44
|
+
"channel": "waha-v2",
|
|
45
|
+
"to": "15550001234@c.us",
|
|
46
|
+
"media": "https://…/file.pdf",
|
|
47
|
+
"message": "Your report"
|
|
48
|
+
}
|
|
41
49
|
```
|
|
42
50
|
|
|
43
51
|
### Poll
|
|
52
|
+
|
|
44
53
|
```json
|
|
45
|
-
{
|
|
54
|
+
{
|
|
55
|
+
"action": "poll",
|
|
56
|
+
"channel": "waha-v2",
|
|
57
|
+
"to": "15550001234@c.us",
|
|
58
|
+
"pollQuestion": "Which day?",
|
|
59
|
+
"pollOption": ["Mon", "Wed", "Fri"],
|
|
60
|
+
"pollMulti": false
|
|
61
|
+
}
|
|
46
62
|
```
|
|
47
63
|
|
|
48
64
|
### Location
|
|
65
|
+
|
|
49
66
|
```json
|
|
50
|
-
{
|
|
67
|
+
{
|
|
68
|
+
"action": "send-location",
|
|
69
|
+
"channel": "waha-v2",
|
|
70
|
+
"to": "15550001234@c.us",
|
|
71
|
+
"latitude": 37.77,
|
|
72
|
+
"longitude": -122.41,
|
|
73
|
+
"title": "SF Office"
|
|
74
|
+
}
|
|
51
75
|
```
|
|
52
76
|
|
|
53
77
|
### Contact card
|
|
78
|
+
|
|
54
79
|
```json
|
|
55
|
-
{
|
|
80
|
+
{
|
|
81
|
+
"action": "send-contact",
|
|
82
|
+
"channel": "waha-v2",
|
|
83
|
+
"to": "15550001234@c.us",
|
|
84
|
+
"contacts": [{ "vcard": "BEGIN:VCARD\nVERSION:3.0\nFN:Alice\nTEL:+14155559999\nEND:VCARD" }]
|
|
85
|
+
}
|
|
56
86
|
```
|
|
57
87
|
|
|
58
88
|
### Forward a message
|
|
89
|
+
|
|
59
90
|
```json
|
|
60
91
|
{ "action": "forward-message", "channel": "waha-v2", "to": "15550001234@c.us", "messageId": "<id>" }
|
|
61
92
|
```
|
|
@@ -152,11 +183,13 @@ Use the `message` tool with `channel: "waha-v2"`. You have complete WhatsApp acc
|
|
|
152
183
|
## Session Management & Login Flow
|
|
153
184
|
|
|
154
185
|
### Full QR login sequence
|
|
186
|
+
|
|
155
187
|
1. `start-session` — if `alreadyConnected: true`, done.
|
|
156
188
|
2. `get-qr` — returns `{ data }` base64 PNG; show to user to scan in WhatsApp → Linked Devices.
|
|
157
189
|
3. User scans, then call `start-session` again to confirm `connected: true`.
|
|
158
190
|
|
|
159
191
|
### Pairing code (no phone camera)
|
|
192
|
+
|
|
160
193
|
1. `start-session`
|
|
161
194
|
2. `request-code` with `phoneNumber: "15550001234"` — returns 8-digit code.
|
|
162
195
|
3. User enters code in WhatsApp → Linked Devices → Link with phone number.
|
|
@@ -171,7 +204,13 @@ Use the `message` tool with `channel: "waha-v2"`. You have complete WhatsApp acc
|
|
|
171
204
|
## Multi-Account
|
|
172
205
|
|
|
173
206
|
```json
|
|
174
|
-
{
|
|
207
|
+
{
|
|
208
|
+
"action": "send",
|
|
209
|
+
"channel": "waha-v2",
|
|
210
|
+
"accountId": "secondary",
|
|
211
|
+
"to": "15550001234@c.us",
|
|
212
|
+
"message": "Hi"
|
|
213
|
+
}
|
|
175
214
|
```
|
|
176
215
|
|
|
177
216
|
Each account gets its own webhook: `{webhookUrl}/{accountId}`.
|
package/src/accounts.ts
CHANGED
|
@@ -60,6 +60,7 @@ export function resolveWahaV2Account(
|
|
|
60
60
|
enabled: account.enabled !== false,
|
|
61
61
|
dmPolicy: account.dmPolicy,
|
|
62
62
|
allowFrom: account.allowFrom,
|
|
63
|
+
typing: account.typing,
|
|
63
64
|
};
|
|
64
65
|
}
|
|
65
66
|
|
|
@@ -102,7 +103,10 @@ export function setWahaV2AccountEnabled(
|
|
|
102
103
|
// Single-account mode — set enabled on root.
|
|
103
104
|
return setWahaV2ChannelConfig(cfg, { ...root, enabled });
|
|
104
105
|
}
|
|
105
|
-
const accounts = {
|
|
106
|
+
const accounts = {
|
|
107
|
+
...(root.accounts ?? {}),
|
|
108
|
+
[accountId]: { ...(root.accounts?.[accountId] ?? {}), enabled },
|
|
109
|
+
};
|
|
106
110
|
return setWahaV2ChannelConfig(cfg, { ...root, accounts });
|
|
107
111
|
}
|
|
108
112
|
|
|
@@ -113,5 +117,8 @@ export function deleteWahaV2Account(cfg: OpenClawConfig, accountId: string): Ope
|
|
|
113
117
|
}
|
|
114
118
|
const accounts = { ...root.accounts };
|
|
115
119
|
delete accounts[accountId];
|
|
116
|
-
return setWahaV2ChannelConfig(cfg, {
|
|
120
|
+
return setWahaV2ChannelConfig(cfg, {
|
|
121
|
+
...root,
|
|
122
|
+
accounts: Object.keys(accounts).length > 0 ? accounts : undefined,
|
|
123
|
+
});
|
|
117
124
|
}
|
package/src/channel.ts
CHANGED
|
@@ -8,12 +8,12 @@ import {
|
|
|
8
8
|
setWahaV2AccountEnabled,
|
|
9
9
|
setWahaV2ChannelConfig,
|
|
10
10
|
} from "./accounts.js";
|
|
11
|
+
import { wahaV2ChannelConfigSchema } from "./config-schema.js";
|
|
11
12
|
import { wahaV2Gateway } from "./gateway.js";
|
|
12
13
|
import { acquireLoginLock, releaseLoginLock, waitForWahaV2Connected } from "./login.js";
|
|
13
14
|
import { wahaV2Outbound } from "./outbound.js";
|
|
14
15
|
import { probeWahaV2Session } from "./probe.js";
|
|
15
16
|
import { getWahaV2Client } from "./runtime.js";
|
|
16
|
-
import { wahaV2ChannelConfigSchema } from "./config-schema.js";
|
|
17
17
|
import {
|
|
18
18
|
WAHA_V2_CHANNEL_ID,
|
|
19
19
|
WAHA_V2_DEFAULT_ACCOUNT_ID,
|
|
@@ -22,6 +22,48 @@ import {
|
|
|
22
22
|
type WahaV2RootConfig,
|
|
23
23
|
} from "./types.js";
|
|
24
24
|
|
|
25
|
+
function sleep(ms: number): Promise<void> {
|
|
26
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function prepareSessionForRequestCode(params: {
|
|
30
|
+
client: NonNullable<ReturnType<typeof getWahaV2Client>>;
|
|
31
|
+
session: string;
|
|
32
|
+
}): Promise<{
|
|
33
|
+
sessionExisted: boolean;
|
|
34
|
+
previousStatus: string | null;
|
|
35
|
+
restarted: boolean;
|
|
36
|
+
}> {
|
|
37
|
+
const sessions = await params.client.listSessions(true).catch(() => []);
|
|
38
|
+
const current = sessions.find((entry) => String(entry?.name ?? "") === params.session);
|
|
39
|
+
const previousStatus = current && typeof current.status === "string" ? current.status : null;
|
|
40
|
+
const sessionExisted = Boolean(current);
|
|
41
|
+
let restarted = false;
|
|
42
|
+
|
|
43
|
+
if (!sessionExisted) {
|
|
44
|
+
await params.client.createSession(params.session);
|
|
45
|
+
await params.client.startSession(params.session);
|
|
46
|
+
return { sessionExisted, previousStatus, restarted };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const normalized = String(previousStatus ?? "").trim().toUpperCase();
|
|
50
|
+
const shouldRestart =
|
|
51
|
+
normalized.length > 0 &&
|
|
52
|
+
!["STOPPED", "FAILED", "NONE", "UNKNOWN", "DISCONNECTED"].includes(normalized);
|
|
53
|
+
|
|
54
|
+
if (shouldRestart) {
|
|
55
|
+
await params.client.stopSession(params.session).catch(() => {});
|
|
56
|
+
restarted = true;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
await params.client.startSession(params.session).catch(async () => {
|
|
60
|
+
await params.client.createSession(params.session);
|
|
61
|
+
await params.client.startSession(params.session);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
return { sessionExisted, previousStatus, restarted };
|
|
65
|
+
}
|
|
66
|
+
|
|
25
67
|
/** Normalize allow-from entries to WhatsApp JID format. */
|
|
26
68
|
function normalizeAllowEntry(entry: string): string {
|
|
27
69
|
const trimmed = entry.trim();
|
|
@@ -142,8 +184,7 @@ export const wahaV2Plugin: ChannelPlugin<ResolvedWahaV2Account> = {
|
|
|
142
184
|
allowFrom: account.allowFrom,
|
|
143
185
|
}),
|
|
144
186
|
|
|
145
|
-
resolveAllowFrom: ({ cfg, accountId }) =>
|
|
146
|
-
resolveWahaV2Account(cfg, accountId).allowFrom,
|
|
187
|
+
resolveAllowFrom: ({ cfg, accountId }) => resolveWahaV2Account(cfg, accountId).allowFrom,
|
|
147
188
|
|
|
148
189
|
formatAllowFrom: ({ allowFrom }) =>
|
|
149
190
|
allowFrom.map((e) => normalizeAllowEntry(String(e))).filter(Boolean),
|
|
@@ -220,7 +261,13 @@ export const wahaV2Plugin: ChannelPlugin<ResolvedWahaV2Account> = {
|
|
|
220
261
|
}
|
|
221
262
|
// Contact lookup / block
|
|
222
263
|
if (gate("contacts")) {
|
|
223
|
-
result.push(
|
|
264
|
+
result.push(
|
|
265
|
+
"list-contacts",
|
|
266
|
+
"get-contact",
|
|
267
|
+
"check-contact",
|
|
268
|
+
"block-contact",
|
|
269
|
+
"unblock-contact",
|
|
270
|
+
);
|
|
224
271
|
}
|
|
225
272
|
// Group management
|
|
226
273
|
if (gate("groups")) {
|
|
@@ -280,7 +327,9 @@ export const wahaV2Plugin: ChannelPlugin<ResolvedWahaV2Account> = {
|
|
|
280
327
|
await client.startSession(session).catch(async () => {
|
|
281
328
|
await client.createSession(session);
|
|
282
329
|
});
|
|
283
|
-
const waitResult = await waitForWahaV2Connected(client, session, 5_000).catch(() => ({
|
|
330
|
+
const waitResult = await waitForWahaV2Connected(client, session, 5_000).catch(() => ({
|
|
331
|
+
ok: false,
|
|
332
|
+
}));
|
|
284
333
|
const probe = await probeWahaV2Session(client, session).catch(() => ({ ok: false }));
|
|
285
334
|
return jsonResult({
|
|
286
335
|
ok: true,
|
|
@@ -312,8 +361,20 @@ export const wahaV2Plugin: ChannelPlugin<ResolvedWahaV2Account> = {
|
|
|
312
361
|
if (!phoneNumber) throw new Error("waha-v2: request-code requires params.phoneNumber");
|
|
313
362
|
acquireLoginLock(account.accountId);
|
|
314
363
|
try {
|
|
364
|
+
const prep = await prepareSessionForRequestCode({ client, session });
|
|
365
|
+
// Give WAHA a short transition window before requesting pairing code.
|
|
366
|
+
await sleep(5_000);
|
|
315
367
|
const result = await client.requestCode(session, phoneNumber);
|
|
316
|
-
return jsonResult({
|
|
368
|
+
return jsonResult({
|
|
369
|
+
ok: true,
|
|
370
|
+
action: "request-code",
|
|
371
|
+
session,
|
|
372
|
+
sessionExisted: prep.sessionExisted,
|
|
373
|
+
previousStatus: prep.previousStatus,
|
|
374
|
+
restarted: prep.restarted,
|
|
375
|
+
waitedMs: 5_000,
|
|
376
|
+
code: result?.code ?? null,
|
|
377
|
+
});
|
|
317
378
|
} finally {
|
|
318
379
|
releaseLoginLock(account.accountId);
|
|
319
380
|
}
|
|
@@ -367,7 +428,8 @@ export const wahaV2Plugin: ChannelPlugin<ResolvedWahaV2Account> = {
|
|
|
367
428
|
if (action === "forward-message") {
|
|
368
429
|
const chatId = String(p.to ?? p.chatId ?? "");
|
|
369
430
|
const messageId = String(p.messageId ?? "");
|
|
370
|
-
if (!chatId || !messageId)
|
|
431
|
+
if (!chatId || !messageId)
|
|
432
|
+
throw new Error("waha-v2: forward-message requires to and messageId");
|
|
371
433
|
const result = await client.forwardMessage(session, chatId, messageId);
|
|
372
434
|
return jsonResult({ ok: true, action: "forward-message", chatId, result });
|
|
373
435
|
}
|
|
@@ -390,7 +452,8 @@ export const wahaV2Plugin: ChannelPlugin<ResolvedWahaV2Account> = {
|
|
|
390
452
|
const chatId = String(p.to ?? p.chatId ?? "");
|
|
391
453
|
const messageId = String(p.messageId ?? "");
|
|
392
454
|
const text = String(p.text ?? "");
|
|
393
|
-
if (!chatId || !messageId || !text)
|
|
455
|
+
if (!chatId || !messageId || !text)
|
|
456
|
+
throw new Error("waha-v2: edit requires to, messageId, text");
|
|
394
457
|
await client.editMessage(session, chatId, messageId, text);
|
|
395
458
|
return jsonResult({ ok: true, action: "edit", chatId, messageId });
|
|
396
459
|
}
|
|
@@ -441,7 +504,8 @@ export const wahaV2Plugin: ChannelPlugin<ResolvedWahaV2Account> = {
|
|
|
441
504
|
if (action === "get-message") {
|
|
442
505
|
const chatId = String(p.to ?? p.chatId ?? "");
|
|
443
506
|
const messageId = String(p.messageId ?? "");
|
|
444
|
-
if (!chatId || !messageId)
|
|
507
|
+
if (!chatId || !messageId)
|
|
508
|
+
throw new Error("waha-v2: get-message requires to and messageId");
|
|
445
509
|
const message = await client.getChatMessage(session, chatId, messageId);
|
|
446
510
|
return jsonResult({ ok: true, action: "get-message", chatId, messageId, message });
|
|
447
511
|
}
|
|
@@ -570,16 +634,22 @@ export const wahaV2Plugin: ChannelPlugin<ResolvedWahaV2Account> = {
|
|
|
570
634
|
|
|
571
635
|
if (action === "promote-group-admin") {
|
|
572
636
|
const groupId = String(p.groupId ?? p.to ?? "");
|
|
573
|
-
const participants = Array.isArray(p.participants)
|
|
574
|
-
|
|
637
|
+
const participants = Array.isArray(p.participants)
|
|
638
|
+
? (p.participants as string[])
|
|
639
|
+
: [String(p.participant ?? "")].filter(Boolean);
|
|
640
|
+
if (!groupId || participants.length === 0)
|
|
641
|
+
throw new Error("waha-v2: promote-group-admin requires groupId and participants");
|
|
575
642
|
const result = await client.promoteGroupAdmin(session, groupId, participants);
|
|
576
643
|
return jsonResult({ ok: true, action: "promote-group-admin", groupId, result });
|
|
577
644
|
}
|
|
578
645
|
|
|
579
646
|
if (action === "demote-group-admin") {
|
|
580
647
|
const groupId = String(p.groupId ?? p.to ?? "");
|
|
581
|
-
const participants = Array.isArray(p.participants)
|
|
582
|
-
|
|
648
|
+
const participants = Array.isArray(p.participants)
|
|
649
|
+
? (p.participants as string[])
|
|
650
|
+
: [String(p.participant ?? "")].filter(Boolean);
|
|
651
|
+
if (!groupId || participants.length === 0)
|
|
652
|
+
throw new Error("waha-v2: demote-group-admin requires groupId and participants");
|
|
583
653
|
const result = await client.demoteGroupAdmin(session, groupId, participants);
|
|
584
654
|
return jsonResult({ ok: true, action: "demote-group-admin", groupId, result });
|
|
585
655
|
}
|
|
@@ -602,12 +672,14 @@ export const wahaV2Plugin: ChannelPlugin<ResolvedWahaV2Account> = {
|
|
|
602
672
|
const groupId = String(p.groupId ?? p.to ?? "");
|
|
603
673
|
if (action === "renameGroup") {
|
|
604
674
|
const subject = String(p.name ?? p.subject ?? "");
|
|
605
|
-
if (!groupId || !subject)
|
|
675
|
+
if (!groupId || !subject)
|
|
676
|
+
throw new Error("waha-v2: renameGroup requires groupId and name");
|
|
606
677
|
await client.updateGroupSubject(session, groupId, subject);
|
|
607
678
|
return jsonResult({ ok: true, action: "renameGroup", groupId });
|
|
608
679
|
}
|
|
609
680
|
const description = String(p.description ?? "");
|
|
610
|
-
if (!groupId || !description)
|
|
681
|
+
if (!groupId || !description)
|
|
682
|
+
throw new Error("waha-v2: update-group-description requires groupId and description");
|
|
611
683
|
await client.updateGroupDescription(session, groupId, description);
|
|
612
684
|
return jsonResult({ ok: true, action: "update-group-description", groupId });
|
|
613
685
|
}
|