Add configurable bypass options and UI

Introduce granular "bypass" configuration to control Napi2Native bypass features and expose it in the WebUI.

Key changes:
- Add bypass defaults to packages/napcat-core/external/napcat.json and BypassOptionsSchema in napcat-core helper config.
- Extend Napi2NativeLoader types: enableAllBypasses now accepts BypassOptions.
- Framework & Shell: load napcat.json (via json5), pass parsed bypass options to native loader, and log the applied config. Add json5 dependency.
- Shell: implement loadBypassConfig with a crash-recovery override (NAPCAT_BYPASS_DISABLE_LEVEL) and add master<->worker IPC (login-success) plus progressive bypass-disable strategy to mitigate repeated crashes before login.
- WebUI backend: add GET/Set endpoints for NapCat config (NapCatConfigRouter) with validation and JSON5-aware defaults.
- WebUI frontend: add BypassConfig page, types, and controller methods to get/set bypass config.
- Update package.json to include json5 and update pnpm lockfile; native binaries (.node / ffmpeg.dll) also updated.

This enables operators to tune bypass behavior per-installation and to have an in-UI control for toggling anti-detection features; it also adds progressive fallback behavior to help recover from crashes caused by bypasses.
This commit is contained in:
手瓜一十雪
2026-02-18 22:09:27 +08:00
parent 9998207346
commit b9f61cc0ee
20 changed files with 541 additions and 15 deletions

View File

@@ -5,5 +5,13 @@
"consoleLogLevel": "info",
"packetBackend": "auto",
"packetServer": "",
"o3HookMode": 1
"o3HookMode": 1,
"bypass": {
"hook": true,
"module": true,
"window": true,
"js": true,
"container": true,
"maps": true
}
}

View File

