@openclaw/zalouser 2026.2.25 → 2026.3.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.
- package/CHANGELOG.md +22 -0
- package/README.md +41 -147
- package/index.ts +1 -3
- package/package.json +4 -3
- package/src/accounts.test.ts +214 -0
- package/src/accounts.ts +28 -17
- package/src/channel.sendpayload.test.ts +117 -0
- package/src/channel.test.ts +123 -1
- package/src/channel.ts +244 -191
- package/src/config-schema.ts +1 -0
- package/src/group-policy.test.ts +49 -0
- package/src/group-policy.ts +78 -0
- package/src/message-sid.test.ts +66 -0
- package/src/message-sid.ts +80 -0
- package/src/monitor.account-scope.test.ts +123 -0
- package/src/monitor.group-gating.test.ts +216 -0
- package/src/monitor.ts +299 -228
- package/src/onboarding.ts +110 -142
- package/src/probe.test.ts +60 -0
- package/src/probe.ts +19 -12
- package/src/reaction.test.ts +19 -0
- package/src/reaction.ts +29 -0
- package/src/send.test.ts +116 -115
- package/src/send.ts +63 -117
- package/src/status-issues.test.ts +1 -15
- package/src/status-issues.ts +7 -26
- package/src/tool.test.ts +149 -0
- package/src/tool.ts +36 -54
- package/src/types.ts +52 -42
- package/src/zalo-js.ts +1401 -0
- package/src/zca-client.ts +249 -0
- package/src/zca-js-exports.d.ts +22 -0
- package/src/zca.ts +0 -198
package/src/send.test.ts
CHANGED
|
@@ -1,156 +1,157 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
2
|
import {
|
|
3
|
+
sendDeliveredZalouser,
|
|
3
4
|
sendImageZalouser,
|
|
4
5
|
sendLinkZalouser,
|
|
5
6
|
sendMessageZalouser,
|
|
6
|
-
|
|
7
|
+
sendReactionZalouser,
|
|
8
|
+
sendSeenZalouser,
|
|
9
|
+
sendTypingZalouser,
|
|
7
10
|
} from "./send.js";
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
import {
|
|
12
|
+
sendZaloDeliveredEvent,
|
|
13
|
+
sendZaloLink,
|
|
14
|
+
sendZaloReaction,
|
|
15
|
+
sendZaloSeenEvent,
|
|
16
|
+
sendZaloTextMessage,
|
|
17
|
+
sendZaloTypingEvent,
|
|
18
|
+
} from "./zalo-js.js";
|
|
19
|
+
|
|
20
|
+
vi.mock("./zalo-js.js", () => ({
|
|
21
|
+
sendZaloTextMessage: vi.fn(),
|
|
22
|
+
sendZaloLink: vi.fn(),
|
|
23
|
+
sendZaloTypingEvent: vi.fn(),
|
|
24
|
+
sendZaloReaction: vi.fn(),
|
|
25
|
+
sendZaloDeliveredEvent: vi.fn(),
|
|
26
|
+
sendZaloSeenEvent: vi.fn(),
|
|
12
27
|
}));
|
|
13
28
|
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
stdout,
|
|
21
|
-
stderr: "",
|
|
22
|
-
exitCode: 0,
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function failResult(stderr = "") {
|
|
27
|
-
return {
|
|
28
|
-
ok: false,
|
|
29
|
-
stdout: "",
|
|
30
|
-
stderr,
|
|
31
|
-
exitCode: 1,
|
|
32
|
-
};
|
|
33
|
-
}
|
|
29
|
+
const mockSendText = vi.mocked(sendZaloTextMessage);
|
|
30
|
+
const mockSendLink = vi.mocked(sendZaloLink);
|
|
31
|
+
const mockSendTyping = vi.mocked(sendZaloTypingEvent);
|
|
32
|
+
const mockSendReaction = vi.mocked(sendZaloReaction);
|
|
33
|
+
const mockSendDelivered = vi.mocked(sendZaloDeliveredEvent);
|
|
34
|
+
const mockSendSeen = vi.mocked(sendZaloSeenEvent);
|
|
34
35
|
|
|
35
36
|
describe("zalouser send helpers", () => {
|
|
36
37
|
beforeEach(() => {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
process.env.ZCA_PROFILE = originalZcaProfile;
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
delete process.env.ZCA_PROFILE;
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it("returns validation error when thread id is missing", async () => {
|
|
50
|
-
const result = await sendMessageZalouser("", "hello");
|
|
51
|
-
expect(result).toEqual({
|
|
52
|
-
ok: false,
|
|
53
|
-
error: "No threadId provided",
|
|
54
|
-
} satisfies ZalouserSendResult);
|
|
55
|
-
expect(mockRunZca).not.toHaveBeenCalled();
|
|
38
|
+
mockSendText.mockReset();
|
|
39
|
+
mockSendLink.mockReset();
|
|
40
|
+
mockSendTyping.mockReset();
|
|
41
|
+
mockSendReaction.mockReset();
|
|
42
|
+
mockSendDelivered.mockReset();
|
|
43
|
+
mockSendSeen.mockReset();
|
|
56
44
|
});
|
|
57
45
|
|
|
58
|
-
it("
|
|
59
|
-
|
|
46
|
+
it("delegates text send to JS transport", async () => {
|
|
47
|
+
mockSendText.mockResolvedValueOnce({ ok: true, messageId: "mid-1" });
|
|
60
48
|
|
|
61
|
-
const result = await sendMessageZalouser("
|
|
62
|
-
profile: "
|
|
49
|
+
const result = await sendMessageZalouser("thread-1", "hello", {
|
|
50
|
+
profile: "default",
|
|
63
51
|
isGroup: true,
|
|
64
52
|
});
|
|
65
53
|
|
|
66
|
-
expect(
|
|
67
|
-
profile: "
|
|
54
|
+
expect(mockSendText).toHaveBeenCalledWith("thread-1", "hello", {
|
|
55
|
+
profile: "default",
|
|
56
|
+
isGroup: true,
|
|
68
57
|
});
|
|
69
|
-
expect(result).toEqual({ ok: true, messageId: "mid-
|
|
58
|
+
expect(result).toEqual({ ok: true, messageId: "mid-1" });
|
|
70
59
|
});
|
|
71
60
|
|
|
72
|
-
it("
|
|
73
|
-
|
|
61
|
+
it("maps image helper to media send", async () => {
|
|
62
|
+
mockSendText.mockResolvedValueOnce({ ok: true, messageId: "mid-2" });
|
|
74
63
|
|
|
75
|
-
await
|
|
76
|
-
profile: "
|
|
77
|
-
|
|
78
|
-
isGroup:
|
|
64
|
+
await sendImageZalouser("thread-2", "https://example.com/a.png", {
|
|
65
|
+
profile: "p2",
|
|
66
|
+
caption: "cap",
|
|
67
|
+
isGroup: false,
|
|
79
68
|
});
|
|
80
69
|
|
|
81
|
-
expect(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
"https://cdn.example.com/video.mp4",
|
|
88
|
-
"-m",
|
|
89
|
-
"media caption",
|
|
90
|
-
"-g",
|
|
91
|
-
],
|
|
92
|
-
{ profile: "profile-b" },
|
|
93
|
-
);
|
|
70
|
+
expect(mockSendText).toHaveBeenCalledWith("thread-2", "cap", {
|
|
71
|
+
profile: "p2",
|
|
72
|
+
caption: "cap",
|
|
73
|
+
isGroup: false,
|
|
74
|
+
mediaUrl: "https://example.com/a.png",
|
|
75
|
+
});
|
|
94
76
|
});
|
|
95
77
|
|
|
96
|
-
it("
|
|
97
|
-
|
|
78
|
+
it("delegates link helper to JS transport", async () => {
|
|
79
|
+
mockSendLink.mockResolvedValueOnce({ ok: false, error: "boom" });
|
|
98
80
|
|
|
99
|
-
await
|
|
100
|
-
profile: "
|
|
101
|
-
|
|
81
|
+
const result = await sendLinkZalouser("thread-3", "https://openclaw.ai", {
|
|
82
|
+
profile: "p3",
|
|
83
|
+
isGroup: true,
|
|
102
84
|
});
|
|
103
85
|
|
|
104
|
-
expect(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
);
|
|
86
|
+
expect(mockSendLink).toHaveBeenCalledWith("thread-3", "https://openclaw.ai", {
|
|
87
|
+
profile: "p3",
|
|
88
|
+
isGroup: true,
|
|
89
|
+
});
|
|
90
|
+
expect(result).toEqual({ ok: false, error: "boom" });
|
|
108
91
|
});
|
|
109
92
|
|
|
110
|
-
it("
|
|
111
|
-
|
|
93
|
+
it("delegates typing helper to JS transport", async () => {
|
|
94
|
+
await sendTypingZalouser("thread-4", { profile: "p4", isGroup: true });
|
|
112
95
|
|
|
113
|
-
|
|
114
|
-
profile: "
|
|
115
|
-
caption: "caption text",
|
|
96
|
+
expect(mockSendTyping).toHaveBeenCalledWith("thread-4", {
|
|
97
|
+
profile: "p4",
|
|
116
98
|
isGroup: true,
|
|
117
99
|
});
|
|
118
|
-
|
|
119
|
-
expect(mockRunZca).toHaveBeenCalledWith(
|
|
120
|
-
[
|
|
121
|
-
"msg",
|
|
122
|
-
"image",
|
|
123
|
-
"thread-4",
|
|
124
|
-
"-u",
|
|
125
|
-
"https://cdn.example.com/img.png",
|
|
126
|
-
"-m",
|
|
127
|
-
"caption text",
|
|
128
|
-
"-g",
|
|
129
|
-
],
|
|
130
|
-
{ profile: "profile-d" },
|
|
131
|
-
);
|
|
132
|
-
expect(result).toEqual({ ok: false, error: "Failed to send image" });
|
|
133
100
|
});
|
|
134
101
|
|
|
135
|
-
it("
|
|
136
|
-
|
|
137
|
-
mockRunZca.mockResolvedValueOnce(okResult("abc123"));
|
|
102
|
+
it("delegates reaction helper to JS transport", async () => {
|
|
103
|
+
mockSendReaction.mockResolvedValueOnce({ ok: true });
|
|
138
104
|
|
|
139
|
-
const result = await
|
|
105
|
+
const result = await sendReactionZalouser({
|
|
106
|
+
threadId: "thread-5",
|
|
107
|
+
profile: "p5",
|
|
108
|
+
isGroup: true,
|
|
109
|
+
msgId: "100",
|
|
110
|
+
cliMsgId: "200",
|
|
111
|
+
emoji: "👍",
|
|
112
|
+
});
|
|
140
113
|
|
|
141
|
-
expect(
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
114
|
+
expect(mockSendReaction).toHaveBeenCalledWith({
|
|
115
|
+
profile: "p5",
|
|
116
|
+
threadId: "thread-5",
|
|
117
|
+
isGroup: true,
|
|
118
|
+
msgId: "100",
|
|
119
|
+
cliMsgId: "200",
|
|
120
|
+
emoji: "👍",
|
|
121
|
+
remove: undefined,
|
|
122
|
+
});
|
|
123
|
+
expect(result).toEqual({ ok: true, error: undefined });
|
|
146
124
|
});
|
|
147
125
|
|
|
148
|
-
it("
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
126
|
+
it("delegates delivered+seen helpers to JS transport", async () => {
|
|
127
|
+
mockSendDelivered.mockResolvedValueOnce();
|
|
128
|
+
mockSendSeen.mockResolvedValueOnce();
|
|
129
|
+
|
|
130
|
+
const message = {
|
|
131
|
+
msgId: "100",
|
|
132
|
+
cliMsgId: "200",
|
|
133
|
+
uidFrom: "1",
|
|
134
|
+
idTo: "2",
|
|
135
|
+
msgType: "webchat",
|
|
136
|
+
st: 1,
|
|
137
|
+
at: 0,
|
|
138
|
+
cmd: 0,
|
|
139
|
+
ts: "123",
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
await sendDeliveredZalouser({ profile: "p6", isGroup: true, message, isSeen: false });
|
|
143
|
+
await sendSeenZalouser({ profile: "p6", isGroup: true, message });
|
|
144
|
+
|
|
145
|
+
expect(mockSendDelivered).toHaveBeenCalledWith({
|
|
146
|
+
profile: "p6",
|
|
147
|
+
isGroup: true,
|
|
148
|
+
message,
|
|
149
|
+
isSeen: false,
|
|
150
|
+
});
|
|
151
|
+
expect(mockSendSeen).toHaveBeenCalledWith({
|
|
152
|
+
profile: "p6",
|
|
153
|
+
isGroup: true,
|
|
154
|
+
message,
|
|
154
155
|
});
|
|
155
156
|
});
|
|
156
157
|
});
|
package/src/send.ts
CHANGED
|
@@ -1,104 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
error?: string;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
function resolveProfile(options: ZalouserSendOptions): string {
|
|
17
|
-
return options.profile || process.env.ZCA_PROFILE || "default";
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function appendCaptionAndGroupFlags(args: string[], options: ZalouserSendOptions): void {
|
|
21
|
-
if (options.caption) {
|
|
22
|
-
args.push("-m", options.caption.slice(0, 2000));
|
|
23
|
-
}
|
|
24
|
-
if (options.isGroup) {
|
|
25
|
-
args.push("-g");
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async function runSendCommand(
|
|
30
|
-
args: string[],
|
|
31
|
-
profile: string,
|
|
32
|
-
fallbackError: string,
|
|
33
|
-
): Promise<ZalouserSendResult> {
|
|
34
|
-
try {
|
|
35
|
-
const result = await runZca(args, { profile });
|
|
36
|
-
if (result.ok) {
|
|
37
|
-
return { ok: true, messageId: extractMessageId(result.stdout) };
|
|
38
|
-
}
|
|
39
|
-
return { ok: false, error: result.stderr || fallbackError };
|
|
40
|
-
} catch (err) {
|
|
41
|
-
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
42
|
-
}
|
|
43
|
-
}
|
|
1
|
+
import type { ZaloEventMessage, ZaloSendOptions, ZaloSendResult } from "./types.js";
|
|
2
|
+
import {
|
|
3
|
+
sendZaloDeliveredEvent,
|
|
4
|
+
sendZaloLink,
|
|
5
|
+
sendZaloReaction,
|
|
6
|
+
sendZaloSeenEvent,
|
|
7
|
+
sendZaloTextMessage,
|
|
8
|
+
sendZaloTypingEvent,
|
|
9
|
+
} from "./zalo-js.js";
|
|
10
|
+
|
|
11
|
+
export type ZalouserSendOptions = ZaloSendOptions;
|
|
12
|
+
export type ZalouserSendResult = ZaloSendResult;
|
|
44
13
|
|
|
45
14
|
export async function sendMessageZalouser(
|
|
46
15
|
threadId: string,
|
|
47
16
|
text: string,
|
|
48
17
|
options: ZalouserSendOptions = {},
|
|
49
18
|
): Promise<ZalouserSendResult> {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (!threadId?.trim()) {
|
|
53
|
-
return { ok: false, error: "No threadId provided" };
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Handle media sending
|
|
57
|
-
if (options.mediaUrl) {
|
|
58
|
-
return sendMediaZalouser(threadId, options.mediaUrl, {
|
|
59
|
-
...options,
|
|
60
|
-
caption: text || options.caption,
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Send text message
|
|
65
|
-
const args = ["msg", "send", threadId.trim(), text.slice(0, 2000)];
|
|
66
|
-
if (options.isGroup) {
|
|
67
|
-
args.push("-g");
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return runSendCommand(args, profile, "Failed to send message");
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
async function sendMediaZalouser(
|
|
74
|
-
threadId: string,
|
|
75
|
-
mediaUrl: string,
|
|
76
|
-
options: ZalouserSendOptions = {},
|
|
77
|
-
): Promise<ZalouserSendResult> {
|
|
78
|
-
const profile = resolveProfile(options);
|
|
79
|
-
|
|
80
|
-
if (!threadId?.trim()) {
|
|
81
|
-
return { ok: false, error: "No threadId provided" };
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (!mediaUrl?.trim()) {
|
|
85
|
-
return { ok: false, error: "No media URL provided" };
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Determine media type from URL
|
|
89
|
-
const lowerUrl = mediaUrl.toLowerCase();
|
|
90
|
-
let command: string;
|
|
91
|
-
if (lowerUrl.match(/\.(mp4|mov|avi|webm)$/)) {
|
|
92
|
-
command = "video";
|
|
93
|
-
} else if (lowerUrl.match(/\.(mp3|wav|ogg|m4a)$/)) {
|
|
94
|
-
command = "voice";
|
|
95
|
-
} else {
|
|
96
|
-
command = "image";
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const args = ["msg", command, threadId.trim(), "-u", mediaUrl.trim()];
|
|
100
|
-
appendCaptionAndGroupFlags(args, options);
|
|
101
|
-
return runSendCommand(args, profile, `Failed to send ${command}`);
|
|
19
|
+
return await sendZaloTextMessage(threadId, text, options);
|
|
102
20
|
}
|
|
103
21
|
|
|
104
22
|
export async function sendImageZalouser(
|
|
@@ -106,10 +24,10 @@ export async function sendImageZalouser(
|
|
|
106
24
|
imageUrl: string,
|
|
107
25
|
options: ZalouserSendOptions = {},
|
|
108
26
|
): Promise<ZalouserSendResult> {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
27
|
+
return await sendZaloTextMessage(threadId, options.caption ?? "", {
|
|
28
|
+
...options,
|
|
29
|
+
mediaUrl: imageUrl,
|
|
30
|
+
});
|
|
113
31
|
}
|
|
114
32
|
|
|
115
33
|
export async function sendLinkZalouser(
|
|
@@ -117,25 +35,53 @@ export async function sendLinkZalouser(
|
|
|
117
35
|
url: string,
|
|
118
36
|
options: ZalouserSendOptions = {},
|
|
119
37
|
): Promise<ZalouserSendResult> {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
38
|
+
return await sendZaloLink(threadId, url, options);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function sendTypingZalouser(
|
|
42
|
+
threadId: string,
|
|
43
|
+
options: Pick<ZalouserSendOptions, "profile" | "isGroup"> = {},
|
|
44
|
+
): Promise<void> {
|
|
45
|
+
await sendZaloTypingEvent(threadId, options);
|
|
46
|
+
}
|
|
125
47
|
|
|
126
|
-
|
|
48
|
+
export async function sendReactionZalouser(params: {
|
|
49
|
+
threadId: string;
|
|
50
|
+
msgId: string;
|
|
51
|
+
cliMsgId: string;
|
|
52
|
+
emoji: string;
|
|
53
|
+
remove?: boolean;
|
|
54
|
+
profile?: string;
|
|
55
|
+
isGroup?: boolean;
|
|
56
|
+
}): Promise<ZalouserSendResult> {
|
|
57
|
+
const result = await sendZaloReaction({
|
|
58
|
+
profile: params.profile,
|
|
59
|
+
threadId: params.threadId,
|
|
60
|
+
isGroup: params.isGroup,
|
|
61
|
+
msgId: params.msgId,
|
|
62
|
+
cliMsgId: params.cliMsgId,
|
|
63
|
+
emoji: params.emoji,
|
|
64
|
+
remove: params.remove,
|
|
65
|
+
});
|
|
66
|
+
return {
|
|
67
|
+
ok: result.ok,
|
|
68
|
+
error: result.error,
|
|
69
|
+
};
|
|
127
70
|
}
|
|
128
71
|
|
|
129
|
-
function
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
72
|
+
export async function sendDeliveredZalouser(params: {
|
|
73
|
+
profile?: string;
|
|
74
|
+
isGroup?: boolean;
|
|
75
|
+
message: ZaloEventMessage;
|
|
76
|
+
isSeen?: boolean;
|
|
77
|
+
}): Promise<void> {
|
|
78
|
+
await sendZaloDeliveredEvent(params);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export async function sendSeenZalouser(params: {
|
|
82
|
+
profile?: string;
|
|
83
|
+
isGroup?: boolean;
|
|
84
|
+
message: ZaloEventMessage;
|
|
85
|
+
}): Promise<void> {
|
|
86
|
+
await sendZaloSeenEvent(params);
|
|
141
87
|
}
|
|
@@ -2,20 +2,6 @@ import { describe, expect, it } from "vitest";
|
|
|
2
2
|
import { collectZalouserStatusIssues } from "./status-issues.js";
|
|
3
3
|
|
|
4
4
|
describe("collectZalouserStatusIssues", () => {
|
|
5
|
-
it("flags missing zca when configured is false", () => {
|
|
6
|
-
const issues = collectZalouserStatusIssues([
|
|
7
|
-
{
|
|
8
|
-
accountId: "default",
|
|
9
|
-
enabled: true,
|
|
10
|
-
configured: false,
|
|
11
|
-
lastError: "zca CLI not found in PATH",
|
|
12
|
-
},
|
|
13
|
-
]);
|
|
14
|
-
expect(issues).toHaveLength(1);
|
|
15
|
-
expect(issues[0]?.kind).toBe("runtime");
|
|
16
|
-
expect(issues[0]?.message).toMatch(/zca CLI not found/i);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
5
|
it("flags missing auth when configured is false", () => {
|
|
20
6
|
const issues = collectZalouserStatusIssues([
|
|
21
7
|
{
|
|
@@ -49,7 +35,7 @@ describe("collectZalouserStatusIssues", () => {
|
|
|
49
35
|
accountId: "default",
|
|
50
36
|
enabled: false,
|
|
51
37
|
configured: false,
|
|
52
|
-
lastError: "
|
|
38
|
+
lastError: "not authenticated",
|
|
53
39
|
},
|
|
54
40
|
]);
|
|
55
41
|
expect(issues).toHaveLength(0);
|
package/src/status-issues.ts
CHANGED
|
@@ -27,14 +27,6 @@ function readZalouserAccountStatus(value: ChannelAccountSnapshot): ZalouserAccou
|
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
function isMissingZca(lastError?: string): boolean {
|
|
31
|
-
if (!lastError) {
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
const lower = lastError.toLowerCase();
|
|
35
|
-
return lower.includes("zca") && (lower.includes("not found") || lower.includes("enoent"));
|
|
36
|
-
}
|
|
37
|
-
|
|
38
30
|
export function collectZalouserStatusIssues(
|
|
39
31
|
accounts: ChannelAccountSnapshot[],
|
|
40
32
|
): ChannelStatusIssue[] {
|
|
@@ -51,26 +43,15 @@ export function collectZalouserStatusIssues(
|
|
|
51
43
|
}
|
|
52
44
|
|
|
53
45
|
const configured = account.configured === true;
|
|
54
|
-
const lastError = asString(account.lastError)?.trim();
|
|
55
46
|
|
|
56
47
|
if (!configured) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
});
|
|
65
|
-
} else {
|
|
66
|
-
issues.push({
|
|
67
|
-
channel: "zalouser",
|
|
68
|
-
accountId,
|
|
69
|
-
kind: "auth",
|
|
70
|
-
message: "Not authenticated (no zca session).",
|
|
71
|
-
fix: "Run: openclaw channels login --channel zalouser",
|
|
72
|
-
});
|
|
73
|
-
}
|
|
48
|
+
issues.push({
|
|
49
|
+
channel: "zalouser",
|
|
50
|
+
accountId,
|
|
51
|
+
kind: "auth",
|
|
52
|
+
message: "Not authenticated (no saved Zalo session).",
|
|
53
|
+
fix: "Run: openclaw channels login --channel zalouser",
|
|
54
|
+
});
|
|
74
55
|
continue;
|
|
75
56
|
}
|
|
76
57
|
|