mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 12:30:44 +00:00
chore: apply extension lint cleanups
This commit is contained in:
@@ -178,7 +178,7 @@ async function queryBlueBubblesChats(params: {
|
||||
return [];
|
||||
}
|
||||
const payload = (await res.json().catch(() => null)) as Record<string, unknown> | null;
|
||||
const data = payload && typeof payload.data !== "undefined" ? (payload.data as unknown) : null;
|
||||
const data = payload && payload.data !== undefined ? (payload.data as unknown) : null;
|
||||
return Array.isArray(data) ? (data as BlueBubblesChatRecord[]) : [];
|
||||
}
|
||||
|
||||
|
||||
@@ -226,7 +226,7 @@ async function queryChats(params: {
|
||||
return [];
|
||||
}
|
||||
const payload = (await res.json().catch(() => null)) as Record<string, unknown> | null;
|
||||
const data = payload && typeof payload.data !== "undefined" ? (payload.data as unknown) : null;
|
||||
const data = payload && payload.data !== undefined ? (payload.data as unknown) : null;
|
||||
return Array.isArray(data) ? (data as BlueBubblesChatRecord[]) : [];
|
||||
}
|
||||
|
||||
|
||||
@@ -189,7 +189,7 @@ function readNativeCompactionCompletion(
|
||||
|
||||
function resolveCompactionWaitTimeoutMs(): number {
|
||||
const raw = process.env.OPENCLAW_CODEX_COMPACTION_WAIT_TIMEOUT_MS?.trim();
|
||||
const parsed = raw ? Number.parseInt(raw, 10) : NaN;
|
||||
const parsed = raw ? Number.parseInt(raw, 10) : Number.NaN;
|
||||
if (Number.isFinite(parsed) && parsed > 0) {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
@@ -68,8 +68,8 @@ export async function getAudioDuration(filePath: string): Promise<number> {
|
||||
"csv=p=0",
|
||||
filePath,
|
||||
]);
|
||||
const duration = parseFloat(stdout.trim());
|
||||
if (isNaN(duration)) {
|
||||
const duration = Number.parseFloat(stdout.trim());
|
||||
if (Number.isNaN(duration)) {
|
||||
throw new Error("Could not parse duration");
|
||||
}
|
||||
return Math.round(duration * 100) / 100; // Round to 2 decimal places
|
||||
|
||||
@@ -2,8 +2,8 @@ import { formatErrorMessage } from "openclaw/plugin-sdk/ssrf-runtime";
|
||||
|
||||
const DECRYPT_FAILURE_WINDOW_MS = 30_000;
|
||||
const DECRYPT_FAILURE_RECONNECT_THRESHOLD = 3;
|
||||
const DECRYPT_FAILURE_PATTERN = /DecryptionFailed\(/;
|
||||
const DAVE_PASSTHROUGH_DISABLED_PATTERN = /UnencryptedWhenPassthroughDisabled/;
|
||||
const DECRYPT_FAILURE_MARKER = "DecryptionFailed(";
|
||||
const DAVE_PASSTHROUGH_DISABLED_MARKER = "UnencryptedWhenPassthroughDisabled";
|
||||
|
||||
export const DAVE_RECEIVE_PASSTHROUGH_INITIAL_EXPIRY_SECONDS = 30;
|
||||
export const DAVE_RECEIVE_PASSTHROUGH_REARM_EXPIRY_SECONDS = 15;
|
||||
@@ -80,12 +80,12 @@ export function isAbortLikeReceiveError(err: unknown): boolean {
|
||||
|
||||
export function analyzeVoiceReceiveError(err: unknown): VoiceReceiveErrorAnalysis {
|
||||
const message = formatErrorMessage(err);
|
||||
const shouldAttemptPassthrough = DAVE_PASSTHROUGH_DISABLED_PATTERN.test(message);
|
||||
const shouldAttemptPassthrough = message.includes(DAVE_PASSTHROUGH_DISABLED_MARKER);
|
||||
return {
|
||||
message,
|
||||
isAbortLike: isAbortLikeReceiveError(err),
|
||||
shouldAttemptPassthrough,
|
||||
countsAsDecryptFailure: DECRYPT_FAILURE_PATTERN.test(message) || shouldAttemptPassthrough,
|
||||
countsAsDecryptFailure: message.includes(DECRYPT_FAILURE_MARKER) || shouldAttemptPassthrough,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ function decodeHtmlEntities(text: string): string {
|
||||
.replace(/—/g, "--")
|
||||
.replace(/…/g, "...")
|
||||
.replace(/&#(\d+);/g, (_, code) => String.fromCodePoint(Number(code)))
|
||||
.replace(/&#x([0-9a-f]+);/gi, (_, code) => String.fromCodePoint(parseInt(code, 16)));
|
||||
.replace(/&#x([0-9a-f]+);/gi, (_, code) => String.fromCodePoint(Number.parseInt(code, 16)));
|
||||
}
|
||||
|
||||
function stripHtml(html: string): string {
|
||||
|
||||
@@ -38,9 +38,7 @@ type FeishuMessageLike = {
|
||||
|
||||
export type GroupSessionScope = "group" | "group_sender" | "group_topic" | "group_topic_sender";
|
||||
|
||||
type FeishuLogger = {
|
||||
(...args: unknown[]): void;
|
||||
};
|
||||
type FeishuLogger = (...args: unknown[]) => void;
|
||||
|
||||
export type ResolvedFeishuGroupSession = {
|
||||
peerId: string;
|
||||
@@ -215,7 +213,7 @@ export function parseMergeForwardContent(params: { content: string; log?: Feishu
|
||||
|
||||
log?.(`feishu: merge_forward contains ${subMessages.length} sub-messages`);
|
||||
subMessages.sort(
|
||||
(a, b) => parseInt(a.create_time || "0", 10) - parseInt(b.create_time || "0", 10),
|
||||
(a, b) => Number.parseInt(a.create_time || "0", 10) - Number.parseInt(b.create_time || "0", 10),
|
||||
);
|
||||
|
||||
const lines = ["[Merged and Forwarded Messages]"];
|
||||
|
||||
@@ -17,9 +17,7 @@ type FeishuContactUserGetResponse = Awaited<
|
||||
ReturnType<ReturnType<typeof createFeishuClient>["contact"]["user"]["get"]>
|
||||
>;
|
||||
|
||||
type FeishuLogger = {
|
||||
(...args: unknown[]): void;
|
||||
};
|
||||
type FeishuLogger = (...args: unknown[]) => void;
|
||||
|
||||
const IGNORED_PERMISSION_SCOPE_TOKENS = ["contact:contact.base:readonly"];
|
||||
const FEISHU_SCOPE_CORRECTIONS: Record<string, string> = {
|
||||
|
||||
@@ -409,7 +409,7 @@ export async function handleFeishuMessage(params: {
|
||||
// instead of the delivery/processing time. Feishu uses a millisecond
|
||||
// epoch string; fall back to Date.now() only when the field is absent.
|
||||
const messageCreateTimeMs = event.message.create_time
|
||||
? parseInt(event.message.create_time, 10)
|
||||
? Number.parseInt(event.message.create_time, 10)
|
||||
: Date.now();
|
||||
|
||||
let requireMention = false; // DMs never require mention; groups may override below
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { Readable } from "stream";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { Readable } from "node:stream";
|
||||
import type * as Lark from "@larksuiteoapi/node-sdk";
|
||||
import { mediaKindFromMime } from "openclaw/plugin-sdk/media-runtime";
|
||||
import { withTempDownloadPath } from "openclaw/plugin-sdk/temp-path";
|
||||
@@ -627,22 +627,21 @@ export async function sendMediaFeishu(params: {
|
||||
if (routing.msgType === "image") {
|
||||
const { imageKey } = await uploadImageFeishu({ cfg, image: buffer, accountId });
|
||||
return sendImageFeishu({ cfg, to, imageKey, replyToMessageId, replyInThread, accountId });
|
||||
} else {
|
||||
const { fileKey } = await uploadFileFeishu({
|
||||
cfg,
|
||||
file: buffer,
|
||||
fileName: name,
|
||||
fileType: routing.fileType ?? "stream",
|
||||
accountId,
|
||||
});
|
||||
return sendFileFeishu({
|
||||
cfg,
|
||||
to,
|
||||
fileKey,
|
||||
msgType: routing.msgType,
|
||||
replyToMessageId,
|
||||
replyInThread,
|
||||
accountId,
|
||||
});
|
||||
}
|
||||
const { fileKey } = await uploadFileFeishu({
|
||||
cfg,
|
||||
file: buffer,
|
||||
fileName: name,
|
||||
fileType: routing.fileType ?? "stream",
|
||||
accountId,
|
||||
});
|
||||
return sendFileFeishu({
|
||||
cfg,
|
||||
to,
|
||||
fileKey,
|
||||
msgType: routing.msgType,
|
||||
replyToMessageId,
|
||||
replyInThread,
|
||||
accountId,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -52,11 +52,10 @@ export function isMentionForwardRequest(event: FeishuMessageEvent, botOpenId?: s
|
||||
if (isDirectMessage) {
|
||||
// DM: trigger if any non-bot user is mentioned
|
||||
return hasOtherMention;
|
||||
} else {
|
||||
// Group: need to mention both bot and other users
|
||||
const hasBotMention = mentions.some((m) => m.id.open_id === botOpenId);
|
||||
return hasBotMention && hasOtherMention;
|
||||
}
|
||||
// Group: need to mention both bot and other users
|
||||
const hasBotMention = mentions.some((m) => m.id.open_id === botOpenId);
|
||||
return hasBotMention && hasOtherMention;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as crypto from "crypto";
|
||||
import * as crypto from "node:crypto";
|
||||
import type * as Lark from "@larksuiteoapi/node-sdk";
|
||||
import type { ClawdbotConfig, RuntimeEnv, HistoryEntry } from "../runtime-api.js";
|
||||
import { resolveFeishuAccount } from "./accounts.js";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as http from "http";
|
||||
import * as http from "node:http";
|
||||
import type * as Lark from "@larksuiteoapi/node-sdk";
|
||||
import {
|
||||
createFixedWindowRateLimiter,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as http from "http";
|
||||
import crypto from "node:crypto";
|
||||
import * as http from "node:http";
|
||||
import * as Lark from "@larksuiteoapi/node-sdk";
|
||||
import { createFeishuWSClient } from "./client.js";
|
||||
import {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { createAttachedChannelResultAdapter } from "openclaw/plugin-sdk/channel-send-result";
|
||||
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
||||
import { resolveFeishuAccount } from "./accounts.js";
|
||||
|
||||
@@ -276,7 +276,7 @@ function parseFeishuMessageItem(
|
||||
senderType: item.sender?.sender_type,
|
||||
content: parseFeishuMessageContent(rawContent, msgType),
|
||||
contentType: msgType,
|
||||
createTime: item.create_time ? parseInt(item.create_time, 10) : undefined,
|
||||
createTime: item.create_time ? Number.parseInt(item.create_time, 10) : undefined,
|
||||
threadId: item.thread_id || undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -281,7 +281,7 @@ async function shouldProcessLineEvent(
|
||||
logVerbose(`Blocked line group ${groupId ?? roomId ?? "unknown"} (group disabled)`);
|
||||
return denied;
|
||||
}
|
||||
if (typeof groupAllowOverride !== "undefined") {
|
||||
if (groupAllowOverride !== undefined) {
|
||||
if (!senderId) {
|
||||
logVerbose("Blocked line group message (group allowFrom override, no sender ID)");
|
||||
return denied;
|
||||
|
||||
@@ -64,9 +64,9 @@ export function parseLineDirectives(payload: ReplyPayload): ReplyPayload {
|
||||
const parts = locationMatch[1].split("|").map((s) => s.trim());
|
||||
if (parts.length >= 4) {
|
||||
const [title, address, latStr, lonStr] = parts;
|
||||
const latitude = parseFloat(latStr);
|
||||
const longitude = parseFloat(lonStr);
|
||||
if (!isNaN(latitude) && !isNaN(longitude)) {
|
||||
const latitude = Number.parseFloat(latStr);
|
||||
const longitude = Number.parseFloat(lonStr);
|
||||
if (!Number.isNaN(latitude) && !Number.isNaN(longitude)) {
|
||||
lineData.location = {
|
||||
title: title || "Location",
|
||||
address: address || "",
|
||||
|
||||
@@ -85,7 +85,7 @@ export function moveSingleMatrixAccountConfigToNamedAccount(cfg: CoreConfig): Co
|
||||
typeof base.accounts === "object" && base.accounts
|
||||
? (base.accounts as Record<string, Record<string, unknown>>)
|
||||
: {};
|
||||
const hasNamedAccounts = Object.keys(accounts).filter(Boolean).length > 0;
|
||||
const hasNamedAccounts = Object.keys(accounts).some(Boolean);
|
||||
const keysToMove = Object.entries(base)
|
||||
.filter(([key, value]) => {
|
||||
if (key === "accounts" || key === "enabled" || value === undefined) {
|
||||
|
||||
@@ -377,7 +377,7 @@ function isRetryableError(error: Error): boolean {
|
||||
if (!clientErrorMatch) {
|
||||
continue;
|
||||
}
|
||||
const statusCode = parseInt(clientErrorMatch[1], 10);
|
||||
const statusCode = Number.parseInt(clientErrorMatch[1], 10);
|
||||
if (statusCode >= 400 && statusCode < 500) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ export const memoryConfigSchema = {
|
||||
}
|
||||
|
||||
const dreaming =
|
||||
typeof cfg.dreaming === "undefined"
|
||||
cfg.dreaming === undefined
|
||||
? undefined
|
||||
: cfg.dreaming && typeof cfg.dreaming === "object" && !Array.isArray(cfg.dreaming)
|
||||
? (cfg.dreaming as Record<string, unknown>)
|
||||
|
||||
@@ -551,7 +551,7 @@ export default definePluginEntry({
|
||||
.option("--limit <n>", "Max results", "5")
|
||||
.action(async (query, opts) => {
|
||||
const vector = await embeddings.embed(query);
|
||||
const results = await db.search(vector, parseInt(opts.limit), 0.3);
|
||||
const results = await db.search(vector, Number.parseInt(opts.limit, 10), 0.3);
|
||||
// Strip vectors for output
|
||||
const output = results.map((r) => ({
|
||||
id: r.entry.id,
|
||||
|
||||
@@ -299,10 +299,10 @@ describe("Metrics fuzz", () => {
|
||||
describe("extreme values", () => {
|
||||
it("handles NaN value", () => {
|
||||
const metrics = createPlainMetrics();
|
||||
expect(() => metrics.emit("event.received", NaN)).not.toThrow();
|
||||
expect(() => metrics.emit("event.received", Number.NaN)).not.toThrow();
|
||||
|
||||
const snapshot = metrics.getSnapshot();
|
||||
expect(isNaN(snapshot.eventsReceived)).toBe(true);
|
||||
expect(Number.isNaN(snapshot.eventsReceived)).toBe(true);
|
||||
});
|
||||
|
||||
it("handles Infinity value", () => {
|
||||
|
||||
@@ -23,7 +23,7 @@ export function validatePrivateKey(key: string): Uint8Array {
|
||||
// Convert hex string to Uint8Array
|
||||
const bytes = new Uint8Array(32);
|
||||
for (let i = 0; i < 32; i++) {
|
||||
bytes[i] = parseInt(trimmed.slice(i * 2, i * 2 + 2), 16);
|
||||
bytes[i] = Number.parseInt(trimmed.slice(i * 2, i * 2 + 2), 16);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ export const TEST_SETUP_RELAY_URLS = ["wss://relay.damus.io", "wss://relay.prima
|
||||
export const TEST_RESOLVED_PRIVATE_KEY = "resolved-nostr-private-key";
|
||||
|
||||
export const TEST_HEX_PRIVATE_KEY_BYTES = new Uint8Array(
|
||||
TEST_HEX_PRIVATE_KEY.match(/.{2}/g)!.map((byte) => parseInt(byte, 16)),
|
||||
TEST_HEX_PRIVATE_KEY.match(/.{2}/g)!.map((byte) => Number.parseInt(byte, 16)),
|
||||
);
|
||||
|
||||
export function createConfiguredNostrCfg(overrides: Record<string, unknown> = {}): {
|
||||
|
||||
@@ -1531,7 +1531,7 @@ export async function createQaLabApp(root: HTMLDivElement) {
|
||||
const currentIndex = markers.findIndex(
|
||||
(node) => (node.dataset.captureEvent ?? null) === state.selectedCaptureEventKey,
|
||||
);
|
||||
let nextIndex = currentIndex >= 0 ? currentIndex : 0;
|
||||
let nextIndex = Math.max(currentIndex, 0);
|
||||
if (event.key === "Home") {
|
||||
nextIndex = 0;
|
||||
} else if (event.key === "End") {
|
||||
|
||||
@@ -94,7 +94,7 @@ registerCommand({
|
||||
handler: (ctx) => {
|
||||
const now = Date.now();
|
||||
const eventTime = new Date(ctx.eventTimestamp).getTime();
|
||||
if (isNaN(eventTime)) {
|
||||
if (Number.isNaN(eventTime)) {
|
||||
return `✅ pong!`;
|
||||
}
|
||||
const totalMs = now - eventTime;
|
||||
|
||||
@@ -153,7 +153,8 @@ export async function processAttachments(
|
||||
if (att.content_type?.startsWith("image/")) {
|
||||
log?.debug?.(`Downloaded attachment to: ${localPath}`);
|
||||
return { localPath, type: "image" as const, contentType: att.content_type, meta };
|
||||
} else if (isVoice) {
|
||||
}
|
||||
if (isVoice) {
|
||||
log?.debug?.(`Downloaded attachment to: ${localPath}`);
|
||||
return processVoiceAttachment(
|
||||
localPath,
|
||||
@@ -164,37 +165,35 @@ export async function processAttachments(
|
||||
downloadDir,
|
||||
log,
|
||||
);
|
||||
} else {
|
||||
log?.debug?.(`Downloaded attachment to: ${localPath}`);
|
||||
return { localPath, type: "other" as const, filename: att.filename, meta };
|
||||
}
|
||||
} else {
|
||||
log?.error(`Failed to download: ${attUrl}`);
|
||||
if (att.content_type?.startsWith("image/")) {
|
||||
return {
|
||||
localPath: null,
|
||||
type: "image-fallback" as const,
|
||||
attUrl,
|
||||
contentType: att.content_type,
|
||||
meta,
|
||||
};
|
||||
} else if (isVoice && asrReferText) {
|
||||
log?.info(`Voice attachment download failed, using asr_refer_text fallback`);
|
||||
return {
|
||||
localPath: null,
|
||||
type: "voice-fallback" as const,
|
||||
transcript: asrReferText,
|
||||
meta,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
localPath: null,
|
||||
type: "other-fallback" as const,
|
||||
filename: att.filename ?? att.content_type,
|
||||
meta,
|
||||
};
|
||||
}
|
||||
log?.debug?.(`Downloaded attachment to: ${localPath}`);
|
||||
return { localPath, type: "other" as const, filename: att.filename, meta };
|
||||
}
|
||||
log?.error(`Failed to download: ${attUrl}`);
|
||||
if (att.content_type?.startsWith("image/")) {
|
||||
return {
|
||||
localPath: null,
|
||||
type: "image-fallback" as const,
|
||||
attUrl,
|
||||
contentType: att.content_type,
|
||||
meta,
|
||||
};
|
||||
}
|
||||
if (isVoice && asrReferText) {
|
||||
log?.info(`Voice attachment download failed, using asr_refer_text fallback`);
|
||||
return {
|
||||
localPath: null,
|
||||
type: "voice-fallback" as const,
|
||||
transcript: asrReferText,
|
||||
meta,
|
||||
};
|
||||
}
|
||||
return {
|
||||
localPath: null,
|
||||
type: "other-fallback" as const,
|
||||
filename: att.filename ?? att.content_type,
|
||||
meta,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ export function decodeMediaPath(raw: string, log?: EngineLogger): string {
|
||||
if (!isWinLocal && (hasOctal || hasNonASCII)) {
|
||||
log?.debug?.(`Decoding path with mixed encoding: ${mediaPath}`);
|
||||
const decoded = mediaPath.replace(/\\([0-7]{1,3})/g, (_: string, octal: string) => {
|
||||
return String.fromCharCode(parseInt(octal, 8));
|
||||
return String.fromCharCode(Number.parseInt(octal, 8));
|
||||
});
|
||||
const bytes: number[] = [];
|
||||
for (let i = 0; i < decoded.length; i++) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "path";
|
||||
import * as path from "node:path";
|
||||
import { formatErrorMessage } from "../utils/format.js";
|
||||
import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
@@ -401,16 +401,15 @@ export async function sendPhoto(
|
||||
localPath,
|
||||
});
|
||||
return { channel: "qqbot", messageId: r.id, timestamp: r.timestamp };
|
||||
} else {
|
||||
if (isHttp) {
|
||||
const r = await senderSendText(target, ``, creds, {
|
||||
msgId: ctx.replyToId,
|
||||
});
|
||||
return { channel: "qqbot", messageId: r.id, timestamp: r.timestamp };
|
||||
}
|
||||
debugLog(`sendPhoto: channel does not support local/Base64 images`);
|
||||
return { channel: "qqbot", error: "Channel does not support local/Base64 images" };
|
||||
}
|
||||
if (isHttp) {
|
||||
const r = await senderSendText(target, ``, creds, {
|
||||
msgId: ctx.replyToId,
|
||||
});
|
||||
return { channel: "qqbot", messageId: r.id, timestamp: r.timestamp };
|
||||
}
|
||||
debugLog(`sendPhoto: channel does not support local/Base64 images`);
|
||||
return { channel: "qqbot", error: "Channel does not support local/Base64 images" };
|
||||
} catch (err) {
|
||||
const msg = formatErrorMessage(err);
|
||||
|
||||
@@ -482,10 +481,9 @@ export async function sendVoice(
|
||||
msgId: ctx.replyToId,
|
||||
});
|
||||
return { channel: "qqbot", messageId: r.id, timestamp: r.timestamp };
|
||||
} else {
|
||||
debugLog(`sendVoice: voice not supported in channel`);
|
||||
return { channel: "qqbot", error: "Voice not supported in channel" };
|
||||
}
|
||||
debugLog(`sendVoice: voice not supported in channel`);
|
||||
return { channel: "qqbot", error: "Voice not supported in channel" };
|
||||
} catch (err) {
|
||||
const msg = formatErrorMessage(err);
|
||||
debugWarn(
|
||||
@@ -561,10 +559,9 @@ async function sendVoiceFromLocal(
|
||||
filePath: safeMediaPath,
|
||||
});
|
||||
return { channel: "qqbot", messageId: r.id, timestamp: r.timestamp };
|
||||
} else {
|
||||
debugLog(`sendVoice: voice not supported in channel`);
|
||||
return { channel: "qqbot", error: "Voice not supported in channel" };
|
||||
}
|
||||
debugLog(`sendVoice: voice not supported in channel`);
|
||||
return { channel: "qqbot", error: "Voice not supported in channel" };
|
||||
} catch (err) {
|
||||
const msg = formatErrorMessage(err);
|
||||
debugError(`sendVoice (local) failed: ${msg}`);
|
||||
@@ -603,10 +600,9 @@ export async function sendVideoMsg(
|
||||
msgId: ctx.replyToId,
|
||||
});
|
||||
return { channel: "qqbot", messageId: r.id, timestamp: r.timestamp };
|
||||
} else {
|
||||
debugLog(`sendVideoMsg: video not supported in channel`);
|
||||
return { channel: "qqbot", error: "Video not supported in channel" };
|
||||
}
|
||||
debugLog(`sendVideoMsg: video not supported in channel`);
|
||||
return { channel: "qqbot", error: "Video not supported in channel" };
|
||||
}
|
||||
|
||||
return await sendVideoFromLocal(ctx, mediaPath);
|
||||
@@ -656,10 +652,9 @@ async function sendVideoFromLocal(
|
||||
localPath: mediaPath,
|
||||
});
|
||||
return { channel: "qqbot", messageId: r.id, timestamp: r.timestamp };
|
||||
} else {
|
||||
debugLog(`sendVideoMsg: video not supported in channel`);
|
||||
return { channel: "qqbot", error: "Video not supported in channel" };
|
||||
}
|
||||
debugLog(`sendVideoMsg: video not supported in channel`);
|
||||
return { channel: "qqbot", error: "Video not supported in channel" };
|
||||
} catch (err) {
|
||||
const msg = formatErrorMessage(err);
|
||||
debugError(`sendVideoMsg (local) failed: ${msg}`);
|
||||
@@ -706,10 +701,9 @@ export async function sendDocument(
|
||||
fileName,
|
||||
});
|
||||
return { channel: "qqbot", messageId: r.id, timestamp: r.timestamp };
|
||||
} else {
|
||||
debugLog(`sendDocument: file not supported in channel`);
|
||||
return { channel: "qqbot", error: "File not supported in channel" };
|
||||
}
|
||||
debugLog(`sendDocument: file not supported in channel`);
|
||||
return { channel: "qqbot", error: "File not supported in channel" };
|
||||
}
|
||||
|
||||
return await sendDocumentFromLocal(ctx, mediaPath);
|
||||
@@ -764,10 +758,9 @@ async function sendDocumentFromLocal(
|
||||
localFilePath: mediaPath,
|
||||
});
|
||||
return { channel: "qqbot", messageId: r.id, timestamp: r.timestamp };
|
||||
} else {
|
||||
debugLog(`sendDocument: file not supported in channel`);
|
||||
return { channel: "qqbot", error: "File not supported in channel" };
|
||||
}
|
||||
debugLog(`sendDocument: file not supported in channel`);
|
||||
return { channel: "qqbot", error: "File not supported in channel" };
|
||||
} catch (err) {
|
||||
const msg = formatErrorMessage(err);
|
||||
debugError(`sendDocument (local) failed: ${msg}`);
|
||||
@@ -891,7 +884,7 @@ export async function sendText(ctx: OutboundContext): Promise<OutboundResult> {
|
||||
debugLog(`[qqbot] sendText: Decoding path with mixed encoding: ${mediaPath}`);
|
||||
|
||||
let decoded = mediaPath.replace(/\\([0-7]{1,3})/g, (_: string, octal: string) => {
|
||||
return String.fromCharCode(parseInt(octal, 8));
|
||||
return String.fromCharCode(Number.parseInt(octal, 8));
|
||||
});
|
||||
|
||||
const bytes: number[] = [];
|
||||
|
||||
@@ -94,7 +94,7 @@ export const RemindSchema = {
|
||||
export function parseRelativeTime(timeStr: string): number | null {
|
||||
const s = timeStr.toLowerCase();
|
||||
if (/^\d+$/.test(s)) {
|
||||
return parseInt(s, 10) * 60_000;
|
||||
return Number.parseInt(s, 10) * 60_000;
|
||||
}
|
||||
|
||||
let totalMs = 0;
|
||||
@@ -103,7 +103,7 @@ export function parseRelativeTime(timeStr: string): number | null {
|
||||
let match: RegExpExecArray | null;
|
||||
while ((match = regex.exec(s)) !== null) {
|
||||
matched = true;
|
||||
const value = parseFloat(match[1]);
|
||||
const value = Number.parseFloat(match[1]);
|
||||
const unit = match[2];
|
||||
switch (unit) {
|
||||
case "d":
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Buffer } from "buffer";
|
||||
import { Buffer } from "node:buffer";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const adapterMocks = vi.hoisted(() => ({
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* QQ Bot markdown images use ``.
|
||||
*/
|
||||
|
||||
import { Buffer } from "buffer";
|
||||
import { Buffer } from "node:buffer";
|
||||
import { getPlatformAdapter } from "../adapter/index.js";
|
||||
import type { SsrfPolicyConfig } from "../adapter/types.js";
|
||||
import { formatErrorMessage } from "./format.js";
|
||||
@@ -252,7 +252,7 @@ export function hasQQBotImageSize(markdownImage: string): boolean {
|
||||
export function extractQQBotImageSize(markdownImage: string): ImageSize | null {
|
||||
const match = markdownImage.match(/!\[#(\d+)px\s+#(\d+)px\]/);
|
||||
if (match) {
|
||||
return { width: parseInt(match[1], 10), height: parseInt(match[2], 10) };
|
||||
return { width: Number.parseInt(match[1], 10), height: Number.parseInt(match[2], 10) };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ export const signalMessageActions: ChannelMessageActionAdapter = {
|
||||
const emoji = readStringParam(params, "emoji", { allowEmpty: true });
|
||||
const remove = typeof params.remove === "boolean" ? params.remove : undefined;
|
||||
|
||||
const timestamp = parseInt(messageId, 10);
|
||||
const timestamp = Number.parseInt(messageId, 10);
|
||||
if (!Number.isFinite(timestamp)) {
|
||||
throw new Error(`Invalid messageId: ${messageId}. Expected numeric timestamp.`);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ export type SlackChannelConfigEntries = Record<string, SlackChannelConfigEntry>;
|
||||
|
||||
function firstDefined<T>(...values: Array<T | undefined>) {
|
||||
for (const value of values) {
|
||||
if (typeof value !== "undefined") {
|
||||
if (value !== undefined) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,7 +281,7 @@ function parseNumericUserId(userId?: string | number): number | undefined {
|
||||
if (userId === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
const numericId = typeof userId === "number" ? userId : parseInt(userId, 10);
|
||||
const numericId = typeof userId === "number" ? userId : Number.parseInt(userId, 10);
|
||||
return Number.isNaN(numericId) ? undefined : numericId;
|
||||
}
|
||||
|
||||
|
||||
@@ -262,7 +262,7 @@ export const buildTelegramMessageContext = async ({
|
||||
});
|
||||
// Group sender checks are explicit and must not inherit DM pairing-store entries.
|
||||
const effectiveGroupAllow = normalizeAllowFrom(groupAllowOverride ?? groupAllowFrom);
|
||||
const hasGroupAllowOverride = typeof groupAllowOverride !== "undefined";
|
||||
const hasGroupAllowOverride = groupAllowOverride !== undefined;
|
||||
const senderUsername = msg.from?.username ?? "";
|
||||
const baseAccess = evaluateTelegramGroupBaseAccess({
|
||||
isGroup,
|
||||
|
||||
@@ -52,7 +52,7 @@ export const buildTelegramUpdateKey = (ctx: TelegramUpdateKeyContext) => {
|
||||
ctx.callbackQuery?.message;
|
||||
const chatId = msg?.chat?.id;
|
||||
const messageId = msg?.message_id;
|
||||
if (typeof chatId !== "undefined" && typeof messageId === "number") {
|
||||
if (chatId !== undefined && typeof messageId === "number") {
|
||||
return `message:${chatId}:${messageId}`;
|
||||
}
|
||||
return undefined;
|
||||
|
||||
@@ -47,7 +47,7 @@ import {
|
||||
type DeliveryProgress as ReplyThreadDeliveryProgress,
|
||||
} from "./reply-threading.js";
|
||||
|
||||
const VOICE_FORBIDDEN_RE = /VOICE_MESSAGES_FORBIDDEN/;
|
||||
const VOICE_FORBIDDEN_MARKER = "VOICE_MESSAGES_FORBIDDEN";
|
||||
const CAPTION_TOO_LONG_RE = /caption is too long/i;
|
||||
const GrammyErrorCtor: typeof GrammyError | undefined =
|
||||
typeof GrammyError === "function" ? GrammyError : undefined;
|
||||
@@ -193,9 +193,9 @@ async function sendPendingFollowUpText(params: {
|
||||
|
||||
function isVoiceMessagesForbidden(err: unknown): boolean {
|
||||
if (GrammyErrorCtor && err instanceof GrammyErrorCtor) {
|
||||
return VOICE_FORBIDDEN_RE.test(err.description);
|
||||
return err.description.includes(VOICE_FORBIDDEN_MARKER);
|
||||
}
|
||||
return VOICE_FORBIDDEN_RE.test(formatErrorMessage(err));
|
||||
return formatErrorMessage(err).includes(VOICE_FORBIDDEN_MARKER);
|
||||
}
|
||||
|
||||
function isCaptionTooLong(err: unknown): boolean {
|
||||
|
||||
@@ -144,7 +144,7 @@ export async function resolveTelegramGroupAllowFromContext(params: {
|
||||
// Group sender access must remain explicit (groupAllowFrom/per-group allowFrom only).
|
||||
// DM pairing store entries are not a group authorization source.
|
||||
const effectiveGroupAllow = normalizeAllowFrom(groupAllowOverride ?? params.groupAllowFrom);
|
||||
const hasGroupAllowOverride = typeof groupAllowOverride !== "undefined";
|
||||
const hasGroupAllowOverride = groupAllowOverride !== undefined;
|
||||
return {
|
||||
resolvedThreadId,
|
||||
dmThreadId,
|
||||
|
||||
@@ -165,7 +165,7 @@ export function extractTelegramAllowedEmojiReactions(
|
||||
return undefined;
|
||||
}
|
||||
const availableReactions = chat.available_reactions;
|
||||
if (typeof availableReactions === "undefined") {
|
||||
if (availableReactions === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
if (availableReactions == null) {
|
||||
|
||||
@@ -65,7 +65,7 @@ function truncate(text: string, maxLength: number): string {
|
||||
if (text.length <= maxLength) {
|
||||
return text;
|
||||
}
|
||||
return text.substring(0, maxLength - 3) + "...";
|
||||
return text.slice(0, maxLength - 3) + "...";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -788,7 +788,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
|
||||
type: "channel",
|
||||
requestingShip: senderShip,
|
||||
channelNest: nest,
|
||||
messagePreview: rawText.substring(0, 100),
|
||||
messagePreview: rawText.slice(0, 100),
|
||||
originalMessage: {
|
||||
messageId: messageId ?? "",
|
||||
messageText: rawText,
|
||||
@@ -991,7 +991,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
|
||||
const approval = createPendingApproval({
|
||||
type: "dm",
|
||||
requestingShip: senderShip,
|
||||
messagePreview: messageText.substring(0, 100),
|
||||
messagePreview: messageText.slice(0, 100),
|
||||
originalMessage: {
|
||||
messageId: messageId ?? "",
|
||||
messageText,
|
||||
|
||||
@@ -163,7 +163,7 @@ function assertSafeUploadResultUrl(rawUrl: string, label: string): string {
|
||||
}
|
||||
|
||||
function prefixEndpoint(endpoint: string): string {
|
||||
return endpoint.match(/https?:\/\//) ? endpoint : `https://${endpoint}`;
|
||||
return /https?:\/\//.test(endpoint) ? endpoint : `https://${endpoint}`;
|
||||
}
|
||||
|
||||
function sanitizeFileName(fileName: string): string {
|
||||
|
||||
@@ -222,8 +222,8 @@ export class UrbitSSEClient {
|
||||
buffer += chunk.toString();
|
||||
let eventEnd;
|
||||
while ((eventEnd = buffer.indexOf("\n\n")) !== -1) {
|
||||
const eventData = buffer.substring(0, eventEnd);
|
||||
buffer = buffer.substring(eventEnd + 2);
|
||||
const eventData = buffer.slice(0, eventEnd);
|
||||
buffer = buffer.slice(eventEnd + 2);
|
||||
this.processEvent(eventData);
|
||||
}
|
||||
}
|
||||
@@ -249,10 +249,10 @@ export class UrbitSSEClient {
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.startsWith("id: ")) {
|
||||
eventId = parseInt(line.substring(4), 10);
|
||||
eventId = Number.parseInt(line.slice(4), 10);
|
||||
}
|
||||
if (line.startsWith("data: ")) {
|
||||
data = line.substring(6);
|
||||
data = line.slice(6);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,7 +261,7 @@ export class UrbitSSEClient {
|
||||
}
|
||||
|
||||
// Track event ID and send ack if needed
|
||||
if (eventId !== null && !isNaN(eventId)) {
|
||||
if (eventId !== null && !Number.isNaN(eventId)) {
|
||||
if (eventId > this.lastHeardEventId) {
|
||||
this.lastHeardEventId = eventId;
|
||||
if (eventId - this.lastAcknowledgedEventId > this.ackThreshold) {
|
||||
|
||||
@@ -317,7 +317,7 @@ export class TwilioProvider implements VoiceCallProvider {
|
||||
type: "call.speech",
|
||||
transcript: speechResult,
|
||||
isFinal: true,
|
||||
confidence: parseFloat(params.get("Confidence") || "0.9"),
|
||||
confidence: Number.parseFloat(params.get("Confidence") || "0.9"),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ function extractHostname(hostHeader: string): string | null {
|
||||
if (endBracket === -1) {
|
||||
return null; // Malformed IPv6
|
||||
}
|
||||
hostname = hostHeader.substring(1, endBracket);
|
||||
hostname = hostHeader.slice(1, endBracket);
|
||||
return normalizeLowercaseStringOrEmpty(hostname);
|
||||
}
|
||||
|
||||
@@ -520,7 +520,7 @@ export function verifyTelnyxWebhook(
|
||||
return { ok: false, reason: "Missing signature or timestamp header" };
|
||||
}
|
||||
|
||||
const eventTimeSec = parseInt(timestamp, 10);
|
||||
const eventTimeSec = Number.parseInt(timestamp, 10);
|
||||
if (!Number.isFinite(eventTimeSec)) {
|
||||
return { ok: false, reason: "Invalid timestamp header" };
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ export function createEchoTracker(params: {
|
||||
}
|
||||
if (opts.logVerboseMessage) {
|
||||
params.logVerbose?.(
|
||||
`Added to echo detection set (size now: ${recentlySent.size}): ${text.substring(0, 50)}...`,
|
||||
`Added to echo detection set (size now: ${recentlySent.size}): ${text.slice(0, 50)}...`,
|
||||
);
|
||||
}
|
||||
trim();
|
||||
|
||||
@@ -641,7 +641,7 @@ export async function attachWebInboxToSocket(
|
||||
if (upsert.type === "append") {
|
||||
const APPEND_RECENT_GRACE_MS = 60_000;
|
||||
const msgTsRaw = msg.messageTimestamp;
|
||||
const msgTsNum = msgTsRaw != null ? Number(msgTsRaw) : NaN;
|
||||
const msgTsNum = msgTsRaw != null ? Number(msgTsRaw) : Number.NaN;
|
||||
const msgTsMs = Number.isFinite(msgTsNum) ? msgTsNum * 1000 : 0;
|
||||
if (msgTsMs < connectedAtMs - APPEND_RECENT_GRACE_MS) {
|
||||
continue;
|
||||
|
||||
@@ -69,7 +69,7 @@ describe("append upsert handling (#20952)", () => {
|
||||
{
|
||||
key: { id: "nan-1", fromMe: false, remoteJid: "120363@g.us" },
|
||||
message: { conversation: "bad timestamp" },
|
||||
messageTimestamp: NaN,
|
||||
messageTimestamp: Number.NaN,
|
||||
pushName: "BadTs",
|
||||
},
|
||||
],
|
||||
|
||||
@@ -12,9 +12,9 @@ type WhatsAppSetupConfig = {
|
||||
};
|
||||
|
||||
type WizardPromptHarness = {
|
||||
text: { (...args: unknown[]): unknown };
|
||||
select: { (...args: unknown[]): unknown };
|
||||
note: { (...args: unknown[]): unknown };
|
||||
text: (...args: unknown[]) => unknown;
|
||||
select: (...args: unknown[]) => unknown;
|
||||
note: (...args: unknown[]) => unknown;
|
||||
};
|
||||
|
||||
type QueuedWizardPrompterFactory<T extends WizardPromptHarness> = (params: {
|
||||
|
||||
Reference in New Issue
Block a user