@@ -3,6 +3,15 @@ import { NapCatCore } from '@/napcat-core/index';
import { Type, Static } from '@sinclair/typebox';
import { AnySchema } from 'ajv';
export const BypassOptionsSchema = Type.Object({
hook: Type.Boolean({ default: true }),
module: Type.Boolean({ default: true }),
window: Type.Boolean({ default: true }),
js: Type.Boolean({ default: true }),
container: Type.Boolean({ default: true }),
maps: Type.Boolean({ default: true }),
});
export const NapcatConfigSchema = Type.Object({
fileLog: Type.Boolean({ default: false }),
consoleLog: Type.Boolean({ default: true }),
@@ -11,6 +20,7 @@ export const NapcatConfigSchema = Type.Object({
packetBackend: Type.String({ default: 'auto' }),
packetServer: Type.String({ default: '' }),
o3HookMode: Type.Number({ default: 0 }),
bypass: Type.Optional(BypassOptionsSchema),
});
export type NapcatConfig = Static<typeof NapcatConfigSchema>;

View File

@@ -4,10 +4,19 @@ import fs from 'fs';
import { constants } from 'node:os';
import { LogWrapper } from '../../helper/log';
export interface BypassOptions {
hook?: boolean;
module?: boolean;
window?: boolean;
js?: boolean;
container?: boolean;
maps?: boolean;
}
export interface Napi2NativeExportType {
initHook?: (send: string, recv: string) => boolean;
setVerbose?: (verbose: boolean) => void; // 默认关闭日志
enableAllBypasses?: () => void;
enableAllBypasses?: (options?: BypassOptions) => boolean;
}
export class Napi2NativeLoader {

View File

@@ -2,7 +2,10 @@ import { NapCatPathWrapper } from 'napcat-common/src/path';
import { InitWebUi, WebUiConfig, webUiRuntimePort } from 'napcat-webui-backend/index';
import { NapCatAdapterManager } from 'napcat-adapter';
import { NativePacketHandler } from 'napcat-core/packet/handler/client';
import { Napi2NativeLoader } from 'napcat-core/packet/handler/napi2nativeLoader';
import { Napi2NativeLoader, BypassOptions } from 'napcat-core/packet/handler/napi2nativeLoader';
import path from 'path';
import fs from 'fs';
import json5 from 'json5';
import { FFmpegService } from 'napcat-core/helper/ffmpeg/ffmpeg';
import { logSubscription, LogWrapper } from 'napcat-core/helper/log';
import { QQBasicInfoWrapper } from '@/napcat-core/helper/qq-basic-info';
@@ -44,10 +47,29 @@ export async function NCoreInitFramework (
const napi2nativeLoader = new Napi2NativeLoader({ logger }); // 初始化 Napi2NativeLoader 用于后续使用
//console.log('[NapCat] [Napi2NativeLoader]', napi2nativeLoader.nativeExports.enableAllBypasses?.());
if (process.env['NAPCAT_DISABLE_BYPASS'] !== '1') {
const bypassEnabled = napi2nativeLoader.nativeExports.enableAllBypasses?.();
if (bypassEnabled) {
logger.log('[NapCat] Napi2NativeLoader: 已启用Bypass');
// 读取 napcat.json 配置
let bypassOptions: BypassOptions = {
hook: false,
module: false,
window: false,
js: false,
container: false,
maps: false,
};
try {
const configFile = path.join(pathWrapper.configPath, 'napcat.json');
if (fs.existsSync(configFile)) {
const content = fs.readFileSync(configFile, 'utf-8');
const config = json5.parse(content);
if (config.bypass && typeof config.bypass === 'object') {
bypassOptions = { ...bypassOptions, ...config.bypass };
}
}
} catch (e) {
logger.logWarn('[NapCat] 读取 napcat.json bypass 配置失败,已全部禁用:', e);
}
const bypassEnabled = napi2nativeLoader.nativeExports.enableAllBypasses?.(bypassOptions);
logger.log('[NapCat] Napi2NativeLoader: Framework模式Bypass配置:', bypassOptions);
} else {
logger.log('[NapCat] Napi2NativeLoader: Bypass已通过环境变量禁用');
}

View File

@@ -22,7 +22,8 @@
"napcat-adapter": "workspace:*",
"napcat-webui-backend": "workspace:*",
"napcat-vite": "workspace:*",
"napcat-qrcode": "workspace:*"
"napcat-qrcode": "workspace:*",
"json5": "^3.2.2"
},
"devDependencies": {
"@types/node": "^22.0.1"

View File

@@ -20,6 +20,7 @@ import { hostname, systemVersion } from 'napcat-common/src/system';
import path from 'path';
import fs from 'fs';
import os from 'os';
import json5 from 'json5';
import { LoginListItem, NodeIKernelLoginService } from 'napcat-core/services';
import qrcode from 'napcat-qrcode/lib/main';
import { NapCatAdapterManager } from 'napcat-adapter';
@@ -30,13 +31,72 @@ import { NodeIO3MiscListener } from 'napcat-core/listeners/NodeIO3MiscListener';
import { sleep } from 'napcat-common/src/helper';
import { FFmpegService } from '@/napcat-core/helper/ffmpeg/ffmpeg';
import { NativePacketHandler } from 'napcat-core/packet/handler/client';
import { Napi2NativeLoader } from 'napcat-core/packet/handler/napi2nativeLoader';
import { Napi2NativeLoader, BypassOptions } from 'napcat-core/packet/handler/napi2nativeLoader';
import { logSubscription, LogWrapper } from '@/napcat-core/helper/log';
import { proxiedListenerOf } from '@/napcat-core/helper/proxy-handler';
import { QQBasicInfoWrapper } from '@/napcat-core/helper/qq-basic-info';
import { statusHelperSubscription } from '@/napcat-core/helper/status';
import { applyPendingUpdates } from '@/napcat-webui-backend/src/api/UpdateNapCat';
import { connectToNamedPipe } from './pipe';
/**
* 读取 napcat.json 配置中的 bypass 选项,并根据分步禁用级别覆盖
*
* 分步禁用级别 (NAPCAT_BYPASS_DISABLE_LEVEL):
* 0: 使用配置文件原始值(全部启用或用户自定义)
* 1: 强制禁用 hook
* 2: 强制禁用 hook + module
* 3: 强制禁用全部 bypass
*/
function loadBypassConfig (configPath: string, logger: LogWrapper): BypassOptions {
const defaultOptions: BypassOptions = {
hook: true,
module: true,
window: true,
js: true,
container: true,
maps: true,
};
let options = { ...defaultOptions };
try {
const configFile = path.join(configPath, 'napcat.json');
if (fs.existsSync(configFile)) {
const content = fs.readFileSync(configFile, 'utf-8');
const config = json5.parse(content);
if (config.bypass && typeof config.bypass === 'object') {
options = { ...defaultOptions, ...config.bypass };
}
}
} catch (e) {
logger.logWarn('[NapCat] 读取 bypass 配置失败,使用默认值:', e);
}
// 根据分步禁用级别覆盖配置
const disableLevel = parseInt(process.env['NAPCAT_BYPASS_DISABLE_LEVEL'] || '0', 10);
if (disableLevel > 0) {
const levelDescriptions = ['全部启用', '禁用 hook', '禁用 hook + module', '全部禁用 bypass'];
logger.logWarn(`[NapCat] 崩溃恢复:当前 bypass 禁用级别 ${disableLevel} (${levelDescriptions[disableLevel] ?? '未知'})`);
if (disableLevel >= 1) {
options.hook = false;
}
if (disableLevel >= 2) {
options.module = false;
}
if (disableLevel >= 3) {
options.hook = false;
options.module = false;
options.window = false;
options.js = false;
options.container = false;
options.maps = false;
}
}
return options;
}
// NapCat Shell App ES 入口文件
async function handleUncaughtExceptions (logger: LogWrapper) {
process.on('uncaughtException', (err) => {
@@ -406,7 +466,9 @@ export async function NCoreInitShell () {
}
// wrapper.node 加载后立刻启用 Bypass可通过环境变量禁用
if (process.env['NAPCAT_DISABLE_BYPASS'] !== '1') {
const bypassEnabled = napi2nativeLoader.nativeExports.enableAllBypasses?.();
const bypassOptions = loadBypassConfig(pathWrapper.configPath, logger);
logger.logDebug('[NapCat] Bypass 配置:', bypassOptions);
const bypassEnabled = napi2nativeLoader.nativeExports.enableAllBypasses?.(bypassOptions);
if (bypassEnabled) {
logger.log('[NapCat] Napi2NativeLoader: 已启用Bypass');
}
@@ -463,6 +525,13 @@ export async function NCoreInitShell () {
o3Service.reportAmgomWeather('login', 'a1', [dataTimestape, '0', '0']);
const selfInfo = await handleLogin(loginService, logger, pathWrapper, quickLoginUin, historyLoginList);
// 登录成功后通知 Master 进程(用于切换崩溃重试策略)
if (typeof process.send === 'function') {
process.send({ type: 'login-success' });
logger.log('[NapCat] 已通知主进程登录成功');
}
const amgomDataPiece = 'eb1fd6ac257461580dc7438eb099f23aae04ca679f4d88f53072dc56e3bb1129';
o3Service.setAmgomDataPiece(basicInfoWrapper.QQVersionAppid, new Uint8Array(Buffer.from(amgomDataPiece, 'hex')));

View File

@@ -45,7 +45,7 @@ const ENV = {
// Worker 消息类型
interface WorkerMessage {
type: 'restart' | 'restart-prepare' | 'shutdown';
type: 'restart' | 'restart-prepare' | 'shutdown' | 'login-success';
secretKey?: string;
port?: number;
}
@@ -65,6 +65,16 @@ const recentCrashTimestamps: number[] = [];
const CRASH_TIME_WINDOW = 10000; // 10秒时间窗口
const MAX_CRASHES_IN_WINDOW = 3; // 最大崩溃次数
// 分步禁用策略:记录当前禁用级别 (0-3)
// 0: 全部启用
// 1: 禁用 hook
// 2: 禁用 hook + module
// 3: 全部禁用
let bypassDisableLevel = 0;
// 是否已登录成功(登录后不再使用分步禁用策略)
let isLoggedIn = false;
/**
* 获取进程类型名称(用于日志)
*/
@@ -154,6 +164,8 @@ async function cleanupOrphanedProcesses (excludePids: number[]): Promise<void> {
*/
export async function restartWorker (secretKey?: string, port?: number): Promise<void> {
isRestarting = true;
isLoggedIn = false;
bypassDisableLevel = 0;
if (!currentWorker) {
logger.logWarn('[NapCat] [Process] 没有运行中的Worker进程');
@@ -246,6 +258,7 @@ async function startWorker (passQuickLogin: boolean = true, secretKey?: string,
NAPCAT_WORKER_PROCESS: '1',
...(secretKey ? { NAPCAT_WEBUI_JWT_SECRET_KEY: secretKey } : {}),
...(preferredPort ? { NAPCAT_WEBUI_PREFERRED_PORT: String(preferredPort) } : {}),
...(bypassDisableLevel > 0 ? { NAPCAT_BYPASS_DISABLE_LEVEL: String(bypassDisableLevel) } : {}),
},
stdio: isElectron ? 'pipe' : ['inherit', 'pipe', 'pipe', 'ipc'],
});
@@ -275,6 +288,9 @@ async function startWorker (passQuickLogin: boolean = true, secretKey?: string,
restartWorker(message.secretKey, message.port).catch(e => {
logger.logError(`[NapCat] [${processType}] 重启Worker进程失败:`, e);
});
} else if (message.type === 'login-success') {
isLoggedIn = true;
logger.log(`[NapCat] [${processType}] Worker进程已登录成功切换到正常重试策略`);
}
}
});
@@ -297,13 +313,34 @@ async function startWorker (passQuickLogin: boolean = true, secretKey?: string,
// 记录本次崩溃
recentCrashTimestamps.push(now);
// 检查是否超过崩溃阈值
if (recentCrashTimestamps.length >= MAX_CRASHES_IN_WINDOW) {
logger.logError(`[NapCat] [${processType}] Worker进程在 ${CRASH_TIME_WINDOW / 1000} 秒内异常退出 ${MAX_CRASHES_IN_WINDOW} 次,主进程退出`);
process.exit(1);
// 登录前:使用分步禁用策略
if (!isLoggedIn) {
// 每次崩溃提升禁用级别
bypassDisableLevel = Math.min(bypassDisableLevel + 1, 3);
const levelDescriptions = [
'全部启用',
'禁用 hook',
'禁用 hook + module',
'全部禁用 bypass'
];
if (bypassDisableLevel >= 3 && recentCrashTimestamps.length >= MAX_CRASHES_IN_WINDOW) {
logger.logError(`[NapCat] [${processType}] Worker进程在 ${CRASH_TIME_WINDOW / 1000} 秒内异常退出 ${MAX_CRASHES_IN_WINDOW} 次,已尝试全部禁用策略,主进程退出`);
process.exit(1);
}
logger.logWarn(`[NapCat] [${processType}] Worker进程意外退出 (${recentCrashTimestamps.length}/${MAX_CRASHES_IN_WINDOW}),切换到禁用级别 ${bypassDisableLevel}: ${levelDescriptions[bypassDisableLevel]},正在尝试重新拉起...`);
} else {
// 登录后:使用正常重试策略
if (recentCrashTimestamps.length >= MAX_CRASHES_IN_WINDOW) {
logger.logError(`[NapCat] [${processType}] Worker进程在 ${CRASH_TIME_WINDOW / 1000} 秒内异常退出 ${MAX_CRASHES_IN_WINDOW} 次,主进程退出`);
process.exit(1);
}
logger.logWarn(`[NapCat] [${processType}] Worker进程意外退出 (${recentCrashTimestamps.length}/${MAX_CRASHES_IN_WINDOW}),正在尝试重新拉起...`);
}
logger.logWarn(`[NapCat] [${processType}] Worker进程意外退出 (${recentCrashTimestamps.length}/${MAX_CRASHES_IN_WINDOW}),正在尝试重新拉起...`);
startWorker(true).catch(e => {
logger.logError(`[NapCat] [${processType}] 重新拉起Worker进程失败:`, e);
});

View File

@@ -25,6 +25,7 @@
"napcat-qrcode": "workspace:*"
},
"devDependencies": {
"json5": "^2.2.3",
"@types/node": "^22.0.1",
"napcat-vite": "workspace:*"
},

View File

@@ -0,0 +1,97 @@
import { RequestHandler } from 'express';
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
import { resolve } from 'node:path';
import { webUiPathWrapper } from '@/napcat-webui-backend/index';
import { sendError, sendSuccess } from '@/napcat-webui-backend/src/utils/response';
import json5 from 'json5';
// NapCat 配置默认值
const defaultNapcatConfig = {
fileLog: false,
consoleLog: true,
fileLogLevel: 'debug',
consoleLogLevel: 'info',
packetBackend: 'auto',
packetServer: '',
o3HookMode: 1,
bypass: {
hook: true,
module: true,
window: true,
js: true,
container: true,
maps: true,
},
};
/**
* 获取 napcat 配置文件路径
*/
function getNapcatConfigPath (): string {
return resolve(webUiPathWrapper.configPath, './napcat.json');
}
/**
* 读取 napcat 配置
*/
function readNapcatConfig (): Record<string, unknown> {
const configPath = getNapcatConfigPath();
try {
if (existsSync(configPath)) {
const content = readFileSync(configPath, 'utf-8');
return { ...defaultNapcatConfig, ...json5.parse(content) };
}
} catch (_e) {
// 读取失败,使用默认值
}
return { ...defaultNapcatConfig };
}
/**
* 写入 napcat 配置
*/
function writeNapcatConfig (config: Record<string, unknown>): void {
const configPath = resolve(webUiPathWrapper.configPath, './napcat.json');
mkdirSync(webUiPathWrapper.configPath, { recursive: true });
writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
}
// 获取 NapCat 配置
export const NapCatGetConfigHandler: RequestHandler = (_, res) => {
try {
const config = readNapcatConfig();
return sendSuccess(res, config);
} catch (e) {
return sendError(res, 'Config Get Error: ' + (e as Error).message);
}
};
// 设置 NapCat 配置
export const NapCatSetConfigHandler: RequestHandler = (req, res) => {
try {
const newConfig = req.body;
if (!newConfig || typeof newConfig !== 'object') {
return sendError(res, 'config is empty or invalid');
}
// 读取当前配置并合并
const currentConfig = readNapcatConfig();
const mergedConfig = { ...currentConfig, ...newConfig };
// 验证 bypass 字段
if (mergedConfig.bypass && typeof mergedConfig.bypass === 'object') {
const bypass = mergedConfig.bypass as Record<string, unknown>;
const validKeys = ['hook', 'module', 'window', 'js', 'container', 'maps'];
for (const key of validKeys) {
if (key in bypass && typeof bypass[key] !== 'boolean') {
return sendError(res, `bypass.${key} must be boolean`);
}
}
}
writeNapcatConfig(mergedConfig);
return sendSuccess(res, null);
} catch (e) {
return sendError(res, 'Config Set Error: ' + (e as Error).message);
}
};

View File

@@ -0,0 +1,12 @@
import { Router } from 'express';
import { NapCatGetConfigHandler, NapCatSetConfigHandler } from '@/napcat-webui-backend/src/api/NapCatConfig';
const router: Router = Router();
// router:获取 NapCat 配置
router.get('/GetConfig', NapCatGetConfigHandler);
// router:设置 NapCat 配置
router.post('/SetConfig', NapCatSetConfigHandler);
export { router as NapCatConfigRouter };

View File

@@ -19,6 +19,7 @@ import DebugRouter from '@/napcat-webui-backend/src/api/Debug';
import { ProcessRouter } from './Process';
import { PluginRouter } from './Plugin';
import { MirrorRouter } from './Mirror';
import { NapCatConfigRouter } from './NapCatConfig';
const router: Router = Router();
@@ -53,5 +54,7 @@ router.use('/Process', ProcessRouter);
router.use('/Plugin', PluginRouter);
// router:镜像管理相关路由
router.use('/Mirror', MirrorRouter);
// router:NapCat配置相关路由
router.use('/NapCatConfig', NapCatConfigRouter);
export { router as ALLRouter };

View File

@@ -178,5 +178,23 @@ export default class QQManager {
public static async resetLinuxDeviceID () {
await serverRequest.post<ServerResponse<null>>('/QQLogin/ResetLinuxDeviceID');
}
// ============================================================
// NapCat 配置管理
// ============================================================
public static async getNapCatConfig () {
const { data } = await serverRequest.get<ServerResponse<NapCatConfig>>(
'/NapCatConfig/GetConfig'
);
return data.data;
}
public static async setNapCatConfig (config: Partial<NapCatConfig>) {
await serverRequest.post<ServerResponse<null>>(
'/NapCatConfig/SetConfig',
config
);
}
}

View File

@@ -0,0 +1,169 @@
import { useEffect, useState } from 'react';
import { Controller, useForm } from 'react-hook-form';
import toast from 'react-hot-toast';
import SaveButtons from '@/components/button/save_buttons';
import PageLoading from '@/components/page_loading';
import SwitchCard from '@/components/switch_card';
import QQManager from '@/controllers/qq_manager';
interface BypassFormData {
hook: boolean;
module: boolean;
window: boolean;
js: boolean;
container: boolean;
maps: boolean;
}
const defaultBypass: BypassFormData = {
hook: true,
module: true,
window: true,
js: true,
container: true,
maps: true,
};
const BypassConfigCard = () => {
const [loading, setLoading] = useState(true);
const {
control,
handleSubmit,
formState: { isSubmitting },
setValue,
} = useForm<BypassFormData>({
defaultValues: defaultBypass,
});
const loadConfig = async (showTip = false) => {
try {
setLoading(true);
const config = await QQManager.getNapCatConfig();
const bypass = config.bypass ?? defaultBypass;
setValue('hook', bypass.hook ?? true);
setValue('module', bypass.module ?? true);
setValue('window', bypass.window ?? true);
setValue('js', bypass.js ?? true);
setValue('container', bypass.container ?? true);
setValue('maps', bypass.maps ?? true);
if (showTip) toast.success('刷新成功');
} catch (error) {
const msg = (error as Error).message;
toast.error(`获取配置失败: ${msg}`);
} finally {
setLoading(false);
}
};
const onSubmit = handleSubmit(async (data) => {
try {
await QQManager.setNapCatConfig({ bypass: data });
toast.success('保存成功,重启后生效');
} catch (error) {
const msg = (error as Error).message;
toast.error(`保存失败: ${msg}`);
}
});
const onReset = () => {
loadConfig();
};
const onRefresh = async () => {
await loadConfig(true);
};
useEffect(() => {
loadConfig();
}, []);
if (loading) return <PageLoading loading />;
return (
<>
<title> - NapCat WebUI</title>
<div className='flex flex-col gap-1 mb-2'>
<h3 className='text-lg font-semibold text-default-700'></h3>
<p className='text-sm text-default-500'>
Napi2Native
</p>
</div>
<Controller
control={control}
name='hook'
render={({ field }) => (
<SwitchCard
{...field}
label='Hook'
description='hook特征隐藏'
/>
)}
/>
<Controller
control={control}
name='module'
render={({ field }) => (
<SwitchCard
{...field}
label='Module'
description='加载模块隐藏'
/>
)}
/>
<Controller
control={control}
name='window'
render={({ field }) => (
<SwitchCard
{...field}
label='Window'
description='窗口伪造'
/>
)}
/>
<Controller
control={control}
name='js'
render={({ field }) => (
<SwitchCard
{...field}
label='JS'
description='JS Bypass保留'
/>
)}
/>
<Controller
control={control}
name='container'
render={({ field }) => (
<SwitchCard
{...field}
label='Container'
description='容器反检测'
/>
)}
/>
<Controller
control={control}
name='maps'
render={({ field }) => (
<SwitchCard
{...field}
label='Maps'
description='linux maps反检测'
/>
)}
/>
<SaveButtons
onSubmit={onSubmit}
reset={onReset}
isSubmitting={isSubmitting}
refresh={onRefresh}
/>
</>
);
};
export default BypassConfigCard;

View File

@@ -14,6 +14,7 @@ import SSLConfigCard from './ssl';
import ThemeConfigCard from './theme';
import WebUIConfigCard from './webui';
import BackupConfigCard from './backup';
import BypassConfigCard from './bypass';
export interface ConfigPageProps {
children?: React.ReactNode;
@@ -114,6 +115,11 @@ export default function ConfigPage () {
<BackupConfigCard />
</ConfigPageItem>
</Tab>
<Tab title='Bypass配置' key='bypass'>
<ConfigPageItem>
<BypassConfigCard />
</ConfigPageItem>
</Tab>
</Tabs>
</section>
);

View File

@@ -0,0 +1,19 @@
interface BypassOptions {
hook: boolean;
module: boolean;
window: boolean;
js: boolean;
container: boolean;
maps: boolean;
}
interface NapCatConfig {
fileLog: boolean;
consoleLog: boolean;
fileLogLevel: string;
consoleLogLevel: string;
packetBackend: string;
packetServer: string;
o3HookMode: number;
bypass?: BypassOptions;
}

45
pnpm-lock.yaml generated
View File

@@ -136,6 +136,9 @@ importers:
packages/napcat-framework:
dependencies:
json5:
specifier: ^2.2.3
version: 2.2.3
napcat-adapter:
specifier: workspace:*
version: link:../napcat-adapter
@@ -357,6 +360,9 @@ importers:
'@types/node':
specifier: ^22.0.1
version: 22.19.1
json5:
specifier: ^2.2.3
version: 2.2.3
napcat-vite:
specifier: workspace:*
version: link:../napcat-vite
@@ -1907,89 +1913,105 @@ packages:
resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@img/sharp-libvips-linux-arm@1.2.4':
resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==}
cpu: [arm]
os: [linux]
libc: [glibc]
'@img/sharp-libvips-linux-ppc64@1.2.4':
resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@img/sharp-libvips-linux-riscv64@1.2.4':
resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@img/sharp-libvips-linux-s390x@1.2.4':
resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@img/sharp-libvips-linux-x64@1.2.4':
resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@img/sharp-libvips-linuxmusl-arm64@1.2.4':
resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@img/sharp-libvips-linuxmusl-x64@1.2.4':
resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==}
cpu: [x64]
os: [linux]
libc: [musl]
'@img/sharp-linux-arm64@0.34.5':
resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@img/sharp-linux-arm@0.34.5':
resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm]
os: [linux]
libc: [glibc]
'@img/sharp-linux-ppc64@0.34.5':
resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@img/sharp-linux-riscv64@0.34.5':
resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@img/sharp-linux-s390x@0.34.5':
resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@img/sharp-linux-x64@0.34.5':
resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
libc: [glibc]
'@img/sharp-linuxmusl-arm64@0.34.5':
resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [linux]
libc: [musl]
'@img/sharp-linuxmusl-x64@0.34.5':
resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
libc: [musl]
'@img/sharp-wasm32@0.34.5':
resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==}
@@ -2740,56 +2762,67 @@ packages:
resolution: {integrity: sha512-EPlb95nUsz6Dd9Qy13fI5kUPXNSljaG9FiJ4YUGU1O/Q77i5DYFW5KR8g1OzTcdZUqQQ1KdDqsTohdFVwCwjqg==}
cpu: [arm]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.53.2':
resolution: {integrity: sha512-BOmnVW+khAUX+YZvNfa0tGTEMVVEerOxN0pDk2E6N6DsEIa2Ctj48FOMfNDdrwinocKaC7YXUZ1pHlKpnkja/Q==}
cpu: [arm]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.53.2':
resolution: {integrity: sha512-Xt2byDZ+6OVNuREgBXr4+CZDJtrVso5woFtpKdGPhpTPHcNG7D8YXeQzpNbFRxzTVqJf7kvPMCub/pcGUWgBjA==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.53.2':
resolution: {integrity: sha512-+LdZSldy/I9N8+klim/Y1HsKbJ3BbInHav5qE9Iy77dtHC/pibw1SR/fXlWyAk0ThnpRKoODwnAuSjqxFRDHUQ==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-loong64-gnu@4.53.2':
resolution: {integrity: sha512-8ms8sjmyc1jWJS6WdNSA23rEfdjWB30LH8Wqj0Cqvv7qSHnvw6kgMMXRdop6hkmGPlyYBdRPkjJnj3KCUHV/uQ==}
cpu: [loong64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-ppc64-gnu@4.53.2':
resolution: {integrity: sha512-3HRQLUQbpBDMmzoxPJYd3W6vrVHOo2cVW8RUo87Xz0JPJcBLBr5kZ1pGcQAhdZgX9VV7NbGNipah1omKKe23/g==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-gnu@4.53.2':
resolution: {integrity: sha512-fMjKi+ojnmIvhk34gZP94vjogXNNUKMEYs+EDaB/5TG/wUkoeua7p7VCHnE6T2Tx+iaghAqQX8teQzcvrYpaQA==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-musl@4.53.2':
resolution: {integrity: sha512-XuGFGU+VwUUV5kLvoAdi0Wz5Xbh2SrjIxCtZj6Wq8MDp4bflb/+ThZsVxokM7n0pcbkEr2h5/pzqzDYI7cCgLQ==}
cpu: [riscv64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-s390x-gnu@4.53.2':
resolution: {integrity: sha512-w6yjZF0P+NGzWR3AXWX9zc0DNEGdtvykB03uhonSHMRa+oWA6novflo2WaJr6JZakG2ucsyb+rvhrKac6NIy+w==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.53.2':
resolution: {integrity: sha512-yo8d6tdfdeBArzC7T/PnHd7OypfI9cbuZzPnzLJIyKYFhAQ8SvlkKtKBMbXDxe1h03Rcr7u++nFS7tqXz87Gtw==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.53.2':
resolution: {integrity: sha512-ah59c1YkCxKExPP8O9PwOvs+XRLKwh/mV+3YdKqQ5AMQ0r4M4ZDuOrpWkUaqO7fzAHdINzV9tEVu8vNw48z0lA==}
cpu: [x64]
os: [linux]
libc: [musl]
'@rollup/rollup-openharmony-arm64@4.53.2':
resolution: {integrity: sha512-4VEd19Wmhr+Zy7hbUsFZ6YXEiP48hE//KPLCSVNY5RMGX2/7HZ+QkN55a3atM1C/BZCGIgqN+xrVgtdak2S9+A==}
@@ -2864,24 +2897,28 @@ packages:
engines: {node: '>=10'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@swc/core-linux-arm64-musl@1.15.1':
resolution: {integrity: sha512-fKzP9mRQGbhc5QhJPIsqKNNX/jyWrZgBxmo3Nz1SPaepfCUc7RFmtcJQI5q8xAun3XabXjh90wqcY/OVyg2+Kg==}
engines: {node: '>=10'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@swc/core-linux-x64-gnu@1.15.1':
resolution: {integrity: sha512-ZLjMi138uTJxb+1wzo4cB8mIbJbAsSLWRNeHc1g1pMvkERPWOGlem+LEYkkzaFzCNv1J8aKcL653Vtw8INHQeg==}
engines: {node: '>=10'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@swc/core-linux-x64-musl@1.15.1':
resolution: {integrity: sha512-jvSI1IdsIYey5kOITzyajjofXOOySVitmLxb45OPUjoNojql4sDojvlW5zoHXXFePdA6qAX4Y6KbzAOV3T3ctA==}
engines: {node: '>=10'}
cpu: [x64]
os: [linux]
libc: [musl]
'@swc/core-win32-arm64-msvc@1.15.1':
resolution: {integrity: sha512-X/FcDtNrDdY9r4FcXHt9QxUqC/2FbQdvZobCKHlHe8vTSKhUHOilWl5EBtkFVfsEs4D5/yAri9e3bJbwyBhhBw==}
@@ -3246,41 +3283,49 @@ packages:
resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@unrs/resolver-binding-linux-arm64-musl@1.11.1':
resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@unrs/resolver-binding-linux-ppc64-gnu@1.11.1':
resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@unrs/resolver-binding-linux-riscv64-gnu@1.11.1':
resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@unrs/resolver-binding-linux-riscv64-musl@1.11.1':
resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==}
cpu: [riscv64]
os: [linux]
libc: [musl]
'@unrs/resolver-binding-linux-s390x-gnu@1.11.1':
resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@unrs/resolver-binding-linux-x64-gnu@1.11.1':
resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@unrs/resolver-binding-linux-x64-musl@1.11.1':
resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==}
cpu: [x64]
os: [linux]
libc: [musl]
'@unrs/resolver-binding-wasm32-wasi@1.11.1':
resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==}