mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-25 03:04:29 -04:00
chore: Enable "curly" rule to avoid single-statement if confusion/errors.
This commit is contained in:
@@ -12,19 +12,25 @@ export type ResolvedIMessageAccount = {
|
||||
|
||||
function listConfiguredAccountIds(cfg: OpenClawConfig): string[] {
|
||||
const accounts = cfg.channels?.imessage?.accounts;
|
||||
if (!accounts || typeof accounts !== "object") return [];
|
||||
if (!accounts || typeof accounts !== "object") {
|
||||
return [];
|
||||
}
|
||||
return Object.keys(accounts).filter(Boolean);
|
||||
}
|
||||
|
||||
export function listIMessageAccountIds(cfg: OpenClawConfig): string[] {
|
||||
const ids = listConfiguredAccountIds(cfg);
|
||||
if (ids.length === 0) return [DEFAULT_ACCOUNT_ID];
|
||||
if (ids.length === 0) {
|
||||
return [DEFAULT_ACCOUNT_ID];
|
||||
}
|
||||
return ids.toSorted((a, b) => a.localeCompare(b));
|
||||
}
|
||||
|
||||
export function resolveDefaultIMessageAccountId(cfg: OpenClawConfig): string {
|
||||
const ids = listIMessageAccountIds(cfg);
|
||||
if (ids.includes(DEFAULT_ACCOUNT_ID)) return DEFAULT_ACCOUNT_ID;
|
||||
if (ids.includes(DEFAULT_ACCOUNT_ID)) {
|
||||
return DEFAULT_ACCOUNT_ID;
|
||||
}
|
||||
return ids[0] ?? DEFAULT_ACCOUNT_ID;
|
||||
}
|
||||
|
||||
@@ -33,7 +39,9 @@ function resolveAccountConfig(
|
||||
accountId: string,
|
||||
): IMessageAccountConfig | undefined {
|
||||
const accounts = cfg.channels?.imessage?.accounts;
|
||||
if (!accounts || typeof accounts !== "object") return undefined;
|
||||
if (!accounts || typeof accounts !== "object") {
|
||||
return undefined;
|
||||
}
|
||||
return accounts[accountId] as IMessageAccountConfig | undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,9 @@ export class IMessageRpcClient {
|
||||
}
|
||||
|
||||
async start(): Promise<void> {
|
||||
if (this.child) return;
|
||||
if (this.child) {
|
||||
return;
|
||||
}
|
||||
const args = ["rpc"];
|
||||
if (this.dbPath) {
|
||||
args.push("--db", this.dbPath);
|
||||
@@ -73,14 +75,18 @@ export class IMessageRpcClient {
|
||||
|
||||
this.reader.on("line", (line) => {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed) return;
|
||||
if (!trimmed) {
|
||||
return;
|
||||
}
|
||||
this.handleLine(trimmed);
|
||||
});
|
||||
|
||||
child.stderr?.on("data", (chunk) => {
|
||||
const lines = chunk.toString().split(/\r?\n/);
|
||||
for (const line of lines) {
|
||||
if (!line.trim()) continue;
|
||||
if (!line.trim()) {
|
||||
continue;
|
||||
}
|
||||
this.runtime?.error?.(`imsg rpc: ${line.trim()}`);
|
||||
}
|
||||
});
|
||||
@@ -102,7 +108,9 @@ export class IMessageRpcClient {
|
||||
}
|
||||
|
||||
async stop(): Promise<void> {
|
||||
if (!this.child) return;
|
||||
if (!this.child) {
|
||||
return;
|
||||
}
|
||||
this.reader?.close();
|
||||
this.reader = null;
|
||||
this.child.stdin?.end();
|
||||
@@ -113,7 +121,9 @@ export class IMessageRpcClient {
|
||||
this.closed,
|
||||
new Promise<void>((resolve) => {
|
||||
setTimeout(() => {
|
||||
if (!child.killed) child.kill("SIGTERM");
|
||||
if (!child.killed) {
|
||||
child.kill("SIGTERM");
|
||||
}
|
||||
resolve();
|
||||
}, 500);
|
||||
}),
|
||||
@@ -175,8 +185,12 @@ export class IMessageRpcClient {
|
||||
if (parsed.id !== undefined && parsed.id !== null) {
|
||||
const key = String(parsed.id);
|
||||
const pending = this.pending.get(key);
|
||||
if (!pending) return;
|
||||
if (pending.timer) clearTimeout(pending.timer);
|
||||
if (!pending) {
|
||||
return;
|
||||
}
|
||||
if (pending.timer) {
|
||||
clearTimeout(pending.timer);
|
||||
}
|
||||
this.pending.delete(key);
|
||||
|
||||
if (parsed.error) {
|
||||
@@ -184,11 +198,15 @@ export class IMessageRpcClient {
|
||||
const details = parsed.error.data;
|
||||
const code = parsed.error.code;
|
||||
const suffixes = [] as string[];
|
||||
if (typeof code === "number") suffixes.push(`code=${code}`);
|
||||
if (typeof code === "number") {
|
||||
suffixes.push(`code=${code}`);
|
||||
}
|
||||
if (details !== undefined) {
|
||||
const detailText =
|
||||
typeof details === "string" ? details : JSON.stringify(details, null, 2);
|
||||
if (detailText) suffixes.push(detailText);
|
||||
if (detailText) {
|
||||
suffixes.push(detailText);
|
||||
}
|
||||
}
|
||||
const msg = suffixes.length > 0 ? `${baseMessage}: ${suffixes.join(" ")}` : baseMessage;
|
||||
pending.reject(new Error(msg));
|
||||
@@ -208,7 +226,9 @@ export class IMessageRpcClient {
|
||||
|
||||
private failAll(err: Error) {
|
||||
for (const [key, pending] of this.pending.entries()) {
|
||||
if (pending.timer) clearTimeout(pending.timer);
|
||||
if (pending.timer) {
|
||||
clearTimeout(pending.timer);
|
||||
}
|
||||
pending.reject(err);
|
||||
this.pending.delete(key);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,9 @@ const flush = () => new Promise((resolve) => setTimeout(resolve, 0));
|
||||
|
||||
async function waitForSubscribe() {
|
||||
for (let i = 0; i < 5; i += 1) {
|
||||
if (requestMock.mock.calls.some((call) => call[0] === "watch.subscribe")) return;
|
||||
if (requestMock.mock.calls.some((call) => call[0] === "watch.subscribe")) {
|
||||
return;
|
||||
}
|
||||
await flush();
|
||||
}
|
||||
}
|
||||
@@ -84,7 +86,9 @@ beforeEach(() => {
|
||||
},
|
||||
};
|
||||
requestMock.mockReset().mockImplementation((method: string) => {
|
||||
if (method === "watch.subscribe") return Promise.resolve({ subscription: 1 });
|
||||
if (method === "watch.subscribe") {
|
||||
return Promise.resolve({ subscription: 1 });
|
||||
}
|
||||
return Promise.resolve({});
|
||||
});
|
||||
stopMock.mockReset().mockResolvedValue(undefined);
|
||||
|
||||
@@ -64,7 +64,9 @@ const flush = () => new Promise((resolve) => setTimeout(resolve, 0));
|
||||
|
||||
async function waitForSubscribe() {
|
||||
for (let i = 0; i < 5; i += 1) {
|
||||
if (requestMock.mock.calls.some((call) => call[0] === "watch.subscribe")) return;
|
||||
if (requestMock.mock.calls.some((call) => call[0] === "watch.subscribe")) {
|
||||
return;
|
||||
}
|
||||
await flush();
|
||||
}
|
||||
}
|
||||
@@ -84,7 +86,9 @@ beforeEach(() => {
|
||||
},
|
||||
};
|
||||
requestMock.mockReset().mockImplementation((method: string) => {
|
||||
if (method === "watch.subscribe") return Promise.resolve({ subscription: 1 });
|
||||
if (method === "watch.subscribe") {
|
||||
return Promise.resolve({ subscription: 1 });
|
||||
}
|
||||
return Promise.resolve({});
|
||||
});
|
||||
stopMock.mockReset().mockResolvedValue(undefined);
|
||||
@@ -133,8 +137,12 @@ describe("monitorIMessageProvider", () => {
|
||||
|
||||
it("does not trigger unhandledRejection when aborting during shutdown", async () => {
|
||||
requestMock.mockImplementation((method: string) => {
|
||||
if (method === "watch.subscribe") return Promise.resolve({ subscription: 1 });
|
||||
if (method === "watch.unsubscribe") return Promise.reject(new Error("imsg rpc closed"));
|
||||
if (method === "watch.subscribe") {
|
||||
return Promise.resolve({ subscription: 1 });
|
||||
}
|
||||
if (method === "watch.unsubscribe") {
|
||||
return Promise.reject(new Error("imsg rpc closed"));
|
||||
}
|
||||
return Promise.resolve({});
|
||||
});
|
||||
|
||||
|
||||
@@ -28,7 +28,9 @@ export async function deliverReplies(params: {
|
||||
const mediaList = payload.mediaUrls ?? (payload.mediaUrl ? [payload.mediaUrl] : []);
|
||||
const rawText = payload.text ?? "";
|
||||
const text = convertMarkdownTables(rawText, tableMode);
|
||||
if (!text && mediaList.length === 0) continue;
|
||||
if (!text && mediaList.length === 0) {
|
||||
continue;
|
||||
}
|
||||
if (mediaList.length === 0) {
|
||||
for (const chunk of chunkTextWithMode(text, textLimit, chunkMode)) {
|
||||
await sendMessageIMessage(target, chunk, {
|
||||
|
||||
@@ -72,7 +72,9 @@ async function detectRemoteHostFromCliPath(cliPath: string): Promise<string | un
|
||||
|
||||
// Match user@host pattern first (e.g., openclaw@192.168.64.3)
|
||||
const userHostMatch = content.match(/\bssh\b[^\n]*?\s+([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+)/);
|
||||
if (userHostMatch) return userHostMatch[1];
|
||||
if (userHostMatch) {
|
||||
return userHostMatch[1];
|
||||
}
|
||||
|
||||
// Fallback: match host-only before imsg command (e.g., ssh -T mac-mini imsg)
|
||||
const hostOnlyMatch = content.match(/\bssh\b[^\n]*?\s+([a-zA-Z][a-zA-Z0-9._-]*)\s+\S*\bimsg\b/);
|
||||
@@ -93,13 +95,17 @@ function normalizeReplyField(value: unknown): string | undefined {
|
||||
const trimmed = value.trim();
|
||||
return trimmed ? trimmed : undefined;
|
||||
}
|
||||
if (typeof value === "number") return String(value);
|
||||
if (typeof value === "number") {
|
||||
return String(value);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function describeReplyContext(message: IMessagePayload): IMessageReplyContext | null {
|
||||
const body = normalizeReplyField(message.reply_to_text);
|
||||
if (!body) return null;
|
||||
if (!body) {
|
||||
return null;
|
||||
}
|
||||
const id = normalizeReplyField(message.reply_to_id);
|
||||
const sender = normalizeReplyField(message.reply_to_sender);
|
||||
return { body, id, sender };
|
||||
@@ -149,7 +155,9 @@ export async function monitorIMessageProvider(opts: MonitorIMessageOpts = {}): P
|
||||
debounceMs: inboundDebounceMs,
|
||||
buildKey: (entry) => {
|
||||
const sender = entry.message.sender?.trim();
|
||||
if (!sender) return null;
|
||||
if (!sender) {
|
||||
return null;
|
||||
}
|
||||
const conversationId =
|
||||
entry.message.chat_id != null
|
||||
? `chat:${entry.message.chat_id}`
|
||||
@@ -158,13 +166,19 @@ export async function monitorIMessageProvider(opts: MonitorIMessageOpts = {}): P
|
||||
},
|
||||
shouldDebounce: (entry) => {
|
||||
const text = entry.message.text?.trim() ?? "";
|
||||
if (!text) return false;
|
||||
if (entry.message.attachments && entry.message.attachments.length > 0) return false;
|
||||
if (!text) {
|
||||
return false;
|
||||
}
|
||||
if (entry.message.attachments && entry.message.attachments.length > 0) {
|
||||
return false;
|
||||
}
|
||||
return !hasControlCommand(text, cfg);
|
||||
},
|
||||
onFlush: async (entries) => {
|
||||
const last = entries.at(-1);
|
||||
if (!last) return;
|
||||
if (!last) {
|
||||
return;
|
||||
}
|
||||
if (entries.length === 1) {
|
||||
await handleMessageNow(last.message);
|
||||
return;
|
||||
@@ -188,9 +202,13 @@ export async function monitorIMessageProvider(opts: MonitorIMessageOpts = {}): P
|
||||
async function handleMessageNow(message: IMessagePayload) {
|
||||
const senderRaw = message.sender ?? "";
|
||||
const sender = senderRaw.trim();
|
||||
if (!sender) return;
|
||||
if (!sender) {
|
||||
return;
|
||||
}
|
||||
const senderNormalized = normalizeIMessageHandle(sender);
|
||||
if (message.is_from_me) return;
|
||||
if (message.is_from_me) {
|
||||
return;
|
||||
}
|
||||
|
||||
const chatId = message.chat_id ?? undefined;
|
||||
const chatGuid = message.chat_guid ?? undefined;
|
||||
@@ -220,7 +238,9 @@ export async function monitorIMessageProvider(opts: MonitorIMessageOpts = {}): P
|
||||
);
|
||||
|
||||
const isGroup = Boolean(message.is_group) || treatAsGroupByConfig;
|
||||
if (isGroup && !chatId) return;
|
||||
if (isGroup && !chatId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const groupId = isGroup ? groupIdCandidate : undefined;
|
||||
const storeAllowFrom = await readChannelAllowFromStore("imessage").catch(() => []);
|
||||
@@ -273,7 +293,9 @@ export async function monitorIMessageProvider(opts: MonitorIMessageOpts = {}): P
|
||||
chatIdentifier,
|
||||
}));
|
||||
if (!isGroup) {
|
||||
if (dmPolicy === "disabled") return;
|
||||
if (dmPolicy === "disabled") {
|
||||
return;
|
||||
}
|
||||
if (!dmAuthorized) {
|
||||
if (dmPolicy === "pairing") {
|
||||
const senderId = normalizeIMessageHandle(sender);
|
||||
@@ -336,7 +358,9 @@ export async function monitorIMessageProvider(opts: MonitorIMessageOpts = {}): P
|
||||
const kind = mediaKindFromMime(mediaType ?? undefined);
|
||||
const placeholder = kind ? `<media:${kind}>` : attachments?.length ? "<media:attachment>" : "";
|
||||
const bodyText = messageText || placeholder;
|
||||
if (!bodyText) return;
|
||||
if (!bodyText) {
|
||||
return;
|
||||
}
|
||||
const replyContext = describeReplyContext(message);
|
||||
const createdAt = message.created_at ? Date.parse(message.created_at) : undefined;
|
||||
const historyKey = isGroup
|
||||
@@ -580,7 +604,9 @@ export async function monitorIMessageProvider(opts: MonitorIMessageOpts = {}): P
|
||||
const handleMessage = async (raw: unknown) => {
|
||||
const params = raw as { message?: IMessagePayload | null };
|
||||
const message = params?.message ?? null;
|
||||
if (!message) return;
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
await inboundDebouncer.enqueue({ message });
|
||||
};
|
||||
|
||||
@@ -594,7 +620,9 @@ export async function monitorIMessageProvider(opts: MonitorIMessageOpts = {}): P
|
||||
runtime,
|
||||
check: async () => {
|
||||
const probe = await probeIMessage(2000, { cliPath, dbPath, runtime });
|
||||
if (probe.ok) return { ok: true };
|
||||
if (probe.ok) {
|
||||
return { ok: true };
|
||||
}
|
||||
if (probe.fatal) {
|
||||
throw new Error(probe.error ?? "imsg rpc unavailable");
|
||||
}
|
||||
@@ -602,7 +630,9 @@ export async function monitorIMessageProvider(opts: MonitorIMessageOpts = {}): P
|
||||
},
|
||||
});
|
||||
|
||||
if (opts.abortSignal?.aborted) return;
|
||||
if (opts.abortSignal?.aborted) {
|
||||
return;
|
||||
}
|
||||
|
||||
const client = await createIMessageRpcClient({
|
||||
cliPath,
|
||||
@@ -644,7 +674,9 @@ export async function monitorIMessageProvider(opts: MonitorIMessageOpts = {}): P
|
||||
subscriptionId = result?.subscription ?? null;
|
||||
await client.waitForClose();
|
||||
} catch (err) {
|
||||
if (abort?.aborted) return;
|
||||
if (abort?.aborted) {
|
||||
return;
|
||||
}
|
||||
runtime.error?.(danger(`imessage: monitor failed: ${String(err)}`));
|
||||
throw err;
|
||||
} finally {
|
||||
|
||||
@@ -26,7 +26,9 @@ const rpcSupportCache = new Map<string, RpcSupportResult>();
|
||||
|
||||
async function probeRpcSupport(cliPath: string): Promise<RpcSupportResult> {
|
||||
const cached = rpcSupportCache.get(cliPath);
|
||||
if (cached) return cached;
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
try {
|
||||
const result = await runCommandWithTimeout([cliPath, "rpc", "--help"], { timeoutMs: 2000 });
|
||||
const combined = `${result.stdout}\n${result.stderr}`.trim();
|
||||
|
||||
@@ -26,7 +26,9 @@ export type IMessageSendResult = {
|
||||
};
|
||||
|
||||
function resolveMessageId(result: Record<string, unknown> | null | undefined): string | null {
|
||||
if (!result) return null;
|
||||
if (!result) {
|
||||
return null;
|
||||
}
|
||||
const raw =
|
||||
(typeof result.messageId === "string" && result.messageId.trim()) ||
|
||||
(typeof result.message_id === "string" && result.message_id.trim()) ||
|
||||
@@ -83,7 +85,9 @@ export async function sendMessageIMessage(
|
||||
filePath = resolved.path;
|
||||
if (!message.trim()) {
|
||||
const kind = mediaKindFromMime(resolved.contentType ?? undefined);
|
||||
if (kind) message = kind === "image" ? "<media:image>" : `<media:${kind}>`;
|
||||
if (kind) {
|
||||
message = kind === "image" ? "<media:image>" : `<media:${kind}>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +108,9 @@ export async function sendMessageIMessage(
|
||||
service: service || "auto",
|
||||
region,
|
||||
};
|
||||
if (filePath) params.file = filePath;
|
||||
if (filePath) {
|
||||
params.file = filePath;
|
||||
}
|
||||
|
||||
if (target.kind === "chat_id") {
|
||||
params.chat_id = target.chatId;
|
||||
|
||||
@@ -29,11 +29,19 @@ function stripPrefix(value: string, prefix: string): string {
|
||||
|
||||
export function normalizeIMessageHandle(raw: string): string {
|
||||
const trimmed = raw.trim();
|
||||
if (!trimmed) return "";
|
||||
if (!trimmed) {
|
||||
return "";
|
||||
}
|
||||
const lowered = trimmed.toLowerCase();
|
||||
if (lowered.startsWith("imessage:")) return normalizeIMessageHandle(trimmed.slice(9));
|
||||
if (lowered.startsWith("sms:")) return normalizeIMessageHandle(trimmed.slice(4));
|
||||
if (lowered.startsWith("auto:")) return normalizeIMessageHandle(trimmed.slice(5));
|
||||
if (lowered.startsWith("imessage:")) {
|
||||
return normalizeIMessageHandle(trimmed.slice(9));
|
||||
}
|
||||
if (lowered.startsWith("sms:")) {
|
||||
return normalizeIMessageHandle(trimmed.slice(4));
|
||||
}
|
||||
if (lowered.startsWith("auto:")) {
|
||||
return normalizeIMessageHandle(trimmed.slice(5));
|
||||
}
|
||||
|
||||
// Normalize chat_id/chat_guid/chat_identifier prefixes case-insensitively
|
||||
for (const prefix of CHAT_ID_PREFIXES) {
|
||||
@@ -55,21 +63,29 @@ export function normalizeIMessageHandle(raw: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
if (trimmed.includes("@")) return trimmed.toLowerCase();
|
||||
if (trimmed.includes("@")) {
|
||||
return trimmed.toLowerCase();
|
||||
}
|
||||
const normalized = normalizeE164(trimmed);
|
||||
if (normalized) return normalized;
|
||||
if (normalized) {
|
||||
return normalized;
|
||||
}
|
||||
return trimmed.replace(/\s+/g, "");
|
||||
}
|
||||
|
||||
export function parseIMessageTarget(raw: string): IMessageTarget {
|
||||
const trimmed = raw.trim();
|
||||
if (!trimmed) throw new Error("iMessage target is required");
|
||||
if (!trimmed) {
|
||||
throw new Error("iMessage target is required");
|
||||
}
|
||||
const lower = trimmed.toLowerCase();
|
||||
|
||||
for (const { prefix, service } of SERVICE_PREFIXES) {
|
||||
if (lower.startsWith(prefix)) {
|
||||
const remainder = stripPrefix(trimmed, prefix);
|
||||
if (!remainder) throw new Error(`${prefix} target is required`);
|
||||
if (!remainder) {
|
||||
throw new Error(`${prefix} target is required`);
|
||||
}
|
||||
const remainderLower = remainder.toLowerCase();
|
||||
const isChatTarget =
|
||||
CHAT_ID_PREFIXES.some((p) => remainderLower.startsWith(p)) ||
|
||||
@@ -96,7 +112,9 @@ export function parseIMessageTarget(raw: string): IMessageTarget {
|
||||
for (const prefix of CHAT_GUID_PREFIXES) {
|
||||
if (lower.startsWith(prefix)) {
|
||||
const value = stripPrefix(trimmed, prefix);
|
||||
if (!value) throw new Error("chat_guid is required");
|
||||
if (!value) {
|
||||
throw new Error("chat_guid is required");
|
||||
}
|
||||
return { kind: "chat_guid", chatGuid: value };
|
||||
}
|
||||
}
|
||||
@@ -104,7 +122,9 @@ export function parseIMessageTarget(raw: string): IMessageTarget {
|
||||
for (const prefix of CHAT_IDENTIFIER_PREFIXES) {
|
||||
if (lower.startsWith(prefix)) {
|
||||
const value = stripPrefix(trimmed, prefix);
|
||||
if (!value) throw new Error("chat_identifier is required");
|
||||
if (!value) {
|
||||
throw new Error("chat_identifier is required");
|
||||
}
|
||||
return { kind: "chat_identifier", chatIdentifier: value };
|
||||
}
|
||||
}
|
||||
@@ -114,13 +134,17 @@ export function parseIMessageTarget(raw: string): IMessageTarget {
|
||||
|
||||
export function parseIMessageAllowTarget(raw: string): IMessageAllowTarget {
|
||||
const trimmed = raw.trim();
|
||||
if (!trimmed) return { kind: "handle", handle: "" };
|
||||
if (!trimmed) {
|
||||
return { kind: "handle", handle: "" };
|
||||
}
|
||||
const lower = trimmed.toLowerCase();
|
||||
|
||||
for (const { prefix } of SERVICE_PREFIXES) {
|
||||
if (lower.startsWith(prefix)) {
|
||||
const remainder = stripPrefix(trimmed, prefix);
|
||||
if (!remainder) return { kind: "handle", handle: "" };
|
||||
if (!remainder) {
|
||||
return { kind: "handle", handle: "" };
|
||||
}
|
||||
return parseIMessageAllowTarget(remainder);
|
||||
}
|
||||
}
|
||||
@@ -129,21 +153,27 @@ export function parseIMessageAllowTarget(raw: string): IMessageAllowTarget {
|
||||
if (lower.startsWith(prefix)) {
|
||||
const value = stripPrefix(trimmed, prefix);
|
||||
const chatId = Number.parseInt(value, 10);
|
||||
if (Number.isFinite(chatId)) return { kind: "chat_id", chatId };
|
||||
if (Number.isFinite(chatId)) {
|
||||
return { kind: "chat_id", chatId };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const prefix of CHAT_GUID_PREFIXES) {
|
||||
if (lower.startsWith(prefix)) {
|
||||
const value = stripPrefix(trimmed, prefix);
|
||||
if (value) return { kind: "chat_guid", chatGuid: value };
|
||||
if (value) {
|
||||
return { kind: "chat_guid", chatGuid: value };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const prefix of CHAT_IDENTIFIER_PREFIXES) {
|
||||
if (lower.startsWith(prefix)) {
|
||||
const value = stripPrefix(trimmed, prefix);
|
||||
if (value) return { kind: "chat_identifier", chatIdentifier: value };
|
||||
if (value) {
|
||||
return { kind: "chat_identifier", chatIdentifier: value };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,8 +188,12 @@ export function isAllowedIMessageSender(params: {
|
||||
chatIdentifier?: string | null;
|
||||
}): boolean {
|
||||
const allowFrom = params.allowFrom.map((entry) => String(entry).trim());
|
||||
if (allowFrom.length === 0) return true;
|
||||
if (allowFrom.includes("*")) return true;
|
||||
if (allowFrom.length === 0) {
|
||||
return true;
|
||||
}
|
||||
if (allowFrom.includes("*")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const senderNormalized = normalizeIMessageHandle(params.sender);
|
||||
const chatId = params.chatId ?? undefined;
|
||||
@@ -167,22 +201,34 @@ export function isAllowedIMessageSender(params: {
|
||||
const chatIdentifier = params.chatIdentifier?.trim();
|
||||
|
||||
for (const entry of allowFrom) {
|
||||
if (!entry) continue;
|
||||
if (!entry) {
|
||||
continue;
|
||||
}
|
||||
const parsed = parseIMessageAllowTarget(entry);
|
||||
if (parsed.kind === "chat_id" && chatId !== undefined) {
|
||||
if (parsed.chatId === chatId) return true;
|
||||
if (parsed.chatId === chatId) {
|
||||
return true;
|
||||
}
|
||||
} else if (parsed.kind === "chat_guid" && chatGuid) {
|
||||
if (parsed.chatGuid === chatGuid) return true;
|
||||
if (parsed.chatGuid === chatGuid) {
|
||||
return true;
|
||||
}
|
||||
} else if (parsed.kind === "chat_identifier" && chatIdentifier) {
|
||||
if (parsed.chatIdentifier === chatIdentifier) return true;
|
||||
if (parsed.chatIdentifier === chatIdentifier) {
|
||||
return true;
|
||||
}
|
||||
} else if (parsed.kind === "handle" && senderNormalized) {
|
||||
if (parsed.handle === senderNormalized) return true;
|
||||
if (parsed.handle === senderNormalized) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function formatIMessageChatTarget(chatId?: number | null): string {
|
||||
if (!chatId || !Number.isFinite(chatId)) return "";
|
||||
if (!chatId || !Number.isFinite(chatId)) {
|
||||
return "";
|
||||
}
|
||||
return `chat_id:${chatId}`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user