mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 23:14:32 +00:00
fix(zalouser): normalize send and onboarding flows
This commit is contained in:
@@ -23,6 +23,45 @@ import { runZca, runZcaInteractive, checkZcaInstalled, parseJsonOutput } from ".
|
|||||||
|
|
||||||
const channel = "zalouser" as const;
|
const channel = "zalouser" as const;
|
||||||
|
|
||||||
|
function setZalouserAccountScopedConfig(
|
||||||
|
cfg: OpenClawConfig,
|
||||||
|
accountId: string,
|
||||||
|
defaultPatch: Record<string, unknown>,
|
||||||
|
accountPatch: Record<string, unknown> = defaultPatch,
|
||||||
|
): OpenClawConfig {
|
||||||
|
if (accountId === DEFAULT_ACCOUNT_ID) {
|
||||||
|
return {
|
||||||
|
...cfg,
|
||||||
|
channels: {
|
||||||
|
...cfg.channels,
|
||||||
|
zalouser: {
|
||||||
|
...cfg.channels?.zalouser,
|
||||||
|
enabled: true,
|
||||||
|
...defaultPatch,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as OpenClawConfig;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...cfg,
|
||||||
|
channels: {
|
||||||
|
...cfg.channels,
|
||||||
|
zalouser: {
|
||||||
|
...cfg.channels?.zalouser,
|
||||||
|
enabled: true,
|
||||||
|
accounts: {
|
||||||
|
...cfg.channels?.zalouser?.accounts,
|
||||||
|
[accountId]: {
|
||||||
|
...cfg.channels?.zalouser?.accounts?.[accountId],
|
||||||
|
enabled: cfg.channels?.zalouser?.accounts?.[accountId]?.enabled ?? true,
|
||||||
|
...accountPatch,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as OpenClawConfig;
|
||||||
|
}
|
||||||
|
|
||||||
function setZalouserDmPolicy(
|
function setZalouserDmPolicy(
|
||||||
cfg: OpenClawConfig,
|
cfg: OpenClawConfig,
|
||||||
dmPolicy: "pairing" | "allowlist" | "open" | "disabled",
|
dmPolicy: "pairing" | "allowlist" | "open" | "disabled",
|
||||||
@@ -123,40 +162,10 @@ async function promptZalouserAllowFrom(params: {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const unique = mergeAllowFromEntries(existingAllowFrom, results.filter(Boolean) as string[]);
|
const unique = mergeAllowFromEntries(existingAllowFrom, results.filter(Boolean) as string[]);
|
||||||
if (accountId === DEFAULT_ACCOUNT_ID) {
|
return setZalouserAccountScopedConfig(cfg, accountId, {
|
||||||
return {
|
dmPolicy: "allowlist",
|
||||||
...cfg,
|
allowFrom: unique,
|
||||||
channels: {
|
});
|
||||||
...cfg.channels,
|
|
||||||
zalouser: {
|
|
||||||
...cfg.channels?.zalouser,
|
|
||||||
enabled: true,
|
|
||||||
dmPolicy: "allowlist",
|
|
||||||
allowFrom: unique,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as OpenClawConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...cfg,
|
|
||||||
channels: {
|
|
||||||
...cfg.channels,
|
|
||||||
zalouser: {
|
|
||||||
...cfg.channels?.zalouser,
|
|
||||||
enabled: true,
|
|
||||||
accounts: {
|
|
||||||
...cfg.channels?.zalouser?.accounts,
|
|
||||||
[accountId]: {
|
|
||||||
...cfg.channels?.zalouser?.accounts?.[accountId],
|
|
||||||
enabled: cfg.channels?.zalouser?.accounts?.[accountId]?.enabled ?? true,
|
|
||||||
dmPolicy: "allowlist",
|
|
||||||
allowFrom: unique,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as OpenClawConfig;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,37 +174,9 @@ function setZalouserGroupPolicy(
|
|||||||
accountId: string,
|
accountId: string,
|
||||||
groupPolicy: "open" | "allowlist" | "disabled",
|
groupPolicy: "open" | "allowlist" | "disabled",
|
||||||
): OpenClawConfig {
|
): OpenClawConfig {
|
||||||
if (accountId === DEFAULT_ACCOUNT_ID) {
|
return setZalouserAccountScopedConfig(cfg, accountId, {
|
||||||
return {
|
groupPolicy,
|
||||||
...cfg,
|
});
|
||||||
channels: {
|
|
||||||
...cfg.channels,
|
|
||||||
zalouser: {
|
|
||||||
...cfg.channels?.zalouser,
|
|
||||||
enabled: true,
|
|
||||||
groupPolicy,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as OpenClawConfig;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...cfg,
|
|
||||||
channels: {
|
|
||||||
...cfg.channels,
|
|
||||||
zalouser: {
|
|
||||||
...cfg.channels?.zalouser,
|
|
||||||
enabled: true,
|
|
||||||
accounts: {
|
|
||||||
...cfg.channels?.zalouser?.accounts,
|
|
||||||
[accountId]: {
|
|
||||||
...cfg.channels?.zalouser?.accounts?.[accountId],
|
|
||||||
enabled: cfg.channels?.zalouser?.accounts?.[accountId]?.enabled ?? true,
|
|
||||||
groupPolicy,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as OpenClawConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setZalouserGroupAllowlist(
|
function setZalouserGroupAllowlist(
|
||||||
@@ -204,37 +185,9 @@ function setZalouserGroupAllowlist(
|
|||||||
groupKeys: string[],
|
groupKeys: string[],
|
||||||
): OpenClawConfig {
|
): OpenClawConfig {
|
||||||
const groups = Object.fromEntries(groupKeys.map((key) => [key, { allow: true }]));
|
const groups = Object.fromEntries(groupKeys.map((key) => [key, { allow: true }]));
|
||||||
if (accountId === DEFAULT_ACCOUNT_ID) {
|
return setZalouserAccountScopedConfig(cfg, accountId, {
|
||||||
return {
|
groups,
|
||||||
...cfg,
|
});
|
||||||
channels: {
|
|
||||||
...cfg.channels,
|
|
||||||
zalouser: {
|
|
||||||
...cfg.channels?.zalouser,
|
|
||||||
enabled: true,
|
|
||||||
groups,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as OpenClawConfig;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...cfg,
|
|
||||||
channels: {
|
|
||||||
...cfg.channels,
|
|
||||||
zalouser: {
|
|
||||||
...cfg.channels?.zalouser,
|
|
||||||
enabled: true,
|
|
||||||
accounts: {
|
|
||||||
...cfg.channels?.zalouser?.accounts,
|
|
||||||
[accountId]: {
|
|
||||||
...cfg.channels?.zalouser?.accounts?.[accountId],
|
|
||||||
enabled: cfg.channels?.zalouser?.accounts?.[accountId]?.enabled ?? true,
|
|
||||||
groups,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as OpenClawConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resolveZalouserGroups(params: {
|
async function resolveZalouserGroups(params: {
|
||||||
@@ -403,38 +356,12 @@ export const zalouserOnboardingAdapter: ChannelOnboardingAdapter = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Enable the channel
|
// Enable the channel
|
||||||
if (accountId === DEFAULT_ACCOUNT_ID) {
|
next = setZalouserAccountScopedConfig(
|
||||||
next = {
|
next,
|
||||||
...next,
|
accountId,
|
||||||
channels: {
|
{ profile: account.profile !== "default" ? account.profile : undefined },
|
||||||
...next.channels,
|
{ profile: account.profile, enabled: true },
|
||||||
zalouser: {
|
);
|
||||||
...next.channels?.zalouser,
|
|
||||||
enabled: true,
|
|
||||||
profile: account.profile !== "default" ? account.profile : undefined,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as OpenClawConfig;
|
|
||||||
} else {
|
|
||||||
next = {
|
|
||||||
...next,
|
|
||||||
channels: {
|
|
||||||
...next.channels,
|
|
||||||
zalouser: {
|
|
||||||
...next.channels?.zalouser,
|
|
||||||
enabled: true,
|
|
||||||
accounts: {
|
|
||||||
...next.channels?.zalouser?.accounts,
|
|
||||||
[accountId]: {
|
|
||||||
...next.channels?.zalouser?.accounts?.[accountId],
|
|
||||||
enabled: true,
|
|
||||||
profile: account.profile,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as OpenClawConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (forceAllowFrom) {
|
if (forceAllowFrom) {
|
||||||
next = await promptZalouserAllowFrom({
|
next = await promptZalouserAllowFrom({
|
||||||
|
|||||||
156
extensions/zalouser/src/send.test.ts
Normal file
156
extensions/zalouser/src/send.test.ts
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
import {
|
||||||
|
sendImageZalouser,
|
||||||
|
sendLinkZalouser,
|
||||||
|
sendMessageZalouser,
|
||||||
|
type ZalouserSendResult,
|
||||||
|
} from "./send.js";
|
||||||
|
import { runZca } from "./zca.js";
|
||||||
|
|
||||||
|
vi.mock("./zca.js", () => ({
|
||||||
|
runZca: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const mockRunZca = vi.mocked(runZca);
|
||||||
|
const originalZcaProfile = process.env.ZCA_PROFILE;
|
||||||
|
|
||||||
|
function okResult(stdout = "message_id: msg-1") {
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
stdout,
|
||||||
|
stderr: "",
|
||||||
|
exitCode: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function failResult(stderr = "") {
|
||||||
|
return {
|
||||||
|
ok: false,
|
||||||
|
stdout: "",
|
||||||
|
stderr,
|
||||||
|
exitCode: 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("zalouser send helpers", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockRunZca.mockReset();
|
||||||
|
delete process.env.ZCA_PROFILE;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
if (originalZcaProfile) {
|
||||||
|
process.env.ZCA_PROFILE = originalZcaProfile;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delete process.env.ZCA_PROFILE;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns validation error when thread id is missing", async () => {
|
||||||
|
const result = await sendMessageZalouser("", "hello");
|
||||||
|
expect(result).toEqual({
|
||||||
|
ok: false,
|
||||||
|
error: "No threadId provided",
|
||||||
|
} satisfies ZalouserSendResult);
|
||||||
|
expect(mockRunZca).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("builds text send command with truncation and group flag", async () => {
|
||||||
|
mockRunZca.mockResolvedValueOnce(okResult("message id: mid-123"));
|
||||||
|
|
||||||
|
const result = await sendMessageZalouser(" thread-1 ", "x".repeat(2200), {
|
||||||
|
profile: "profile-a",
|
||||||
|
isGroup: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mockRunZca).toHaveBeenCalledWith(["msg", "send", "thread-1", "x".repeat(2000), "-g"], {
|
||||||
|
profile: "profile-a",
|
||||||
|
});
|
||||||
|
expect(result).toEqual({ ok: true, messageId: "mid-123" });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("routes media sends from sendMessage and keeps text as caption", async () => {
|
||||||
|
mockRunZca.mockResolvedValueOnce(okResult());
|
||||||
|
|
||||||
|
await sendMessageZalouser("thread-2", "media caption", {
|
||||||
|
profile: "profile-b",
|
||||||
|
mediaUrl: "https://cdn.example.com/video.mp4",
|
||||||
|
isGroup: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mockRunZca).toHaveBeenCalledWith(
|
||||||
|
[
|
||||||
|
"msg",
|
||||||
|
"video",
|
||||||
|
"thread-2",
|
||||||
|
"-u",
|
||||||
|
"https://cdn.example.com/video.mp4",
|
||||||
|
"-m",
|
||||||
|
"media caption",
|
||||||
|
"-g",
|
||||||
|
],
|
||||||
|
{ profile: "profile-b" },
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("maps audio media to voice command", async () => {
|
||||||
|
mockRunZca.mockResolvedValueOnce(okResult());
|
||||||
|
|
||||||
|
await sendMessageZalouser("thread-3", "", {
|
||||||
|
profile: "profile-c",
|
||||||
|
mediaUrl: "https://cdn.example.com/clip.mp3",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mockRunZca).toHaveBeenCalledWith(
|
||||||
|
["msg", "voice", "thread-3", "-u", "https://cdn.example.com/clip.mp3"],
|
||||||
|
{ profile: "profile-c" },
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("builds image command with caption and returns fallback error", async () => {
|
||||||
|
mockRunZca.mockResolvedValueOnce(failResult(""));
|
||||||
|
|
||||||
|
const result = await sendImageZalouser("thread-4", " https://cdn.example.com/img.png ", {
|
||||||
|
profile: "profile-d",
|
||||||
|
caption: "caption text",
|
||||||
|
isGroup: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mockRunZca).toHaveBeenCalledWith(
|
||||||
|
[
|
||||||
|
"msg",
|
||||||
|
"image",
|
||||||
|
"thread-4",
|
||||||
|
"-u",
|
||||||
|
"https://cdn.example.com/img.png",
|
||||||
|
"-m",
|
||||||
|
"caption text",
|
||||||
|
"-g",
|
||||||
|
],
|
||||||
|
{ profile: "profile-d" },
|
||||||
|
);
|
||||||
|
expect(result).toEqual({ ok: false, error: "Failed to send image" });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses env profile fallback and builds link command", async () => {
|
||||||
|
process.env.ZCA_PROFILE = "env-profile";
|
||||||
|
mockRunZca.mockResolvedValueOnce(okResult("abc123"));
|
||||||
|
|
||||||
|
const result = await sendLinkZalouser("thread-5", " https://openclaw.ai ", { isGroup: true });
|
||||||
|
|
||||||
|
expect(mockRunZca).toHaveBeenCalledWith(
|
||||||
|
["msg", "link", "thread-5", "https://openclaw.ai", "-g"],
|
||||||
|
{ profile: "env-profile" },
|
||||||
|
);
|
||||||
|
expect(result).toEqual({ ok: true, messageId: "abc123" });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns caught command errors", async () => {
|
||||||
|
mockRunZca.mockRejectedValueOnce(new Error("zca unavailable"));
|
||||||
|
|
||||||
|
await expect(sendLinkZalouser("thread-6", "https://openclaw.ai")).resolves.toEqual({
|
||||||
|
ok: false,
|
||||||
|
error: "zca unavailable",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -13,12 +13,41 @@ export type ZalouserSendResult = {
|
|||||||
error?: string;
|
error?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function resolveProfile(options: ZalouserSendOptions): string {
|
||||||
|
return options.profile || process.env.ZCA_PROFILE || "default";
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendCaptionAndGroupFlags(args: string[], options: ZalouserSendOptions): void {
|
||||||
|
if (options.caption) {
|
||||||
|
args.push("-m", options.caption.slice(0, 2000));
|
||||||
|
}
|
||||||
|
if (options.isGroup) {
|
||||||
|
args.push("-g");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runSendCommand(
|
||||||
|
args: string[],
|
||||||
|
profile: string,
|
||||||
|
fallbackError: string,
|
||||||
|
): Promise<ZalouserSendResult> {
|
||||||
|
try {
|
||||||
|
const result = await runZca(args, { profile });
|
||||||
|
if (result.ok) {
|
||||||
|
return { ok: true, messageId: extractMessageId(result.stdout) };
|
||||||
|
}
|
||||||
|
return { ok: false, error: result.stderr || fallbackError };
|
||||||
|
} catch (err) {
|
||||||
|
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function sendMessageZalouser(
|
export async function sendMessageZalouser(
|
||||||
threadId: string,
|
threadId: string,
|
||||||
text: string,
|
text: string,
|
||||||
options: ZalouserSendOptions = {},
|
options: ZalouserSendOptions = {},
|
||||||
): Promise<ZalouserSendResult> {
|
): Promise<ZalouserSendResult> {
|
||||||
const profile = options.profile || process.env.ZCA_PROFILE || "default";
|
const profile = resolveProfile(options);
|
||||||
|
|
||||||
if (!threadId?.trim()) {
|
if (!threadId?.trim()) {
|
||||||
return { ok: false, error: "No threadId provided" };
|
return { ok: false, error: "No threadId provided" };
|
||||||
@@ -38,17 +67,7 @@ export async function sendMessageZalouser(
|
|||||||
args.push("-g");
|
args.push("-g");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
return runSendCommand(args, profile, "Failed to send message");
|
||||||
const result = await runZca(args, { profile });
|
|
||||||
|
|
||||||
if (result.ok) {
|
|
||||||
return { ok: true, messageId: extractMessageId(result.stdout) };
|
|
||||||
}
|
|
||||||
|
|
||||||
return { ok: false, error: result.stderr || "Failed to send message" };
|
|
||||||
} catch (err) {
|
|
||||||
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sendMediaZalouser(
|
async function sendMediaZalouser(
|
||||||
@@ -56,7 +75,7 @@ async function sendMediaZalouser(
|
|||||||
mediaUrl: string,
|
mediaUrl: string,
|
||||||
options: ZalouserSendOptions = {},
|
options: ZalouserSendOptions = {},
|
||||||
): Promise<ZalouserSendResult> {
|
): Promise<ZalouserSendResult> {
|
||||||
const profile = options.profile || process.env.ZCA_PROFILE || "default";
|
const profile = resolveProfile(options);
|
||||||
|
|
||||||
if (!threadId?.trim()) {
|
if (!threadId?.trim()) {
|
||||||
return { ok: false, error: "No threadId provided" };
|
return { ok: false, error: "No threadId provided" };
|
||||||
@@ -78,24 +97,8 @@ async function sendMediaZalouser(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const args = ["msg", command, threadId.trim(), "-u", mediaUrl.trim()];
|
const args = ["msg", command, threadId.trim(), "-u", mediaUrl.trim()];
|
||||||
if (options.caption) {
|
appendCaptionAndGroupFlags(args, options);
|
||||||
args.push("-m", options.caption.slice(0, 2000));
|
return runSendCommand(args, profile, `Failed to send ${command}`);
|
||||||
}
|
|
||||||
if (options.isGroup) {
|
|
||||||
args.push("-g");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result = await runZca(args, { profile });
|
|
||||||
|
|
||||||
if (result.ok) {
|
|
||||||
return { ok: true, messageId: extractMessageId(result.stdout) };
|
|
||||||
}
|
|
||||||
|
|
||||||
return { ok: false, error: result.stderr || `Failed to send ${command}` };
|
|
||||||
} catch (err) {
|
|
||||||
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function sendImageZalouser(
|
export async function sendImageZalouser(
|
||||||
@@ -103,24 +106,10 @@ export async function sendImageZalouser(
|
|||||||
imageUrl: string,
|
imageUrl: string,
|
||||||
options: ZalouserSendOptions = {},
|
options: ZalouserSendOptions = {},
|
||||||
): Promise<ZalouserSendResult> {
|
): Promise<ZalouserSendResult> {
|
||||||
const profile = options.profile || process.env.ZCA_PROFILE || "default";
|
const profile = resolveProfile(options);
|
||||||
const args = ["msg", "image", threadId.trim(), "-u", imageUrl.trim()];
|
const args = ["msg", "image", threadId.trim(), "-u", imageUrl.trim()];
|
||||||
if (options.caption) {
|
appendCaptionAndGroupFlags(args, options);
|
||||||
args.push("-m", options.caption.slice(0, 2000));
|
return runSendCommand(args, profile, "Failed to send image");
|
||||||
}
|
|
||||||
if (options.isGroup) {
|
|
||||||
args.push("-g");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result = await runZca(args, { profile });
|
|
||||||
if (result.ok) {
|
|
||||||
return { ok: true, messageId: extractMessageId(result.stdout) };
|
|
||||||
}
|
|
||||||
return { ok: false, error: result.stderr || "Failed to send image" };
|
|
||||||
} catch (err) {
|
|
||||||
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function sendLinkZalouser(
|
export async function sendLinkZalouser(
|
||||||
@@ -128,21 +117,13 @@ export async function sendLinkZalouser(
|
|||||||
url: string,
|
url: string,
|
||||||
options: ZalouserSendOptions = {},
|
options: ZalouserSendOptions = {},
|
||||||
): Promise<ZalouserSendResult> {
|
): Promise<ZalouserSendResult> {
|
||||||
const profile = options.profile || process.env.ZCA_PROFILE || "default";
|
const profile = resolveProfile(options);
|
||||||
const args = ["msg", "link", threadId.trim(), url.trim()];
|
const args = ["msg", "link", threadId.trim(), url.trim()];
|
||||||
if (options.isGroup) {
|
if (options.isGroup) {
|
||||||
args.push("-g");
|
args.push("-g");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
return runSendCommand(args, profile, "Failed to send link");
|
||||||
const result = await runZca(args, { profile });
|
|
||||||
if (result.ok) {
|
|
||||||
return { ok: true, messageId: extractMessageId(result.stdout) };
|
|
||||||
}
|
|
||||||
return { ok: false, error: result.stderr || "Failed to send link" };
|
|
||||||
} catch (err) {
|
|
||||||
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractMessageId(stdout: string): string | undefined {
|
function extractMessageId(stdout: string): string | undefined {
|
||||||
|
|||||||
@@ -68,35 +68,30 @@ export type ListenOptions = CommonOptions & {
|
|||||||
prefix?: string;
|
prefix?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ZalouserAccountConfig = {
|
type ZalouserToolConfig = { allow?: string[]; deny?: string[] };
|
||||||
|
|
||||||
|
type ZalouserGroupConfig = {
|
||||||
|
allow?: boolean;
|
||||||
|
enabled?: boolean;
|
||||||
|
tools?: ZalouserToolConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ZalouserSharedConfig = {
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
name?: string;
|
name?: string;
|
||||||
profile?: string;
|
profile?: string;
|
||||||
dmPolicy?: "pairing" | "allowlist" | "open" | "disabled";
|
dmPolicy?: "pairing" | "allowlist" | "open" | "disabled";
|
||||||
allowFrom?: Array<string | number>;
|
allowFrom?: Array<string | number>;
|
||||||
groupPolicy?: "open" | "allowlist" | "disabled";
|
groupPolicy?: "open" | "allowlist" | "disabled";
|
||||||
groups?: Record<
|
groups?: Record<string, ZalouserGroupConfig>;
|
||||||
string,
|
|
||||||
{ allow?: boolean; enabled?: boolean; tools?: { allow?: string[]; deny?: string[] } }
|
|
||||||
>;
|
|
||||||
messagePrefix?: string;
|
messagePrefix?: string;
|
||||||
responsePrefix?: string;
|
responsePrefix?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ZalouserConfig = {
|
export type ZalouserAccountConfig = ZalouserSharedConfig;
|
||||||
enabled?: boolean;
|
|
||||||
name?: string;
|
export type ZalouserConfig = ZalouserSharedConfig & {
|
||||||
profile?: string;
|
|
||||||
defaultAccount?: string;
|
defaultAccount?: string;
|
||||||
dmPolicy?: "pairing" | "allowlist" | "open" | "disabled";
|
|
||||||
allowFrom?: Array<string | number>;
|
|
||||||
groupPolicy?: "open" | "allowlist" | "disabled";
|
|
||||||
groups?: Record<
|
|
||||||
string,
|
|
||||||
{ allow?: boolean; enabled?: boolean; tools?: { allow?: string[]; deny?: string[] } }
|
|
||||||
>;
|
|
||||||
messagePrefix?: string;
|
|
||||||
responsePrefix?: string;
|
|
||||||
accounts?: Record<string, ZalouserAccountConfig>;
|
accounts?: Record<string, ZalouserAccountConfig>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user