From fa80441e360bf836774146120c28aa28a97ca603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=8B=E7=93=9C=E4=B8=80=E5=8D=81=E9=9B=AA?= Date: Sat, 15 Nov 2025 16:21:59 +0800 Subject: [PATCH] Add ESLint config and update code style Introduced a new eslint.config.js using neostandard and added related devDependencies. Updated codebase for consistent formatting, spacing, and function declarations. Minor refactoring and cleanup across multiple files to improve readability and maintain code style compliance. --- eslint.config.js | 52 +++ package.json | 6 +- packages/napcat-common/src/helper.ts | 30 +- packages/napcat-common/src/store.ts | 2 +- packages/napcat-common/src/types.ts | 2 +- packages/napcat-common/src/version.ts | 1 - .../adapters/NodeIDependsAdapter.ts | 2 +- packages/napcat-core/apis/file.ts | 3 +- packages/napcat-core/helper/event.ts | 12 +- .../helper/ffmpeg/ffmpeg-addon-adapter.ts | 4 +- packages/napcat-core/helper/ffmpeg/ffmpeg.ts | 1 - packages/napcat-core/index.ts | 14 +- .../packet/context/loggerContext.ts | 1 - packages/napcat-core/packet/handler/client.ts | 1 - .../napcat-core/packet/handler/eventList.ts | 6 +- .../packet/handler/serviceRegister.ts | 36 +- .../napcat-core/protocol/OlpushSerivce.ts | 65 ++-- .../services/NodeIKernelBuddyService.ts | 1 - packages/napcat-core/types/element.ts | 10 +- packages/napcat-develop/index.js | 4 +- packages/napcat-develop/loadNapCat.cjs | 12 +- packages/napcat-framework/vite.config.ts | 12 +- .../napcat-onebot/action/auto-register.ts | 4 +- packages/napcat-onebot/action/index.ts | 4 +- packages/napcat-onebot/api/file.ts | 316 +++++++++--------- packages/napcat-onebot/api/group.ts | 31 +- packages/napcat-onebot/index.ts | 36 +- packages/napcat-protobuf/NapProto.ts | 240 ++++++------- packages/napcat-shell-loader/loadNapCat.js | 4 +- packages/napcat-shell/base.ts | 2 +- packages/napcat-shell/vite.config.ts | 16 +- packages/napcat-test/sha1Stream.test.ts | 2 +- packages/napcat-test/vitest.config.ts | 2 +- packages/napcat-vite/vite-auto-include.js | 118 +++---- packages/napcat-vite/vite-plugin-version.js | 60 ++-- .../napcat-webui-backend/src/helper/config.ts | 2 +- .../napcat-webui-frontend/eslint.config.mjs | 2 - .../napcat-webui-frontend/postcss.config.js | 6 +- .../src/types/react-color.d.ts | 2 +- .../napcat-webui-frontend/tailwind.config.js | 36 +- packages/napcat-webui-frontend/vite.config.ts | 46 +-- vitest.config.ts | 2 +- 42 files changed, 628 insertions(+), 580 deletions(-) create mode 100644 eslint.config.js delete mode 100644 packages/napcat-webui-frontend/eslint.config.mjs diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 00000000..b413ff63 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,52 @@ +import neostandard from 'neostandard'; + +/** 尾随逗号 */ +const commaDangle = val => { + if (val?.rules?.['@stylistic/comma-dangle']?.[0] === 'warn') { + const rule = val?.rules?.['@stylistic/comma-dangle']?.[1]; + Object.keys(rule).forEach(key => { + rule[key] = 'always-multiline'; + }); + val.rules['@stylistic/comma-dangle'][1] = rule; + } + + /** 三元表达式 */ + if (val?.rules?.['@stylistic/indent']) { + val.rules['@stylistic/indent'][2] = { + ...val.rules?.['@stylistic/indent']?.[2], + flatTernaryExpressions: true, + offsetTernaryExpressions: false, + }; + } + + /** 支持下划线 - 禁用 camelcase 规则 */ + if (val?.rules?.camelcase) { + val.rules.camelcase = 'off'; + } + + /** 未使用的变量强制报错 */ + if (val?.rules?.['@typescript-eslint/no-unused-vars']) { + val.rules['@typescript-eslint/no-unused-vars'] = ['error', { + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + caughtErrorsIgnorePattern: '^_', + }]; + } + + return val; +}; + +/** 忽略的文件 */ +const ignores = [ + 'node_modules', + '**/dist/**', + 'launcher', +]; + +const options = neostandard({ + ts: true, + ignores, + semi: true, // 强制使用分号 +}).map(commaDangle); + +export default options; diff --git a/package.json b/package.json index 295ee533..3c38cd5a 100644 --- a/package.json +++ b/package.json @@ -11,13 +11,17 @@ "dev:shell": "pnpm --filter napcat-develop run dev || exit 1", "typecheck": "pnpm -r --if-present run typecheck", "test": "pnpm --filter napcat-test run test", - "test:ui": "pnpm --filter napcat-test run test:ui" + "test:ui": "pnpm --filter napcat-test run test:ui", + "lint": "eslint .", + "lint:fix": "eslint . --fix" }, "devDependencies": { "@rollup/plugin-node-resolve": "^16.0.3", "@vitejs/plugin-react-swc": "^4.2.2", "@vitest/ui": "^4.0.9", + "eslint": "^9.39.1", "inversify": "^7.10.4", + "neostandard": "^0.12.2", "reflect-metadata": "^0.2.2", "typescript": "^5.3.0", "vite": "^6.4.1", diff --git a/packages/napcat-common/src/helper.ts b/packages/napcat-common/src/helper.ts index 093e9df1..c1809c0c 100644 --- a/packages/napcat-common/src/helper.ts +++ b/packages/napcat-common/src/helper.ts @@ -3,7 +3,7 @@ import fs from 'fs'; import os from 'node:os'; import { QQVersionConfigType, QQLevel } from './types'; -export async function solveProblem any>(func: T, ...args: Parameters): Promise | undefined> { +export async function solveProblem any> (func: T, ...args: Parameters): Promise | undefined> { return new Promise | undefined>((resolve) => { try { const result = func(...args); @@ -14,7 +14,7 @@ export async function solveProblem any>(func: T, .. }); } -export async function solveAsyncProblem Promise>(func: T, ...args: Parameters): Promise> | undefined> { +export async function solveAsyncProblem Promise> (func: T, ...args: Parameters): Promise> | undefined> { return new Promise> | undefined>((resolve) => { func(...args).then((result) => { resolve(result); @@ -24,18 +24,18 @@ export async function solveAsyncProblem Promise { +export function sleep (ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } -export function PromiseTimer(promise: Promise, ms: number): Promise { +export function PromiseTimer (promise: Promise, ms: number): Promise { const timeoutPromise = new Promise((_resolve, reject) => setTimeout(() => reject(new Error('PromiseTimer: Operation timed out')), ms) ); return Promise.race([promise, timeoutPromise]); } -export async function runAllWithTimeout(tasks: Promise[], timeout: number): Promise { +export async function runAllWithTimeout (tasks: Promise[], timeout: number): Promise { const wrappedTasks = tasks.map((task) => PromiseTimer(task, timeout).then( (result) => ({ status: 'fulfilled', value: result }), @@ -48,15 +48,15 @@ export async function runAllWithTimeout(tasks: Promise[], timeout: number) .map((result) => (result as { status: 'fulfilled'; value: T; }).value); } -export function isNull(value: any) { +export function isNull (value: any) { return value === undefined || value === null; } -export function isNumeric(str: string) { +export function isNumeric (str: string) { return /^\d+$/.test(str); } -export function truncateString(obj: any, maxLength = 500) { +export function truncateString (obj: any, maxLength = 500) { if (obj !== null && typeof obj === 'object') { Object.keys(obj).forEach((key) => { if (typeof obj[key] === 'string') { @@ -73,7 +73,7 @@ export function truncateString(obj: any, maxLength = 500) { return obj; } -export function isEqual(obj1: any, obj2: any) { +export function isEqual (obj1: any, obj2: any) { if (obj1 === obj2) return true; if (obj1 == null || obj2 == null) return false; if (typeof obj1 !== 'object' || typeof obj2 !== 'object') return obj1 === obj2; @@ -89,7 +89,7 @@ export function isEqual(obj1: any, obj2: any) { return true; } -export function getDefaultQQVersionConfigInfo(): QQVersionConfigType { +export function getDefaultQQVersionConfigInfo (): QQVersionConfigType { if (os.platform() === 'linux') { return { baseVersion: '3.2.12.28060', @@ -117,7 +117,7 @@ export function getDefaultQQVersionConfigInfo(): QQVersionConfigType { }; } -export function getQQPackageInfoPath(exePath: string = '', version?: string): string { +export function getQQPackageInfoPath (exePath: string = '', version?: string): string { if (process.env['NAPCAT_QQ_PACKAGE_INFO_PATH']) { return process.env['NAPCAT_QQ_PACKAGE_INFO_PATH']; } @@ -136,7 +136,7 @@ export function getQQPackageInfoPath(exePath: string = '', version?: string): st return packagePath; } -export function getQQVersionConfigPath(exePath: string = ''): string | undefined { +export function getQQVersionConfigPath (exePath: string = ''): string | undefined { if (process.env['NAPCAT_QQ_VERSION_CONFIG_PATH']) { return process.env['NAPCAT_QQ_VERSION_CONFIG_PATH']; } @@ -165,7 +165,7 @@ export function getQQVersionConfigPath(exePath: string = ''): string | undefined return configVersionInfoPath; } -export function calcQQLevel(level?: QQLevel) { +export function calcQQLevel (level?: QQLevel) { if (!level) return 0; // const { penguinNum, crownNum, sunNum, moonNum, starNum } = level; const { crownNum, sunNum, moonNum, starNum } = level; @@ -173,13 +173,13 @@ export function calcQQLevel(level?: QQLevel) { return crownNum * 64 + sunNum * 16 + moonNum * 4 + starNum; } -export function stringifyWithBigInt(obj: any) { +export function stringifyWithBigInt (obj: any) { return JSON.stringify(obj, (_key, value) => typeof value === 'bigint' ? value.toString() : value ); } -export function parseAppidFromMajor(nodeMajor: string): string | undefined { +export function parseAppidFromMajor (nodeMajor: string): string | undefined { const hexSequence = 'A4 09 00 00 00 35'; const sequenceBytes = Buffer.from(hexSequence.replace(/ /g, ''), 'hex'); const filePath = path.resolve(nodeMajor); diff --git a/packages/napcat-common/src/store.ts b/packages/napcat-common/src/store.ts index 9d804f28..9b5e3baa 100644 --- a/packages/napcat-common/src/store.ts +++ b/packages/napcat-common/src/store.ts @@ -19,4 +19,4 @@ class Store { const store = new Store(); -export default store; \ No newline at end of file +export default store; diff --git a/packages/napcat-common/src/types.ts b/packages/napcat-common/src/types.ts index d2442788..17652a7d 100644 --- a/packages/napcat-common/src/types.ts +++ b/packages/napcat-common/src/types.ts @@ -25,4 +25,4 @@ export interface QQLevel { sunNum: number; moonNum: number; starNum: number; -} \ No newline at end of file +} diff --git a/packages/napcat-common/src/version.ts b/packages/napcat-common/src/version.ts index b1afab9c..e798ba8a 100644 --- a/packages/napcat-common/src/version.ts +++ b/packages/napcat-common/src/version.ts @@ -1,3 +1,2 @@ // @ts-ignore export const napCatVersion = (typeof import.meta?.env !== 'undefined' && import.meta.env.VITE_NAPCAT_VERSION) || 'alpha'; - diff --git a/packages/napcat-core/adapters/NodeIDependsAdapter.ts b/packages/napcat-core/adapters/NodeIDependsAdapter.ts index b65b6d54..1f37c2a4 100644 --- a/packages/napcat-core/adapters/NodeIDependsAdapter.ts +++ b/packages/napcat-core/adapters/NodeIDependsAdapter.ts @@ -24,4 +24,4 @@ export class NodeIDependsAdapter { // console.log('[NodeIDependsAdapter] onSendMsfReply', _seq, _cmd, _uk1, _uk2, Buffer.from(_rsp.pbBuffer).toString('hex')); // } -} \ No newline at end of file +} diff --git a/packages/napcat-core/apis/file.ts b/packages/napcat-core/apis/file.ts index 4817e55a..e45ebf70 100644 --- a/packages/napcat-core/apis/file.ts +++ b/packages/napcat-core/apis/file.ts @@ -33,7 +33,7 @@ export class NTQQFileApi { 'http://ss.xingzhige.com/music_card/rkey', 'https://secret-service.bietiaop.com/rkeys', ], - this.context.logger + this.context.logger ); } @@ -169,7 +169,6 @@ export class NTQQFileApi { }; } - async downloadFileForModelId (peer: Peer, modelId: string, unknown: string, timeout = 1000 * 60 * 2) { const [, fileTransNotifyInfo] = await this.core.eventWrapper.callNormalEventV2( 'NodeIKernelRichMediaService/downloadFileForModelId', diff --git a/packages/napcat-core/helper/event.ts b/packages/napcat-core/helper/event.ts index 1579dfce..7da4b1ee 100644 --- a/packages/napcat-core/helper/event.ts +++ b/packages/napcat-core/helper/event.ts @@ -25,18 +25,18 @@ export class NTEventWrapper { private readonly listenerManager: Map = new Map(); // ListenerName-Unique -> Listener实例 private readonly EventTask = new Map>>(); // tasks ListenerMainName -> ListenerSubName-> uuid -> {timeout,createtime,func} - constructor( + constructor ( wrapperSession: NodeIQQNTWrapperSession ) { this.WrapperSession = wrapperSession; } - createProxyDispatch(ListenerMainName: string) { + createProxyDispatch (ListenerMainName: string) { const dispatcherListenerFunc = this.dispatcherListener.bind(this); return new Proxy( {}, { - get(target: any, prop: any, receiver: any) { + get (target: any, prop: any, receiver: any) { if (typeof target[prop] === 'undefined') { // 如果方法不存在,返回一个函数,这个函数调用existentMethod return (...args: any[]) => { @@ -94,7 +94,7 @@ export class NTEventWrapper { } // 统一回调清理事件 - async dispatcherListener(ListenerMainName: string, ListenerSubName: string, ...args: any[]) { + async dispatcherListener (ListenerMainName: string, ListenerSubName: string, ...args: any[]) { this.EventTask.get(ListenerMainName) ?.get(ListenerSubName) ?.forEach((task, uuid) => { @@ -137,7 +137,7 @@ export class NTEventWrapper { let complete = 0; let retData: Parameters | undefined; - function sendDataCallback() { + function sendDataCallback () { if (complete === 0) { reject(new Error(' ListenerName:' + listenerAndMethod + ' timeout')); } else { @@ -191,7 +191,7 @@ export class NTEventWrapper { let retData: Parameters | undefined; let retEvent: any = {}; - function sendDataCallback(resolve: any, reject: any) { + function sendDataCallback (resolve: any, reject: any) { if (complete === 0) { reject( new Error( diff --git a/packages/napcat-core/helper/ffmpeg/ffmpeg-addon-adapter.ts b/packages/napcat-core/helper/ffmpeg/ffmpeg-addon-adapter.ts index c2154e16..3f131511 100644 --- a/packages/napcat-core/helper/ffmpeg/ffmpeg-addon-adapter.ts +++ b/packages/napcat-core/helper/ffmpeg/ffmpeg-addon-adapter.ts @@ -68,13 +68,13 @@ export class FFmpegAddonAdapter implements IFFmpegAdapter { const addon = this.ensureAddon(); const info = await addon.getVideoInfo(videoPath); - let format = info.format.includes(',') ? info.format.split(',')[0] ?? info.format : info.format; + const format = info.format.includes(',') ? info.format.split(',')[0] ?? info.format : info.format; console.log('[FFmpegAddonAdapter] Detected format:', format); return { width: info.width, height: info.height, duration: info.duration, - format: format, + format, thumbnail: info.image, }; } diff --git a/packages/napcat-core/helper/ffmpeg/ffmpeg.ts b/packages/napcat-core/helper/ffmpeg/ffmpeg.ts index ee56a99b..f8cbee44 100644 --- a/packages/napcat-core/helper/ffmpeg/ffmpeg.ts +++ b/packages/napcat-core/helper/ffmpeg/ffmpeg.ts @@ -53,7 +53,6 @@ export class FFmpegService { throw new Error('FFmpeg service not initialized. Please call FFmpegService.init() first.'); } return this.adapter.name; - } /** diff --git a/packages/napcat-core/index.ts b/packages/napcat-core/index.ts index e67c9b2c..57a47c2c 100644 --- a/packages/napcat-core/index.ts +++ b/packages/napcat-core/index.ts @@ -45,7 +45,7 @@ export enum NapCatCoreWorkingEnv { Framework = 2, } -export function loadQQWrapper(QQVersion: string): WrapperNodeApi { +export function loadQQWrapper (QQVersion: string): WrapperNodeApi { if (process.env['NAPCAT_WRAPPER_PATH']) { const wrapperPath = process.env['NAPCAT_WRAPPER_PATH']; const nativemodule: { exports: WrapperNodeApi; } = { exports: {} as WrapperNodeApi }; @@ -72,7 +72,7 @@ export function loadQQWrapper(QQVersion: string): WrapperNodeApi { process.dlopen(nativemodule, wrapperNodePath); return nativemodule.exports; } -export function getMajorPath(QQVersion: string): string { +export function getMajorPath (QQVersion: string): string { // major.node let appPath; if (os.platform() === 'darwin') { @@ -105,7 +105,7 @@ export class NapCatCore { configLoader: NapCatConfigLoader; // 通过构造器递过去的 runtime info 应该尽量少 - constructor(context: InstanceContext, selfInfo: SelfInfo) { + constructor (context: InstanceContext, selfInfo: SelfInfo) { this.selfInfo = selfInfo; this.context = context; this.util = this.context.wrapper.NodeQQNTWrapperUtil; @@ -134,7 +134,7 @@ export class NapCatCore { }); } - async initCore() { + async initCore () { this.NapCatDataPath = path.join(this.dataPath, 'NapCat'); fs.mkdirSync(this.NapCatDataPath, { recursive: true }); this.NapCatTempPath = path.join(this.NapCatDataPath, 'temp'); @@ -163,7 +163,7 @@ export class NapCatCore { ); } - get dataPath(): string { + get dataPath (): string { let result = this.context.wrapper.NodeQQNTWrapperUtil.getNTUserDataInfoConfig(); if (!result) { result = path.resolve(os.homedir(), './.config/QQ'); @@ -173,7 +173,7 @@ export class NapCatCore { } // Renamed from 'InitDataListener' - async initNapCatCoreListeners() { + async initNapCatCoreListeners () { const msgListener = new NodeIKernelMsgListener(); msgListener.onKickedOffLine = (Info: KickedOffLineInfo) => { @@ -211,7 +211,7 @@ export class NapCatCore { } } -export async function genSessionConfig( +export async function genSessionConfig ( guid: string, QQVersionAppid: string, QQVersion: string, diff --git a/packages/napcat-core/packet/context/loggerContext.ts b/packages/napcat-core/packet/context/loggerContext.ts index 737aa619..a867f80c 100644 --- a/packages/napcat-core/packet/context/loggerContext.ts +++ b/packages/napcat-core/packet/context/loggerContext.ts @@ -1,4 +1,3 @@ - import { NapCoreContext } from '@/napcat-core/packet/context/napCoreContext'; import { LogWrapper, LogLevel } from '@/napcat-core/helper/log'; diff --git a/packages/napcat-core/packet/handler/client.ts b/packages/napcat-core/packet/handler/client.ts index 8f907bc0..48854b7b 100644 --- a/packages/napcat-core/packet/handler/client.ts +++ b/packages/napcat-core/packet/handler/client.ts @@ -50,7 +50,6 @@ export class NativePacketHandler { this.logger.logError('NativePacketClient 加载出错:', error); this.loaded = false; } - } /** diff --git a/packages/napcat-core/packet/handler/eventList.ts b/packages/napcat-core/packet/handler/eventList.ts index 265d7c66..e0e09312 100644 --- a/packages/napcat-core/packet/handler/eventList.ts +++ b/packages/napcat-core/packet/handler/eventList.ts @@ -1,6 +1,6 @@ -import { TypedEventEmitter } from "./typeEvent"; +import { TypedEventEmitter } from './typeEvent'; export interface AppEvents { - 'event:emoji_like': { groupId: string; senderUin: string; emojiId: string, msgSeq: string, isAdd: boolean,count:number }; + 'event:emoji_like': { groupId: string; senderUin: string; emojiId: string, msgSeq: string, isAdd: boolean, count: number }; } -export const appEvent = new TypedEventEmitter(); \ No newline at end of file +export const appEvent = new TypedEventEmitter(); diff --git a/packages/napcat-core/packet/handler/serviceRegister.ts b/packages/napcat-core/packet/handler/serviceRegister.ts index 196ff85e..f03a830f 100644 --- a/packages/napcat-core/packet/handler/serviceRegister.ts +++ b/packages/napcat-core/packet/handler/serviceRegister.ts @@ -1,28 +1,28 @@ -import "reflect-metadata"; -import { Container, injectable } from "inversify"; -import { NapCatCore } from "../.."; -import { TypedEventEmitter } from "./typeEvent"; +import 'reflect-metadata'; +import { Container, injectable } from 'inversify'; +import { NapCatCore } from '../..'; +import { TypedEventEmitter } from './typeEvent'; export const container = new Container(); export const ReceiverServiceRegistry = new Map ServiceBase>(); export abstract class ServiceBase { - get core(): NapCatCore { - return container.get(NapCatCore); - } - get event() { - return container.get(TypedEventEmitter); - } + get core (): NapCatCore { + return container.get(NapCatCore); + } - abstract handler(seq: number, hex_data: string): Promise | void; + get event () { + return container.get(TypedEventEmitter); + } + + abstract handler (seq: number, hex_data: string): Promise | void; } -export function ReceiveService(serviceName: string) { - return function ServiceBase>(constructor: T) { - injectable()(constructor); - ReceiverServiceRegistry.set(serviceName, constructor); - return constructor; - }; +export function ReceiveService (serviceName: string) { + return function ServiceBase>(constructor: T) { + injectable()(constructor); + ReceiverServiceRegistry.set(serviceName, constructor); + return constructor; + }; } - diff --git a/packages/napcat-core/protocol/OlpushSerivce.ts b/packages/napcat-core/protocol/OlpushSerivce.ts index 7fa518e4..6bb54413 100644 --- a/packages/napcat-core/protocol/OlpushSerivce.ts +++ b/packages/napcat-core/protocol/OlpushSerivce.ts @@ -1,37 +1,36 @@ -import { NapProtoMsg } from "napcat-protobuf"; -import { ReceiveService, ServiceBase } from "../packet/handler/serviceRegister"; -import { GroupReactNotify, PushMsg } from "../packet/transformer/proto"; +import { NapProtoMsg } from 'napcat-protobuf'; +import { ReceiveService, ServiceBase } from '../packet/handler/serviceRegister'; +import { GroupReactNotify, PushMsg } from '../packet/transformer/proto'; @ReceiveService('trpc.msg.olpush.OlPushService.MsgPush') export class OlPushService extends ServiceBase { - async handler(_seq: number, hex_data: string) { - const data = new NapProtoMsg(PushMsg).decode(Buffer.from(hex_data, 'hex')); - if (data.message.contentHead.type === 732 && data.message.contentHead.subType === 16) { - const pbNotify = data.message.body?.msgContent?.slice(7); - if (!pbNotify) { - return; - } - // 开始解析Notify - const notify = new NapProtoMsg(GroupReactNotify).decode(pbNotify); - if ((notify.field13 ?? 0) === 35) { - // Group React Notify - const groupCode = notify.groupUin?.toString() ?? ''; - const operatorUid = notify.groupReactionData?.data?.data?.groupReactionDataContent?.operatorUid ?? ''; - const type = notify.groupReactionData?.data?.data?.groupReactionDataContent?.type ?? 0; - const seq = notify.groupReactionData?.data?.data?.groupReactionTarget?.seq?.toString() ?? ''; - const code = notify.groupReactionData?.data?.data?.groupReactionDataContent?.code ?? ''; - const count = notify.groupReactionData?.data?.data?.groupReactionDataContent?.count ?? 0; - const senderUin = await this.core.apis.UserApi.getUinByUidV2(operatorUid); - this.event.emit('event:emoji_like', { - groupId: groupCode, - senderUin: senderUin, - emojiId: code, - msgSeq: seq, - isAdd: type === 1, - count: count - }); - } - } - + async handler (_seq: number, hex_data: string) { + const data = new NapProtoMsg(PushMsg).decode(Buffer.from(hex_data, 'hex')); + if (data.message.contentHead.type === 732 && data.message.contentHead.subType === 16) { + const pbNotify = data.message.body?.msgContent?.slice(7); + if (!pbNotify) { + return; + } + // 开始解析Notify + const notify = new NapProtoMsg(GroupReactNotify).decode(pbNotify); + if ((notify.field13 ?? 0) === 35) { + // Group React Notify + const groupCode = notify.groupUin?.toString() ?? ''; + const operatorUid = notify.groupReactionData?.data?.data?.groupReactionDataContent?.operatorUid ?? ''; + const type = notify.groupReactionData?.data?.data?.groupReactionDataContent?.type ?? 0; + const seq = notify.groupReactionData?.data?.data?.groupReactionTarget?.seq?.toString() ?? ''; + const code = notify.groupReactionData?.data?.data?.groupReactionDataContent?.code ?? ''; + const count = notify.groupReactionData?.data?.data?.groupReactionDataContent?.count ?? 0; + const senderUin = await this.core.apis.UserApi.getUinByUidV2(operatorUid); + this.event.emit('event:emoji_like', { + groupId: groupCode, + senderUin, + emojiId: code, + msgSeq: seq, + isAdd: type === 1, + count, + }); + } } -} \ No newline at end of file + } +} diff --git a/packages/napcat-core/services/NodeIKernelBuddyService.ts b/packages/napcat-core/services/NodeIKernelBuddyService.ts index 32c4fdd7..880f9232 100644 --- a/packages/napcat-core/services/NodeIKernelBuddyService.ts +++ b/packages/napcat-core/services/NodeIKernelBuddyService.ts @@ -24,7 +24,6 @@ export interface NodeIKernelBuddyService { }>; }>; - getBuddyListFromCache (reqType: BuddyListReqType): Promise | Array> }> = object > = { - [P in K]: - S[P] extends Array + [P in K]: + S[P] extends Array ? Pick, U & keyof NonNullable> : S[P] extends keyof NonNullable - ? Pick, S[P]> - : NonNullable; - }; + ? Pick, S[P]> + : NonNullable; +}; export interface TextElement { content: string; diff --git a/packages/napcat-develop/index.js b/packages/napcat-develop/index.js index 2c5488b1..98c9defe 100644 --- a/packages/napcat-develop/index.js +++ b/packages/napcat-develop/index.js @@ -10,5 +10,5 @@ const NAPCAT_MJS_PATH = path.join(BASE_DIR, 'napcat', 'napcat.mjs'); process.env.NAPCAT_WRAPPER_PATH = WRAPPER_NODE_PATH; process.env.NAPCAT_QQ_PACKAGE_INFO_PATH = PACKAGE_JSON_PATH; process.env.NAPCAT_QQ_VERSION_CONFIG_PATH = CONFIG_JSON_PATH; - process.env.NAPCAT_DISABLE_PIPE = '1'; -import(pathToFileURL(NAPCAT_MJS_PATH).href); \ No newline at end of file +process.env.NAPCAT_DISABLE_PIPE = '1'; +import(pathToFileURL(NAPCAT_MJS_PATH).href); diff --git a/packages/napcat-develop/loadNapCat.cjs b/packages/napcat-develop/loadNapCat.cjs index 88c60d02..aa58889a 100644 --- a/packages/napcat-develop/loadNapCat.cjs +++ b/packages/napcat-develop/loadNapCat.cjs @@ -33,7 +33,7 @@ const BASE_DIR = path.join(versionsDir, selectedFolder, 'resources', 'app'); console.log(`BASE_DIR: ${BASE_DIR}`); const TARGET_DIR = path.join(__dirname, 'dist'); const QQNT_FILE = path.join(__dirname, 'QQNT.dll'); -const NAPCAT_MJS_PATH = path.join(__dirname, '..', 'napcat-shell','dist', 'napcat.mjs'); +const NAPCAT_MJS_PATH = path.join(__dirname, '..', 'napcat-shell', 'dist', 'napcat.mjs'); const itemsToCopy = [ 'avif_convert.dll', @@ -45,15 +45,15 @@ const itemsToCopy = [ 'opencv.dll', 'package.json', 'QBar.dll', - 'wrapper.node' + 'wrapper.node', ]; async function copyAll () { const qqntDllPath = path.join(TARGET_DIR, 'QQNT.dll'); const configPath = path.join(TARGET_DIR, 'config.json'); - const allItemsExist = await fs.pathExists(qqntDllPath) - && await fs.pathExists(configPath) - && (await Promise.all(itemsToCopy.map(item => fs.pathExists(path.join(TARGET_DIR, item))))).every(exists => exists); + const allItemsExist = await fs.pathExists(qqntDllPath) && + await fs.pathExists(configPath) && + (await Promise.all(itemsToCopy.map(item => fs.pathExists(path.join(TARGET_DIR, item))))).every(exists => exists); if (!allItemsExist) { console.log('Copying required files...'); @@ -79,4 +79,4 @@ async function copyAll () { await import(pathToFileURL(NAPCAT_MJS_PATH).href); } -copyAll().catch(console.error); \ No newline at end of file +copyAll().catch(console.error); diff --git a/packages/napcat-framework/vite.config.ts b/packages/napcat-framework/vite.config.ts index 6ada540d..9e4121a1 100644 --- a/packages/napcat-framework/vite.config.ts +++ b/packages/napcat-framework/vite.config.ts @@ -2,23 +2,23 @@ import cp from 'vite-plugin-cp'; import { defineConfig, PluginOption, UserConfig } from 'vite'; import path, { resolve } from 'path'; import nodeResolve from '@rollup/plugin-node-resolve'; -import { autoIncludeTSPlugin } from "napcat-vite/vite-auto-include.js"; +import { autoIncludeTSPlugin } from 'napcat-vite/vite-auto-include.js'; import { builtinModules } from 'module'; import react from '@vitejs/plugin-react-swc'; -import napcatVersion from "napcat-vite/vite-plugin-version.js"; -//依赖排除 +import napcatVersion from 'napcat-vite/vite-plugin-version.js'; +// 依赖排除 const external = [ 'silk-wasm', 'ws', - 'express' + 'express', ]; const nodeModules = [...builtinModules, builtinModules.map((m) => `node:${m}`)].flat(); const FrameworkBaseConfigPlugin: PluginOption[] = [ autoIncludeTSPlugin({ entries: [ { entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-core/protocol') }, - { entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-onebot/action/test') } - ] + { entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-onebot/action/test') }, + ], }), react({ tsDecorators: true }), cp({ diff --git a/packages/napcat-onebot/action/auto-register.ts b/packages/napcat-onebot/action/auto-register.ts index 90a3fa61..705ca023 100644 --- a/packages/napcat-onebot/action/auto-register.ts +++ b/packages/napcat-onebot/action/auto-register.ts @@ -1,6 +1,6 @@ import { OneBotAction } from './OneBotAction'; export const AutoRegisterRouter: Array OneBotAction> = []; -export function ActionHandler(target: new (...args: any[]) => OneBotAction) { - AutoRegisterRouter.push(target); +export function ActionHandler (target: new (...args: any[]) => OneBotAction) { + AutoRegisterRouter.push(target); } diff --git a/packages/napcat-onebot/action/index.ts b/packages/napcat-onebot/action/index.ts index 1c80890b..562b44e8 100644 --- a/packages/napcat-onebot/action/index.ts +++ b/packages/napcat-onebot/action/index.ts @@ -138,7 +138,7 @@ import { TestDownloadStream } from './stream/TestStreamDownload'; import { UploadFileStream } from './stream/UploadFileStream'; import { AutoRegisterRouter } from './auto-register'; -export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCore) { +export function createActionMap (obContext: NapCatOneBot11Adapter, core: NapCatCore) { const actionHandlers = [ new CleanStreamTempFile(obContext, core), new DownloadFileStream(obContext, core), @@ -315,7 +315,7 @@ export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCo // function get(key: K): MapType[K]; // function get(key: K): null; // function get(key: K): HandlerUnion | null | MapType[K] - function get(key: K): MapType[K] | undefined { + function get (key: K): MapType[K] | undefined { return _map.get(key as keyof MapType) as MapType[K] | undefined; } return { get }; diff --git a/packages/napcat-onebot/api/file.ts b/packages/napcat-onebot/api/file.ts index 0f9b2949..a7b2d094 100644 --- a/packages/napcat-onebot/api/file.ts +++ b/packages/napcat-onebot/api/file.ts @@ -1,5 +1,3 @@ - - import { NapCatOneBot11Adapter } from '@/napcat-onebot/index'; import { encodeSilk } from '@/napcat-core/helper/audio'; import { FFmpegService } from '@/napcat-core/helper/ffmpeg/ffmpeg'; @@ -14,169 +12,169 @@ import fsPromises from 'fs/promises'; import fs from 'fs'; import { defaultVideoThumbB64 } from '@/napcat-core/helper/ffmpeg/video'; export class OneBotFileApi { - obContext: NapCatOneBot11Adapter; - core: NapCatCore; - constructor(obContext: NapCatOneBot11Adapter, core: NapCatCore) { - this.obContext = obContext; - this.core = core; + obContext: NapCatOneBot11Adapter; + core: NapCatCore; + constructor (obContext: NapCatOneBot11Adapter, core: NapCatCore) { + this.obContext = obContext; + this.core = core; + } + + async createValidSendFileElement (context: SendMessageContext, filePath: string, fileName: string = '', folderId: string = ''): Promise { + const { + fileName: _fileName, + path, + fileSize, + } = await this.core.apis.FileApi.uploadFile(filePath, ElementType.FILE); + if (fileSize === 0) { + throw new Error('文件异常,大小为0'); } - async createValidSendFileElement(context: SendMessageContext, filePath: string, fileName: string = '', folderId: string = ''): Promise { - const { - fileName: _fileName, - path, - fileSize, - } = await this.core.apis.FileApi.uploadFile(filePath, ElementType.FILE); - if (fileSize === 0) { - throw new Error('文件异常,大小为0'); - } - context.deleteAfterSentFiles.push(path); - return { - elementType: ElementType.FILE, - elementId: '', - fileElement: { - fileName: fileName || _fileName, - folderId, - filePath: path, - fileSize: fileSize.toString(), - }, - }; + context.deleteAfterSentFiles.push(path); + return { + elementType: ElementType.FILE, + elementId: '', + fileElement: { + fileName: fileName || _fileName, + folderId, + filePath: path, + fileSize: fileSize.toString(), + }, + }; + } + + async createValidSendPicElement (context: SendMessageContext, picPath: string, summary: string = '', subType: PicSubType = 0): Promise { + const { md5, fileName, path, fileSize } = await this.core.apis.FileApi.uploadFile(picPath, ElementType.PIC, subType); + if (fileSize === 0) { + throw new Error('文件异常,大小为0'); } + const imageSize = await imageSizeFallBack(picPath); + context.deleteAfterSentFiles.push(path); + return { + elementType: ElementType.PIC, + elementId: '', + picElement: { + md5HexStr: md5, + fileSize: fileSize.toString(), + picWidth: imageSize.width, + picHeight: imageSize.height, + fileName, + sourcePath: path, + original: true, + picType: await getFileTypeForSendType(picPath), + picSubType: subType, + fileUuid: '', + fileSubId: '', + thumbFileSize: 0, + summary, + } as PicElement, + }; + } - async createValidSendPicElement(context: SendMessageContext, picPath: string, summary: string = '', subType: PicSubType = 0): Promise { - const { md5, fileName, path, fileSize } = await this.core.apis.FileApi.uploadFile(picPath, ElementType.PIC, subType); - if (fileSize === 0) { - throw new Error('文件异常,大小为0'); - } - const imageSize = await imageSizeFallBack(picPath); - context.deleteAfterSentFiles.push(path); - return { - elementType: ElementType.PIC, - elementId: '', - picElement: { - md5HexStr: md5, - fileSize: fileSize.toString(), - picWidth: imageSize.width, - picHeight: imageSize.height, - fileName, - sourcePath: path, - original: true, - picType: await getFileTypeForSendType(picPath), - picSubType: subType, - fileUuid: '', - fileSubId: '', - thumbFileSize: 0, - summary, - } as PicElement, - }; + async createValidSendVideoElement (context: SendMessageContext, filePath: string, fileName: string = '', _diyThumbPath: string = ''): Promise { + let videoInfo = { + width: 1920, + height: 1080, + time: 15, + format: 'mp4', + size: 0, + filePath, + }; + let fileExt = 'mp4'; + try { + const tempExt = (await fileTypeFromFile(filePath))?.ext; + if (tempExt) fileExt = tempExt; + } catch (e) { + this.core.context.logger.logError('获取文件类型失败', e); } + const newFilePath = `${filePath}.${fileExt}`; + fs.copyFileSync(filePath, newFilePath); + context.deleteAfterSentFiles.push(newFilePath); + filePath = newFilePath; - async createValidSendVideoElement(context: SendMessageContext, filePath: string, fileName: string = '', _diyThumbPath: string = ''): Promise { - let videoInfo = { - width: 1920, - height: 1080, - time: 15, - format: 'mp4', - size: 0, - filePath, - }; - let fileExt = 'mp4'; - try { - const tempExt = (await fileTypeFromFile(filePath))?.ext; - if (tempExt) fileExt = tempExt; - } catch (e) { - this.core.context.logger.logError('获取文件类型失败', e); - } - const newFilePath = `${filePath}.${fileExt}`; - fs.copyFileSync(filePath, newFilePath); - context.deleteAfterSentFiles.push(newFilePath); - filePath = newFilePath; - - const { fileName: _fileName, path, fileSize, md5 } = await this.core.apis.FileApi.uploadFile(filePath, ElementType.VIDEO); - context.deleteAfterSentFiles.push(path); - if (fileSize === 0) { - throw new Error('文件异常,大小为0'); - } - const thumbDir = path.replace(`${pathLib.sep}Ori${pathLib.sep}`, `${pathLib.sep}Thumb${pathLib.sep}`); - fs.mkdirSync(pathLib.dirname(thumbDir), { recursive: true }); - const thumbPath = pathLib.join(pathLib.dirname(thumbDir), `${md5}_0.png`); - try { - videoInfo = await FFmpegService.getVideoInfo(filePath, thumbPath); - if (!fs.existsSync(thumbPath)) { - this.core.context.logger.logError('获取视频缩略图失败', new Error('缩略图不存在')); - throw new Error('获取视频缩略图失败'); - } - } catch (e) { - this.core.context.logger.logError('获取视频信息失败', e); - fs.writeFileSync(thumbPath, Buffer.from(defaultVideoThumbB64, 'base64')); - } - if (_diyThumbPath) { - try { - await this.core.apis.FileApi.copyFile(_diyThumbPath, thumbPath); - } catch (e) { - this.core.context.logger.logError('复制自定义缩略图失败', e); - } - } - context.deleteAfterSentFiles.push(thumbPath); - const thumbSize = (await fsPromises.stat(thumbPath)).size; - const thumbMd5 = await calculateFileMD5(thumbPath); - context.deleteAfterSentFiles.push(thumbPath); - - const uploadName = (fileName || _fileName).toLocaleLowerCase().endsWith(`.${fileExt.toLocaleLowerCase()}`) ? (fileName || _fileName) : `${fileName || _fileName}.${fileExt}`; - return { - elementType: ElementType.VIDEO, - elementId: '', - videoElement: { - fileName: uploadName, - filePath: path, - videoMd5: md5, - thumbMd5, - fileTime: videoInfo.time, - thumbPath: new Map([[0, thumbPath]]), - thumbSize, - thumbWidth: videoInfo.width, - thumbHeight: videoInfo.height, - fileSize: fileSize.toString(), - }, - }; + const { fileName: _fileName, path, fileSize, md5 } = await this.core.apis.FileApi.uploadFile(filePath, ElementType.VIDEO); + context.deleteAfterSentFiles.push(path); + if (fileSize === 0) { + throw new Error('文件异常,大小为0'); } - - async createValidSendPttElement(_context: SendMessageContext, pttPath: string): Promise { - const { converted, path: silkPath, duration } = await encodeSilk(pttPath, this.core.NapCatTempPath, this.core.context.logger); - if (!silkPath) { - throw new Error('语音转换失败, 请检查语音文件是否正常'); - } - const { md5, fileName, path, fileSize } = await this.core.apis.FileApi.uploadFile(silkPath, ElementType.PTT); - if (fileSize === 0) { - throw new Error('文件异常,大小为0'); - } - if (converted) { - fsPromises.unlink(silkPath).then().catch((e) => this.core.context.logger.logError('删除临时文件失败', e)); - } - return { - elementType: ElementType.PTT, - elementId: '', - pttElement: { - fileName, - filePath: path, - md5HexStr: md5, - fileSize: fileSize.toString(), - duration: duration ?? 1, - formatType: 1, - voiceType: 1, - voiceChangeType: 0, - canConvert2Text: true, - waveAmplitudes: [ - 0, 18, 9, 23, 16, 17, 16, 15, 44, 17, 24, 20, 14, 15, 17, - ], - fileSubId: '', - playState: 1, - autoConvertText: 0, - storeID: 0, - otherBusinessInfo: { - aiVoiceType: 0, - }, - }, - }; + const thumbDir = path.replace(`${pathLib.sep}Ori${pathLib.sep}`, `${pathLib.sep}Thumb${pathLib.sep}`); + fs.mkdirSync(pathLib.dirname(thumbDir), { recursive: true }); + const thumbPath = pathLib.join(pathLib.dirname(thumbDir), `${md5}_0.png`); + try { + videoInfo = await FFmpegService.getVideoInfo(filePath, thumbPath); + if (!fs.existsSync(thumbPath)) { + this.core.context.logger.logError('获取视频缩略图失败', new Error('缩略图不存在')); + throw new Error('获取视频缩略图失败'); + } + } catch (e) { + this.core.context.logger.logError('获取视频信息失败', e); + fs.writeFileSync(thumbPath, Buffer.from(defaultVideoThumbB64, 'base64')); } + if (_diyThumbPath) { + try { + await this.core.apis.FileApi.copyFile(_diyThumbPath, thumbPath); + } catch (e) { + this.core.context.logger.logError('复制自定义缩略图失败', e); + } + } + context.deleteAfterSentFiles.push(thumbPath); + const thumbSize = (await fsPromises.stat(thumbPath)).size; + const thumbMd5 = await calculateFileMD5(thumbPath); + context.deleteAfterSentFiles.push(thumbPath); + const uploadName = (fileName || _fileName).toLocaleLowerCase().endsWith(`.${fileExt.toLocaleLowerCase()}`) ? (fileName || _fileName) : `${fileName || _fileName}.${fileExt}`; + return { + elementType: ElementType.VIDEO, + elementId: '', + videoElement: { + fileName: uploadName, + filePath: path, + videoMd5: md5, + thumbMd5, + fileTime: videoInfo.time, + thumbPath: new Map([[0, thumbPath]]), + thumbSize, + thumbWidth: videoInfo.width, + thumbHeight: videoInfo.height, + fileSize: fileSize.toString(), + }, + }; + } + + async createValidSendPttElement (_context: SendMessageContext, pttPath: string): Promise { + const { converted, path: silkPath, duration } = await encodeSilk(pttPath, this.core.NapCatTempPath, this.core.context.logger); + if (!silkPath) { + throw new Error('语音转换失败, 请检查语音文件是否正常'); + } + const { md5, fileName, path, fileSize } = await this.core.apis.FileApi.uploadFile(silkPath, ElementType.PTT); + if (fileSize === 0) { + throw new Error('文件异常,大小为0'); + } + if (converted) { + fsPromises.unlink(silkPath).then().catch((e) => this.core.context.logger.logError('删除临时文件失败', e)); + } + return { + elementType: ElementType.PTT, + elementId: '', + pttElement: { + fileName, + filePath: path, + md5HexStr: md5, + fileSize: fileSize.toString(), + duration: duration ?? 1, + formatType: 1, + voiceType: 1, + voiceChangeType: 0, + canConvert2Text: true, + waveAmplitudes: [ + 0, 18, 9, 23, 16, 17, 16, 15, 44, 17, 24, 20, 14, 15, 17, + ], + fileSubId: '', + playState: 1, + autoConvertText: 0, + storeID: 0, + otherBusinessInfo: { + aiVoiceType: 0, + }, + }, + }; + } } diff --git a/packages/napcat-onebot/api/group.ts b/packages/napcat-onebot/api/group.ts index d18e2f14..c5164c06 100644 --- a/packages/napcat-onebot/api/group.ts +++ b/packages/napcat-onebot/api/group.ts @@ -30,12 +30,12 @@ import { NapCatOneBot11Adapter } from '..'; export class OneBotGroupApi { obContext: NapCatOneBot11Adapter; core: NapCatCore; - constructor(obContext: NapCatOneBot11Adapter, core: NapCatCore) { + constructor (obContext: NapCatOneBot11Adapter, core: NapCatCore) { this.obContext = obContext; this.core = core; } - async parseGroupBanEvent(GroupCode: string, grayTipElement: GrayTipElement) { + async parseGroupBanEvent (GroupCode: string, grayTipElement: GrayTipElement) { const groupElement = grayTipElement?.groupElement; if (!groupElement?.shutUp) return undefined; const memberUid = groupElement.shutUp.member.uid; @@ -66,7 +66,7 @@ export class OneBotGroupApi { return undefined; } - async parseGroupEmojiLikeEventByGrayTip( + async parseGroupEmojiLikeEventByGrayTip ( groupCode: string, grayTipElement: GrayTipElement ) { @@ -85,7 +85,7 @@ export class OneBotGroupApi { return await this.createGroupEmojiLikeEvent(groupCode, senderUin, msgSeq, emojiId, true, 1); } - async createGroupEmojiLikeEvent( + async createGroupEmojiLikeEvent ( groupCode: string, senderUin: string, msgSeq: string, @@ -121,7 +121,7 @@ export class OneBotGroupApi { ); } - async parseCardChangedEvent(msg: RawMessage) { + async parseCardChangedEvent (msg: RawMessage) { if (msg.senderUin && msg.senderUin !== '0') { const member = await this.core.apis.GroupApi.getGroupMember(msg.peerUid, msg.senderUin); if (member && member.cardName !== msg.sendMemberName) { @@ -137,7 +137,7 @@ export class OneBotGroupApi { return undefined; } - async registerParseGroupReactEvent() { + async registerParseGroupReactEvent () { this.obContext.core.context.packetHandler.onCmd('trpc.msg.olpush.OlPushService.MsgPush', async (packet) => { const data = new NapProtoMsg(PushMsg).decode(Buffer.from(packet.hex_data, 'hex')); if (data.message.contentHead.type === 732 && data.message.contentHead.subType === 16) { @@ -172,7 +172,7 @@ export class OneBotGroupApi { }); } - async registerParseGroupReactEventByCore() { + async registerParseGroupReactEventByCore () { this.core.event.on('event:emoji_like', async (data) => { console.log('Received emoji_like event from core:', data); const event = await this.createGroupEmojiLikeEvent( @@ -188,7 +188,8 @@ export class OneBotGroupApi { } }); } - async parsePaiYiPai(msg: RawMessage, jsonStr: string) { + + async parsePaiYiPai (msg: RawMessage, jsonStr: string) { const json = JSON.parse(jsonStr); // 判断业务类型 // Poke事件 @@ -207,7 +208,7 @@ export class OneBotGroupApi { return undefined; } - async parseOtherJsonEvent(msg: RawMessage, jsonStr: string, context: InstanceContext) { + async parseOtherJsonEvent (msg: RawMessage, jsonStr: string, context: InstanceContext) { const json = JSON.parse(jsonStr); const type = json.items[json.items.length - 1]?.txt; await this.core.apis.GroupApi.refreshGroupMemberCachePartial(msg.peerUid, msg.senderUid); @@ -229,7 +230,7 @@ export class OneBotGroupApi { return undefined; } - async parseEssenceMsg(msg: RawMessage, jsonStr: string) { + async parseEssenceMsg (msg: RawMessage, jsonStr: string) { const json = JSON.parse(jsonStr); const searchParams = new URL(json.items[0].jp).searchParams; const msgSeq = searchParams.get('msgSeq')!; @@ -257,7 +258,7 @@ export class OneBotGroupApi { // 获取MsgSeq+Peer可获取具体消息 } - async parseGroupUploadFileEvene(msg: RawMessage, element: FileElement, elementWrapper: MessageElement) { + async parseGroupUploadFileEvene (msg: RawMessage, element: FileElement, elementWrapper: MessageElement) { return new OB11GroupUploadNoticeEvent( this.core, parseInt(msg.peerUid), parseInt(msg.senderUin || ''), @@ -273,7 +274,7 @@ export class OneBotGroupApi { ); } - async parseGroupElement(msg: RawMessage, element: TipGroupElement, elementWrapper: GrayTipElement) { + async parseGroupElement (msg: RawMessage, element: TipGroupElement, elementWrapper: GrayTipElement) { if (element.type === TipGroupElementType.KGROUPNAMEMODIFIED) { this.core.context.logger.logDebug('收到群名称变更事件', element); return new OB11GroupNameEvent( @@ -301,7 +302,7 @@ export class OneBotGroupApi { return undefined; } - async parseSelfInviteEvent(msg: RawMessage, inviterUin: string, inviteeUin: string) { + async parseSelfInviteEvent (msg: RawMessage, inviterUin: string, inviteeUin: string) { return new OB11GroupIncreaseEvent( this.core, parseInt(msg.peerUid), @@ -311,7 +312,7 @@ export class OneBotGroupApi { ); } - async parse51TypeEvent(msg: RawMessage, grayTipElement: GrayTipElement) { + async parse51TypeEvent (msg: RawMessage, grayTipElement: GrayTipElement) { // 神经腾讯 没了妈妈想出来的 // Warn 下面存在高并发危险 if (grayTipElement.jsonGrayTipElement.jsonStr) { @@ -340,7 +341,7 @@ export class OneBotGroupApi { return undefined; } - async parseGrayTipElement(msg: RawMessage, grayTipElement: GrayTipElement) { + async parseGrayTipElement (msg: RawMessage, grayTipElement: GrayTipElement) { if (grayTipElement.subElementType === NTGrayTipElementSubTypeV2.GRAYTIP_ELEMENT_SUBTYPE_GROUP) { // 解析群组事件 由sysmsg解析 return await this.parseGroupElement(msg, grayTipElement.groupElement, grayTipElement); diff --git a/packages/napcat-onebot/index.ts b/packages/napcat-onebot/index.ts index 6952a6bf..4fd656d0 100644 --- a/packages/napcat-onebot/index.ts +++ b/packages/napcat-onebot/index.ts @@ -75,7 +75,7 @@ export class NapCatOneBot11Adapter { actions: ActionMap; private readonly bootTime = Date.now() / 1000; recallEventCache = new Map(); - constructor(core: NapCatCore, context: InstanceContext, pathWrapper: NapCatPathWrapper) { + constructor (core: NapCatCore, context: InstanceContext, pathWrapper: NapCatPathWrapper) { this.core = core; this.context = context; this.configLoader = new OB11ConfigLoader(core, pathWrapper.configPath, OneBotConfigSchema); @@ -91,7 +91,7 @@ export class NapCatOneBot11Adapter { this.networkManager = new OB11NetworkManager(); } - async creatOneBotLog(ob11Config: OneBotConfig) { + async creatOneBotLog (ob11Config: OneBotConfig) { let log = '[network] 配置加载\n'; for (const key of ob11Config.network.httpServers) { log += `HTTP服务: ${key.host}:${key.port}, : ${key.enable ? '已启动' : '未启动'}\n`; @@ -111,7 +111,7 @@ export class NapCatOneBot11Adapter { return log; } - async InitOneBot() { + async InitOneBot () { const selfInfo = this.core.selfInfo; const ob11Config = this.configLoader.configData; this.core.apis.UserApi.getUserDetailInfo(selfInfo.uid, false) @@ -233,7 +233,7 @@ export class NapCatOneBot11Adapter { ); } - private async reloadNetwork(prev: OneBotConfig, now: OneBotConfig): Promise { + private async reloadNetwork (prev: OneBotConfig, now: OneBotConfig): Promise { const prevLog = await this.creatOneBotLog(prev); const newLog = await this.creatOneBotLog(now); this.context.logger.log(`[Notice] [OneBot11] 配置变更前:\n${prevLog}`); @@ -279,7 +279,7 @@ export class NapCatOneBot11Adapter { } } - private initMsgListener() { + private initMsgListener () { const msgListener = new NodeIKernelMsgListener(); msgListener.onRecvSysMsg = (msg) => { this.apis.MsgApi.parseSysMessage(msg) @@ -392,7 +392,7 @@ export class NapCatOneBot11Adapter { this.context.session.getMsgService().addKernelMsgListener(proxiedListenerOf(msgListener, this.context.logger)); } - private initBuddyListener() { + private initBuddyListener () { const buddyListener = new NodeIKernelBuddyListener(); buddyListener.onBuddyReqChange = async (reqs) => { @@ -423,7 +423,7 @@ export class NapCatOneBot11Adapter { .addKernelBuddyListener(proxiedListenerOf(buddyListener, this.context.logger)); } - private initGroupListener() { + private initGroupListener () { const groupListener = new NodeIKernelGroupListener(); groupListener.onGroupNotifiesUpdated = async (_, notifies) => { @@ -516,7 +516,7 @@ export class NapCatOneBot11Adapter { .addKernelGroupListener(proxiedListenerOf(groupListener, this.context.logger)); } - private async emitMsg(message: RawMessage) { + private async emitMsg (message: RawMessage) { const network = await this.networkManager.getAllConfig(); this.context.logger.logDebug('收到新消息 RawMessage', message); await Promise.allSettled([ @@ -525,7 +525,7 @@ export class NapCatOneBot11Adapter { ]); } - private async handleMsg(message: RawMessage, network: Array) { + private async handleMsg (message: RawMessage, network: Array) { // 过滤无效消息 if (message.msgType === NTMsgType.KMSGTYPENULL) { return; @@ -545,7 +545,7 @@ export class NapCatOneBot11Adapter { } } - private isSelfMessage(ob11Msg: { + private isSelfMessage (ob11Msg: { stringMsg: OB11Message; arrayMsg: OB11Message; }): boolean { @@ -553,7 +553,7 @@ export class NapCatOneBot11Adapter { ob11Msg.arrayMsg.user_id.toString() === this.core.selfInfo.uin; } - private createMsgMap(network: Array, ob11Msg: { + private createMsgMap (network: Array, ob11Msg: { stringMsg: OB11Message; arrayMsg: OB11Message; }, isSelfMsg: boolean, message: RawMessage): Map { @@ -572,7 +572,7 @@ export class NapCatOneBot11Adapter { return msgMap; } - private handleDebugNetwork(network: Array, msgMap: Map, message: RawMessage) { + private handleDebugNetwork (network: Array, msgMap: Map, message: RawMessage) { const debugNetwork = network.filter(e => e.enable && e.debug); if (debugNetwork.length > 0) { debugNetwork.forEach(adapter => { @@ -586,7 +586,7 @@ export class NapCatOneBot11Adapter { } } - private handleNotReportSelfNetwork(network: Array, msgMap: Map, isSelfMsg: boolean) { + private handleNotReportSelfNetwork (network: Array, msgMap: Map, isSelfMsg: boolean) { if (isSelfMsg) { const notReportSelfNetwork = network.filter(e => e.enable && (('reportSelfMessage' in e && !e.reportSelfMessage) || !('reportSelfMessage' in e))); notReportSelfNetwork.forEach(adapter => { @@ -595,7 +595,7 @@ export class NapCatOneBot11Adapter { } } - private async handleGroupEvent(message: RawMessage) { + private async handleGroupEvent (message: RawMessage) { try { // 群名片修改事件解析 任何都该判断 if (message.senderUin && message.senderUin !== '0') { @@ -628,7 +628,7 @@ export class NapCatOneBot11Adapter { } } - private async handlePrivateMsgEvent(message: RawMessage) { + private async handlePrivateMsgEvent (message: RawMessage) { try { if (message.msgType === NTMsgType.KMSGTYPEGRAYTIPS) { // 灰条为单元素消息 @@ -645,7 +645,7 @@ export class NapCatOneBot11Adapter { } } - private async emitRecallMsg(message: RawMessage, element: MessageElement) { + private async emitRecallMsg (message: RawMessage, element: MessageElement) { const peer: Peer = { chatType: message.chatType, peerUid: message.peerUid, guildId: '' }; const oriMessageId = MessageUnique.getShortIdByMsgId(message.msgId) ?? MessageUnique.createUniqueMsgId(peer, message.msgId); if (message.chatType === ChatType.KCHATTYPEC2C) { @@ -656,7 +656,7 @@ export class NapCatOneBot11Adapter { return undefined; } - private async emitFriendRecallMsg(message: RawMessage, oriMessageId: number, element: MessageElement) { + private async emitFriendRecallMsg (message: RawMessage, oriMessageId: number, element: MessageElement) { const operatorUid = element.grayTipElement?.revokeElement.operatorUid; if (!operatorUid) return undefined; return new OB11FriendRecallNoticeEvent( @@ -666,7 +666,7 @@ export class NapCatOneBot11Adapter { ); } - private async emitGroupRecallMsg(message: RawMessage, oriMessageId: number, element: MessageElement) { + private async emitGroupRecallMsg (message: RawMessage, oriMessageId: number, element: MessageElement) { const operatorUid = element.grayTipElement?.revokeElement.operatorUid; if (!operatorUid) return undefined; const operatorId = await this.core.apis.UserApi.getUinByUidV2(operatorUid); diff --git a/packages/napcat-protobuf/NapProto.ts b/packages/napcat-protobuf/NapProto.ts index ecf842ad..d9b5c288 100644 --- a/packages/napcat-protobuf/NapProto.ts +++ b/packages/napcat-protobuf/NapProto.ts @@ -7,18 +7,18 @@ type LowerCamelCase = CamelCaseHelper; type CamelCaseHelper< S extends string, CapNext extends boolean, - IsFirstChar extends boolean, + IsFirstChar extends boolean > = S extends `${infer F}${infer R}` - ? F extends '_' - ? CamelCaseHelper - : F extends `${number}` - ? `${F}${CamelCaseHelper}` - : CapNext extends true - ? `${Uppercase}${CamelCaseHelper}` - : IsFirstChar extends true - ? `${Lowercase}${CamelCaseHelper}` - : `${F}${CamelCaseHelper}` - : ''; + ? F extends '_' + ? CamelCaseHelper + : F extends `${number}` + ? `${F}${CamelCaseHelper}` + : CapNext extends true + ? `${Uppercase}${CamelCaseHelper}` + : IsFirstChar extends true + ? `${Lowercase}${CamelCaseHelper}` + : `${F}${CamelCaseHelper}` + : ''; type ScalarTypeToTsType = T extends | ScalarType.DOUBLE @@ -28,36 +28,36 @@ type ScalarTypeToTsType = T extends | ScalarType.UINT32 | ScalarType.SFIXED32 | ScalarType.SINT32 - ? number - : T extends ScalarType.INT64 | ScalarType.UINT64 | ScalarType.FIXED64 | ScalarType.SFIXED64 | ScalarType.SINT64 - ? bigint - : T extends ScalarType.BOOL - ? boolean - : T extends ScalarType.STRING - ? string - : T extends ScalarType.BYTES - ? Uint8Array - : never; + ? number + : T extends ScalarType.INT64 | ScalarType.UINT64 | ScalarType.FIXED64 | ScalarType.SFIXED64 | ScalarType.SINT64 + ? bigint + : T extends ScalarType.BOOL + ? boolean + : T extends ScalarType.STRING + ? string + : T extends ScalarType.BYTES + ? Uint8Array + : never; interface BaseProtoFieldType { - kind: 'scalar' | 'message'; - no: number; - type: T; - optional: O; - repeat: R; + kind: 'scalar' | 'message'; + no: number; + type: T; + optional: O; + repeat: R; } export interface ScalarProtoFieldType - extends BaseProtoFieldType { - kind: 'scalar'; + extends BaseProtoFieldType { + kind: 'scalar'; } export interface MessageProtoFieldType< T extends () => ProtoMessageType, O extends boolean, - R extends O extends true ? false : boolean, + R extends O extends true ? false : boolean > extends BaseProtoFieldType { - kind: 'message'; + kind: 'message'; } type ProtoFieldType = @@ -65,62 +65,62 @@ type ProtoFieldType = | MessageProtoFieldType<() => ProtoMessageType, boolean, boolean>; type ProtoMessageType = { - [key: string]: ProtoFieldType; + [key: string]: ProtoFieldType; }; export function ProtoField< T extends ScalarType, O extends boolean = false, - R extends O extends true ? false : boolean = false, ->(no: number, type: T, optional?: O, repeat?: R): ScalarProtoFieldType; + R extends O extends true ? false : boolean = false +> (no: number, type: T, optional?: O, repeat?: R): ScalarProtoFieldType; export function ProtoField< T extends () => ProtoMessageType, O extends boolean = false, - R extends O extends true ? false : boolean = false, ->(no: number, type: T, optional?: O, repeat?: R): MessageProtoFieldType; -export function ProtoField( - no: number, - type: ScalarType | (() => ProtoMessageType), - optional?: boolean, - repeat?: boolean + R extends O extends true ? false : boolean = false +> (no: number, type: T, optional?: O, repeat?: R): MessageProtoFieldType; +export function ProtoField ( + no: number, + type: ScalarType | (() => ProtoMessageType), + optional?: boolean, + repeat?: boolean ): ProtoFieldType { - if (typeof type === 'function') { - return { kind: 'message', no: no, type: type, optional: optional ?? false, repeat: repeat ?? false }; - } else { - return { kind: 'scalar', no: no, type: type, optional: optional ?? false, repeat: repeat ?? false }; - } + if (typeof type === 'function') { + return { kind: 'message', no, type, optional: optional ?? false, repeat: repeat ?? false }; + } else { + return { kind: 'scalar', no, type, optional: optional ?? false, repeat: repeat ?? false }; + } } type ProtoFieldReturnType = - NonNullable extends ScalarProtoFieldType - ? ScalarTypeToTsType - : T extends NonNullable> - ? NonNullable, E>> - : never; + NonNullable extends ScalarProtoFieldType + ? ScalarTypeToTsType + : T extends NonNullable> + ? NonNullable, E>> + : never; type RequiredFieldsBaseType = { - [K in keyof T as T[K] extends { optional: true } ? never : LowerCamelCase]: T[K] extends { - repeat: true; - } - ? ProtoFieldReturnType[] - : ProtoFieldReturnType; + [K in keyof T as T[K] extends { optional: true } ? never : LowerCamelCase]: T[K] extends { + repeat: true; + } + ? ProtoFieldReturnType[] + : ProtoFieldReturnType; }; type OptionalFieldsBaseType = { - [K in keyof T as T[K] extends { optional: true } ? LowerCamelCase : never]?: T[K] extends { - repeat: true; - } - ? ProtoFieldReturnType[] - : ProtoFieldReturnType; + [K in keyof T as T[K] extends { optional: true } ? LowerCamelCase : never]?: T[K] extends { + repeat: true; + } + ? ProtoFieldReturnType[] + : ProtoFieldReturnType; }; type RequiredFieldsType = E extends true - ? Partial> - : RequiredFieldsBaseType; + ? Partial> + : RequiredFieldsBaseType; type OptionalFieldsType = E extends true - ? Partial> - : OptionalFieldsBaseType; + ? Partial> + : OptionalFieldsBaseType; type NapProtoStructType = RequiredFieldsType & OptionalFieldsType; @@ -129,72 +129,74 @@ export type NapProtoEncodeStructType = NapProtoStructType; export type NapProtoDecodeStructType = NapProtoStructType; class NapProtoRealMsg { - private readonly _field: PartialFieldInfo[]; - private readonly _proto_msg: MessageType>; - private static cache = new WeakMap>(); + private readonly _field: PartialFieldInfo[]; + private readonly _proto_msg: MessageType>; + private static cache = new WeakMap>(); - private constructor(fields: T) { - this._field = Object.keys(fields).map((key) => { - const field = fields[key]; - if (field.kind === 'scalar') { - const repeatType = field.repeat - ? [ScalarType.STRING, ScalarType.BYTES].includes(field.type) - ? RepeatType.UNPACKED - : RepeatType.PACKED - : RepeatType.NO; - return { - no: field.no, - name: key, - kind: 'scalar', - T: field.type, - opt: field.optional, - repeat: repeatType, - }; - } else if (field.kind === 'message') { - return { - no: field.no, - name: key, - kind: 'message', - repeat: field.repeat ? RepeatType.PACKED : RepeatType.NO, - T: () => NapProtoRealMsg.getInstance(field.type())._proto_msg, - }; - } - }) as PartialFieldInfo[]; - this._proto_msg = new MessageType>('nya', this._field); - } + private constructor (fields: T) { + this._field = Object.keys(fields).map((key) => { + const field = fields[key]; + if (field.kind === 'scalar') { + const repeatType = field.repeat + ? [ScalarType.STRING, ScalarType.BYTES].includes(field.type) + ? RepeatType.UNPACKED + : RepeatType.PACKED + : RepeatType.NO; + return { + no: field.no, + name: key, + kind: 'scalar', + T: field.type, + opt: field.optional, + repeat: repeatType, + }; + } else if (field.kind === 'message') { + return { + no: field.no, + name: key, + kind: 'message', + repeat: field.repeat ? RepeatType.PACKED : RepeatType.NO, + T: () => NapProtoRealMsg.getInstance(field.type())._proto_msg, + }; + } else { + throw new Error(`Unknown field kind: ${field.kind}`); + } + }) as PartialFieldInfo[]; + this._proto_msg = new MessageType>('nya', this._field); + } - static getInstance(fields: T): NapProtoRealMsg { - let instance = this.cache.get(fields); - if (!instance) { - instance = new NapProtoRealMsg(fields); - this.cache.set(fields, instance); - } - return instance; + static getInstance(fields: T): NapProtoRealMsg { + let instance = this.cache.get(fields); + if (!instance) { + instance = new NapProtoRealMsg(fields); + this.cache.set(fields, instance); } + return instance; + } - encode(data: NapProtoEncodeStructType): Uint8Array { - return this._proto_msg.toBinary(this._proto_msg.create(data as PartialMessage>)); - } + encode (data: NapProtoEncodeStructType): Uint8Array { + return this._proto_msg.toBinary(this._proto_msg.create(data as PartialMessage>)); + } - decode(data: Uint8Array): NapProtoDecodeStructType { - return this._proto_msg.fromBinary(data) as NapProtoDecodeStructType; - } + decode (data: Uint8Array): NapProtoDecodeStructType { + return this._proto_msg.fromBinary(data) as NapProtoDecodeStructType; + } } export class NapProtoMsg { - private realMsg: NapProtoRealMsg; + private realMsg: NapProtoRealMsg; - constructor(fields: T) { - this.realMsg = NapProtoRealMsg.getInstance(fields); - } + constructor (fields: T) { + this.realMsg = NapProtoRealMsg.getInstance(fields); + } - encode(data: NapProtoEncodeStructType): Uint8Array { - return this.realMsg.encode(data); - } + encode (data: NapProtoEncodeStructType): Uint8Array { + return this.realMsg.encode(data); + } - decode(data: Uint8Array): NapProtoDecodeStructType { - return this.realMsg.decode(data); - } + decode (data: Uint8Array): NapProtoDecodeStructType { + return this.realMsg.decode(data); + } } export { ScalarType } from '@protobuf-ts/runtime'; diff --git a/packages/napcat-shell-loader/loadNapCat.js b/packages/napcat-shell-loader/loadNapCat.js index 81af5e6e..25e1ed19 100644 --- a/packages/napcat-shell-loader/loadNapCat.js +++ b/packages/napcat-shell-loader/loadNapCat.js @@ -1,5 +1,5 @@ const path = require('path'); const CurrentPath = path.dirname(__filename); (async () => { - await import("file://" + path.join(CurrentPath, './napcat/napcat.mjs')); -})(); \ No newline at end of file + await import('file://' + path.join(CurrentPath, './napcat/napcat.mjs')); +})(); diff --git a/packages/napcat-shell/base.ts b/packages/napcat-shell/base.ts index 69f8046e..cba8eb64 100644 --- a/packages/napcat-shell/base.ts +++ b/packages/napcat-shell/base.ts @@ -364,7 +364,7 @@ export async function NCoreInitShell () { await initializeLoginService(loginService, basicInfoWrapper, dataPathGlobal, systemVersion, hostname); handleProxy(session, logger); - let quickLoginUin: string | undefined = undefined; + let quickLoginUin: string | undefined; try { const args = process.argv; const qIndex = args.findIndex(arg => arg === '-q' || arg === '--qq'); diff --git a/packages/napcat-shell/vite.config.ts b/packages/napcat-shell/vite.config.ts index 790ff370..5b4f74c1 100644 --- a/packages/napcat-shell/vite.config.ts +++ b/packages/napcat-shell/vite.config.ts @@ -3,15 +3,15 @@ import { defineConfig, PluginOption, UserConfig } from 'vite'; import path, { resolve } from 'path'; import nodeResolve from '@rollup/plugin-node-resolve'; import { builtinModules } from 'module'; -import napcatVersion from "napcat-vite/vite-plugin-version.js"; -import { autoIncludeTSPlugin } from "napcat-vite/vite-auto-include.js"; +import napcatVersion from 'napcat-vite/vite-plugin-version.js'; +import { autoIncludeTSPlugin } from 'napcat-vite/vite-auto-include.js'; import react from '@vitejs/plugin-react-swc'; -//依赖排除 +// 依赖排除 const external = [ 'silk-wasm', 'ws', - 'express' + 'express', ]; const nodeModules = [...builtinModules, builtinModules.map((m) => `node:${m}`)].flat(); @@ -20,8 +20,8 @@ const ShellBaseConfigPlugin: PluginOption[] = [ autoIncludeTSPlugin({ entries: [ { entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-core/protocol') }, - { entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-onebot/action/test') } - ] + { entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-onebot/action/test') }, + ], }), cp({ targets: [ @@ -29,7 +29,7 @@ const ShellBaseConfigPlugin: PluginOption[] = [ { src: '../napcat-webui-frontend/dist/', dest: 'dist/static/', flatten: false }, { src: '../napcat-core/external/napcat.json', dest: 'dist/config/' }, { src: '../../package.json', dest: 'dist' }, - { src: '../napcat-shell-loader', dest: 'dist' } + { src: '../napcat-shell-loader', dest: 'dist' }, ], }), nodeResolve(), @@ -62,7 +62,7 @@ const ShellBaseConfig = (source_map: boolean = false) => fileName: (_, entryName) => `${entryName}.mjs`, }, rollupOptions: { - external: [...nodeModules, ...external] + external: [...nodeModules, ...external], }, }, }); diff --git a/packages/napcat-test/sha1Stream.test.ts b/packages/napcat-test/sha1Stream.test.ts index bf9600eb..94940aa5 100644 --- a/packages/napcat-test/sha1Stream.test.ts +++ b/packages/napcat-test/sha1Stream.test.ts @@ -84,4 +84,4 @@ describe('Sha1Stream', () => { expect(hash).toEqual(expectedDigest); } }); -}); \ No newline at end of file +}); diff --git a/packages/napcat-test/vitest.config.ts b/packages/napcat-test/vitest.config.ts index 04c89db4..2ec5edf6 100644 --- a/packages/napcat-test/vitest.config.ts +++ b/packages/napcat-test/vitest.config.ts @@ -11,4 +11,4 @@ export default defineConfig({ '@': resolve(__dirname, '../../'), }, }, -}); \ No newline at end of file +}); diff --git a/packages/napcat-vite/vite-auto-include.js b/packages/napcat-vite/vite-auto-include.js index 20c91129..ba8fa9ff 100644 --- a/packages/napcat-vite/vite-auto-include.js +++ b/packages/napcat-vite/vite-auto-include.js @@ -1,78 +1,78 @@ import path from 'path'; import fs from 'fs'; -export function autoIncludeTSPlugin(options) { - // options: { entries: [{ entry: 'napcat.ts', dir: './utils' }, ...] } - const { entries } = options; - let tsFilesMap = {}; +export function autoIncludeTSPlugin (options) { + // options: { entries: [{ entry: 'napcat.ts', dir: './utils' }, ...] } + const { entries } = options; + let tsFilesMap = {}; - return { - name: 'vite-auto-include', + return { + name: 'vite-auto-include', - async buildStart() { - tsFilesMap = {}; - for (const { entry, dir } of entries) { - if (!tsFilesMap[entry]) { - tsFilesMap[entry] = []; - } - const fullDir = path.resolve(dir); - const allTsFiles = await findTSFiles(fullDir); + async buildStart () { + tsFilesMap = {}; + for (const { entry, dir } of entries) { + if (!tsFilesMap[entry]) { + tsFilesMap[entry] = []; + } + const fullDir = path.resolve(dir); + const allTsFiles = await findTSFiles(fullDir); - const validFiles = []; - allTsFiles.forEach((filePath) => { - try { - const source = fs.readFileSync(filePath, 'utf-8'); - if (source && source.trim() !== '') { - validFiles.push(filePath); - } else { - // Skipping empty file: ${filePath} - } - } catch (error) { - console.error(`Error reading file: ${filePath}`, error); - } - }); - - tsFilesMap[entry].push(...validFiles); + const validFiles = []; + allTsFiles.forEach((filePath) => { + try { + const source = fs.readFileSync(filePath, 'utf-8'); + if (source && source.trim() !== '') { + validFiles.push(filePath); + } else { + // Skipping empty file: ${filePath} } - }, + } catch (error) { + console.error(`Error reading file: ${filePath}`, error); + } + }); - transform(code, id) { - for (const [entry, tsFiles] of Object.entries(tsFilesMap)) { - const isMatch = id.endsWith(entry) || id.includes(entry); - if (isMatch && tsFiles.length > 0) { - const imports = tsFiles.map(filePath => { - const relativePath = path.relative(path.dirname(id), filePath).replace(/\\/g, '/'); - return `import './${relativePath}';`; - }).join('\n'); + tsFilesMap[entry].push(...validFiles); + } + }, - const transformedCode = imports + '\n' + code; + transform (code, id) { + for (const [entry, tsFiles] of Object.entries(tsFilesMap)) { + const isMatch = id.endsWith(entry) || id.includes(entry); + if (isMatch && tsFiles.length > 0) { + const imports = tsFiles.map(filePath => { + const relativePath = path.relative(path.dirname(id), filePath).replace(/\\/g, '/'); + return `import './${relativePath}';`; + }).join('\n'); - return { - code: transformedCode, - map: { mappings: '' } // 空映射即可,VSCode 可以在 TS 上断点 - }; - } - } + const transformedCode = imports + '\n' + code; - return null; - }, + return { + code: transformedCode, + map: { mappings: '' }, // 空映射即可,VSCode 可以在 TS 上断点 + }; + } + } - }; + return null; + }, + + }; } // 辅助函数:查找所有 .ts 文件 -async function findTSFiles(dir) { - const files = []; - const items = await fs.promises.readdir(dir, { withFileTypes: true }); +async function findTSFiles (dir) { + const files = []; + const items = await fs.promises.readdir(dir, { withFileTypes: true }); - for (let item of items) { - const fullPath = path.join(dir, item.name); - if (item.isDirectory()) { - files.push(...await findTSFiles(fullPath)); // 递归查找子目录 - } else if (item.isFile() && fullPath.endsWith('.ts')) { - files.push(fullPath); // 收集 .ts 文件 - } + for (const item of items) { + const fullPath = path.join(dir, item.name); + if (item.isDirectory()) { + files.push(...await findTSFiles(fullPath)); // 递归查找子目录 + } else if (item.isFile() && fullPath.endsWith('.ts')) { + files.push(fullPath); // 收集 .ts 文件 } + } - return files; + return files; } diff --git a/packages/napcat-vite/vite-plugin-version.js b/packages/napcat-vite/vite-plugin-version.js index 9bcea274..3b508c53 100644 --- a/packages/napcat-vite/vite-plugin-version.js +++ b/packages/napcat-vite/vite-plugin-version.js @@ -1,7 +1,7 @@ -import fs from "fs"; -import path from "path"; -import https from "https"; -import { fileURLToPath } from "url"; +import fs from 'fs'; +import path from 'path'; +import https from 'https'; +import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -9,28 +9,28 @@ const __dirname = path.dirname(__filename); /** * NapCat Vite Plugin: fetches latest GitHub tag (not release) and injects into import.meta.env */ -export default function vitePluginNapcatVersion() { - const pluginDir = path.resolve(__dirname, "dist"); - const cacheFile = path.join(pluginDir, ".napcat-version.json"); - const owner = "NapNeko"; - const repo = "NapCatQQ"; +export default function vitePluginNapcatVersion () { + const pluginDir = path.resolve(__dirname, 'dist'); + const cacheFile = path.join(pluginDir, '.napcat-version.json'); + const owner = 'NapNeko'; + const repo = 'NapCatQQ'; const maxAgeMs = 24 * 60 * 60 * 1000; // cache 1 day const githubToken = process.env.GITHUB_TOKEN; fs.mkdirSync(pluginDir, { recursive: true }); - function readCache() { + function readCache () { try { const stat = fs.statSync(cacheFile); if (Date.now() - stat.mtimeMs < maxAgeMs) { - const data = JSON.parse(fs.readFileSync(cacheFile, "utf8")); + const data = JSON.parse(fs.readFileSync(cacheFile, 'utf8')); if (data?.tag) return data.tag; } } catch {} return null; } - function writeCache(tag) { + function writeCache (tag) { try { fs.writeFileSync( cacheFile, @@ -39,38 +39,38 @@ export default function vitePluginNapcatVersion() { } catch {} } - async function fetchLatestTag() { + async function fetchLatestTag () { const url = `https://api.github.com/repos/${owner}/${repo}/tags`; return new Promise((resolve, reject) => { const req = https.get( url, { headers: { - "User-Agent": "vite-plugin-napcat-version", - Accept: "application/vnd.github.v3+json", + 'User-Agent': 'vite-plugin-napcat-version', + Accept: 'application/vnd.github.v3+json', ...(githubToken ? { Authorization: `token ${githubToken}` } : {}), }, }, (res) => { - let data = ""; - res.on("data", (c) => (data += c)); - res.on("end", () => { + let data = ''; + res.on('data', (c) => (data += c)); + res.on('end', () => { try { const json = JSON.parse(data); if (Array.isArray(json) && json[0]?.name) { resolve(json[0].name); - } else reject(new Error("Invalid GitHub tag response")); + } else reject(new Error('Invalid GitHub tag response')); } catch (e) { reject(e); } }); } ); - req.on("error", reject); + req.on('error', reject); }); } - async function getVersion() { + async function getVersion () { const cached = readCache(); if (cached) return cached; try { @@ -78,37 +78,37 @@ export default function vitePluginNapcatVersion() { writeCache(tag); return tag; } catch (e) { - console.warn("[vite-plugin-napcat-version] Failed to fetch tag:", e.message); - return cached ?? "v0.0.0"; + console.warn('[vite-plugin-napcat-version] Failed to fetch tag:', e.message); + return cached ?? 'v0.0.0'; } } let lastTag = null; return { - name: "vite-plugin-napcat-version", - enforce: "pre", + name: 'vite-plugin-napcat-version', + enforce: 'pre', - async config(userConfig) { + async config (userConfig) { const tag = await getVersion(); console.log(`[vite-plugin-napcat-version] Using version: ${tag}`); lastTag = tag; return { define: { ...(userConfig.define || {}), - "import.meta.env.VITE_NAPCAT_VERSION": JSON.stringify(tag), + 'import.meta.env.VITE_NAPCAT_VERSION': JSON.stringify(tag), }, }; }, - handleHotUpdate(ctx) { + handleHotUpdate (ctx) { if (path.resolve(ctx.file) === cacheFile) { try { - const json = JSON.parse(fs.readFileSync(cacheFile, "utf8")); + const json = JSON.parse(fs.readFileSync(cacheFile, 'utf8')); const tag = json?.tag; if (tag && tag !== lastTag) { lastTag = tag; - ctx.server?.ws.send({ type: "full-reload" }); + ctx.server?.ws.send({ type: 'full-reload' }); } } catch {} } diff --git a/packages/napcat-webui-backend/src/helper/config.ts b/packages/napcat-webui-backend/src/helper/config.ts index ef0b0d1d..527a1671 100644 --- a/packages/napcat-webui-backend/src/helper/config.ts +++ b/packages/napcat-webui-backend/src/helper/config.ts @@ -1,4 +1,4 @@ -import { webUiPathWrapper, getInitialWebUiToken } from '@/napcat-webui-backend/index' +import { webUiPathWrapper, getInitialWebUiToken } from '@/napcat-webui-backend/index'; import { Type, Static } from '@sinclair/typebox'; import Ajv from 'ajv'; import fs, { constants } from 'node:fs/promises'; diff --git a/packages/napcat-webui-frontend/eslint.config.mjs b/packages/napcat-webui-frontend/eslint.config.mjs deleted file mode 100644 index ecbdd00f..00000000 --- a/packages/napcat-webui-frontend/eslint.config.mjs +++ /dev/null @@ -1,2 +0,0 @@ -import eslintConfig from '../eslint.config.mjs'; -export default eslintConfig; diff --git a/packages/napcat-webui-frontend/postcss.config.js b/packages/napcat-webui-frontend/postcss.config.js index 2b75bd8a..2aa7205d 100644 --- a/packages/napcat-webui-frontend/postcss.config.js +++ b/packages/napcat-webui-frontend/postcss.config.js @@ -1,6 +1,6 @@ export default { plugins: { tailwindcss: {}, - autoprefixer: {} - } -} + autoprefixer: {}, + }, +}; diff --git a/packages/napcat-webui-frontend/src/types/react-color.d.ts b/packages/napcat-webui-frontend/src/types/react-color.d.ts index a7c2e3c5..23056396 100644 --- a/packages/napcat-webui-frontend/src/types/react-color.d.ts +++ b/packages/napcat-webui-frontend/src/types/react-color.d.ts @@ -23,6 +23,6 @@ declare module 'react-color' { export const CirclePicker: any; export default { - SketchPicker: SketchPicker, + SketchPicker, } as any; } diff --git a/packages/napcat-webui-frontend/tailwind.config.js b/packages/napcat-webui-frontend/tailwind.config.js index 379ed05b..e48e7d97 100644 --- a/packages/napcat-webui-frontend/tailwind.config.js +++ b/packages/napcat-webui-frontend/tailwind.config.js @@ -1,4 +1,4 @@ -import { heroui } from '@heroui/theme' +import { heroui } from '@heroui/theme'; /** @type {import('tailwindcss').Config} */ export default { @@ -7,16 +7,16 @@ export default { './src/layouts/**/*.{js,ts,jsx,tsx,mdx}', './src/pages/**/*.{js,ts,jsx,tsx,mdx}', './src/components/**/*.{js,ts,jsx,tsx,mdx}', - './node_modules/@heroui/theme/dist/**/*.{js,ts,jsx,tsx}' + './node_modules/@heroui/theme/dist/**/*.{js,ts,jsx,tsx}', ], safelist: [ { pattern: - /bg-(primary|secondary|success|danger|warning|default)-(50|100|200|300|400|500|600|700|800|900)/ - } + /bg-(primary|secondary|success|danger|warning|default)-(50|100|200|300|400|500|600|700|800|900)/, + }, ], theme: { - extend: {} + extend: {}, }, darkMode: 'class', plugins: [ @@ -36,7 +36,7 @@ export default { 600: '#c20e4d', 700: '#920b3a', 800: '#610726', - 900: '#310413' + 900: '#310413', }, danger: { DEFAULT: '#DB3694', @@ -50,9 +50,9 @@ export default { 600: '#BC278B', 700: '#9D1B7F', 800: '#7F1170', - 900: '#690A66' - } - } + 900: '#690A66', + }, + }, }, dark: { colors: { @@ -68,7 +68,7 @@ export default { 600: '#f871a0', 700: '#faa0bf', 800: '#fdd0df', - 900: '#fee7ef' + 900: '#fee7ef', }, danger: { DEFAULT: '#DB3694', @@ -82,11 +82,11 @@ export default { 600: '#F485AE', 700: '#FBAFC4', 800: '#FDD7DD', - 900: '#FEEAF6' - } - } - } - } - }) - ] -} + 900: '#FEEAF6', + }, + }, + }, + }, + }), + ], +}; diff --git a/packages/napcat-webui-frontend/vite.config.ts b/packages/napcat-webui-frontend/vite.config.ts index d9cf306c..f7087409 100644 --- a/packages/napcat-webui-frontend/vite.config.ts +++ b/packages/napcat-webui-frontend/vite.config.ts @@ -1,18 +1,18 @@ -import react from '@vitejs/plugin-react' -import path from 'node:path' -import { defineConfig, loadEnv, normalizePath } from 'vite' -import { viteStaticCopy } from 'vite-plugin-static-copy' -import tsconfigPaths from 'vite-tsconfig-paths' +import react from '@vitejs/plugin-react'; +import path from 'node:path'; +import { defineConfig, loadEnv, normalizePath } from 'vite'; +import { viteStaticCopy } from 'vite-plugin-static-copy'; +import tsconfigPaths from 'vite-tsconfig-paths'; const monacoEditorPath = normalizePath( path.resolve(__dirname, 'node_modules/monaco-editor/min/vs') -) +); // https://vitejs.dev/config/ export default defineConfig(({ mode }) => { - const env = loadEnv(mode, process.cwd()) - const backendDebugUrl = env.VITE_DEBUG_BACKEND_URL - console.log('backendDebugUrl', backendDebugUrl) + const env = loadEnv(mode, process.cwd()); + const backendDebugUrl = env.VITE_DEBUG_BACKEND_URL; + console.log('backendDebugUrl', backendDebugUrl); return { plugins: [ react(), @@ -21,10 +21,10 @@ export default defineConfig(({ mode }) => { targets: [ { src: monacoEditorPath, - dest: 'monaco-editor/min' - } - ] - }) + dest: 'monaco-editor/min', + }, + ], + }), ], base: '/webui/', server: { @@ -32,11 +32,11 @@ export default defineConfig(({ mode }) => { '/api/ws/terminal': { target: backendDebugUrl, ws: true, - changeOrigin: true + changeOrigin: true, }, '/api': backendDebugUrl, - '/files': backendDebugUrl - } + '/files': backendDebugUrl, + }, }, build: { assetsInlineLimit: 0, @@ -49,10 +49,10 @@ export default defineConfig(({ mode }) => { 'react-hook-form': ['react-hook-form'], 'react-icons': ['react-icons'], 'react-hot-toast': ['react-hot-toast'], - qface: ['qface'] - } - } - } - } - } -}) + qface: ['qface'], + }, + }, + }, + }, + }; +}); diff --git a/vitest.config.ts b/vitest.config.ts index d771157a..cd3d1592 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -12,4 +12,4 @@ export default defineConfig({ '@': resolve(__dirname, 'packages'), }, }, -}); \ No newline at end of file +});