diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml index 241fc19d..ab68845c 100644 --- a/.github/workflows/auto-release.yml +++ b/.github/workflows/auto-release.yml @@ -5,6 +5,63 @@ on: types: [published] jobs: + publish-schema: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + + - name: Get Version + id: get_version + run: | + latest_tag=$(git describe --tags $(git rev-list --tags --max-count=1)) + version=${latest_tag#v} + echo "version=${version}" >> $GITHUB_ENV + echo "latest_tag=${latest_tag}" >> $GITHUB_ENV + echo "Debug: Version is ${version}" + + - name: Install Dependencies + run: pnpm install --frozen-lockfile + + - name: Build napcat-schema + run: | + cd packages/napcat-schema + pnpm run build:openapi + + - name: Checkout NapCatDocs + uses: actions/checkout@v4 + with: + repository: NapNeko/NapCatDocs + token: ${{ secrets.NAPCAT_BUILD }} + path: napcat-docs + + - name: Copy OpenAPI Schema + run: | + mkdir -p napcat-docs/src/api/${{ env.version }} + cp packages/napcat-schema/openapi.json napcat-docs/src/api/${{ env.version }}/openapi.json + echo "OpenAPI schema copied to napcat-docs/src/api/${{ env.version }}/openapi.json" + + - name: Commit and Push + run: | + cd napcat-docs + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add src/api/${{ env.version }}/openapi.json + git commit -m "chore: update OpenAPI schema for version ${{ env.version }}" || echo "No changes to commit" + git push + shell-docker: runs-on: ubuntu-latest steps: diff --git a/package/package.json b/package/package.json new file mode 100644 index 00000000..3780b4c8 --- /dev/null +++ b/package/package.json @@ -0,0 +1,24 @@ +{ + "name": "napcat-types", + "version": "0.0.1", + "type": "module", + "types": "./napcat-types/index.d.ts", + "files": [ + "**/*" + ], + "dependencies": { + "@types/node": "^22.10.7", + "@types/express": "^4.17.21", + "@types/ws": "^8.5.12", + "@types/cors": "^2.8.17", + "@types/multer": "^1.4.12", + "@types/winston": "^2.4.4", + "@types/yaml": "^1.9.7", + "@types/ip": "^1.1.3" + }, + "publishConfig": { + "registry": "https://registry.npmjs.org/", + "access": "public", + "tag": "latest" + } +} \ No newline at end of file diff --git a/packages/napcat-core/apis/online.ts b/packages/napcat-core/apis/online.ts index 967ff737..4a89c61b 100644 --- a/packages/napcat-core/apis/online.ts +++ b/packages/napcat-core/apis/online.ts @@ -114,8 +114,9 @@ export class NTQQOnlineApi { fileElement: { fileName: actualFolderName, filePath: folderPath, + fileSize: "", }, - } as any; + }; const msgService = this.context.session.getMsgService(); const startTime = Math.floor(Date.now() / 1000) - 2; @@ -173,7 +174,7 @@ export class NTQQOnlineApi { * 获取好友的在线文件消息 * @param peer */ - async getOnlineFileMsg (peer: Peer) : Promise { + async getOnlineFileMsg (peer: Peer): Promise { const msgService = this.context.session.getMsgService(); return await msgService.getOnlineFileMsgs(peer); } @@ -183,7 +184,7 @@ export class NTQQOnlineApi { * @param peer * @param msgId */ - async cancelMyOnlineFileMsg (peer: Peer, msgId: string) : Promise { + async cancelMyOnlineFileMsg (peer: Peer, msgId: string): Promise { const msgService = this.context.session.getMsgService(); await msgService.cancelSendMsg(peer, msgId); } @@ -194,7 +195,7 @@ export class NTQQOnlineApi { * @param msgId * @param elementId */ - async refuseOnlineFileMsg (peer: Peer, msgId: string, elementId: string) : Promise { + async refuseOnlineFileMsg (peer: Peer, msgId: string, elementId: string): Promise { const msgService = this.context.session.getMsgService(); const arrToSend = { msgId, @@ -215,7 +216,7 @@ export class NTQQOnlineApi { * @param elementId * @constructor */ - async receiveOnlineFileOrFolder (peer: Peer, msgId: string, elementId: string) : Promise { + async receiveOnlineFileOrFolder (peer: Peer, msgId: string, elementId: string): Promise { const msgService = this.context.session.getMsgService(); const arrToSend = { msgId, @@ -233,7 +234,7 @@ export class NTQQOnlineApi { * @param peer * @param msgId */ - async switchFileToOffline (peer: Peer, msgId: string) : Promise { + async switchFileToOffline (peer: Peer, msgId: string): Promise { const msgService = this.context.session.getMsgService(); await msgService.switchToOfflineSendMsg(peer, msgId); } diff --git a/packages/napcat-core/index.ts b/packages/napcat-core/index.ts index cc7ff526..83fb4bb1 100644 --- a/packages/napcat-core/index.ts +++ b/packages/napcat-core/index.ts @@ -39,6 +39,12 @@ export * from './wrapper'; export * from './types/index'; export * from './services/index'; export * from './listeners/index'; +export * from './apis/index'; +export * from './helper/log'; +export * from './helper/qq-basic-info'; +export * from './helper/event'; +export * from './helper/config'; +export * from './helper/proxy-handler'; export enum NapCatCoreWorkingEnv { Unknown = 0, diff --git a/packages/napcat-core/types/index.ts b/packages/napcat-core/types/index.ts index d4adf5e0..a43181c0 100644 --- a/packages/napcat-core/types/index.ts +++ b/packages/napcat-core/types/index.ts @@ -11,3 +11,7 @@ export * from './constant'; export * from './graytip'; export * from './emoji'; export * from './service'; +export * from './adapter'; +export * from './contact'; +export * from './file'; +export * from './flashfile'; diff --git a/packages/napcat-core/types/msg.ts b/packages/napcat-core/types/msg.ts index a84121ee..aa5592a4 100644 --- a/packages/napcat-core/types/msg.ts +++ b/packages/napcat-core/types/msg.ts @@ -1,4 +1,4 @@ -import { NTGroupMemberRole } from '@/napcat-core/index'; +import { NTGroupMemberRole } from './group'; import { ActionBarElement, ArkElement, AvRecordElement, CalendarElement, FaceBubbleElement, FaceElement, FileElement, GiphyElement, GrayTipElement, MarketFaceElement, PicElement, PttElement, RecommendedMsgElement, ReplyElement, ShareLocationElement, StructLongMsgElement, TaskTopMsgElement, TextElement, TofuRecordElement, VideoElement, YoloGameResultElement } from './element'; /* diff --git a/packages/napcat-onebot/action/OneBotAction.ts b/packages/napcat-onebot/action/OneBotAction.ts index dee915b3..68f69457 100644 --- a/packages/napcat-onebot/action/OneBotAction.ts +++ b/packages/napcat-onebot/action/OneBotAction.ts @@ -5,9 +5,18 @@ import { NapCatOneBot11Adapter, OB11Return } from '@/napcat-onebot/index'; import { NetworkAdapterConfig } from '../config/config'; import { TSchema } from '@sinclair/typebox'; import { StreamPacket, StreamPacketBasic, StreamStatus } from './stream/StreamBasic'; +export const ActionExamples = { + Common: { + errors: [ + { code: 1400, description: '请求参数错误或业务逻辑执行失败' }, + { code: 1401, description: '权限不足' }, + { code: 1404, description: '资源不存在' } + ] + } +}; export class OB11Response { - private static createResponse(data: T, status: string, retcode: number, message: string = '', echo: unknown = null, useStream: boolean = false): OB11Return { + private static createResponse (data: T, status: string, retcode: number, message: string = '', echo: unknown = null, useStream: boolean = false): OB11Return { return { status, retcode, @@ -19,11 +28,11 @@ export class OB11Response { }; } - static res(data: T, status: string, retcode: number, message: string = '', echo: unknown = null, useStream: boolean = false): OB11Return { + static res (data: T, status: string, retcode: number, message: string = '', echo: unknown = null, useStream: boolean = false): OB11Return { return this.createResponse(data, status, retcode, message, echo, useStream); } - static ok(data: T, echo: unknown = null, useStream: boolean = false): OB11Return { + static ok (data: T, echo: unknown = null, useStream: boolean = false): OB11Return { return this.createResponse(data, 'ok', 0, '', echo, useStream); } @@ -32,15 +41,22 @@ export class OB11Response { } } export abstract class OneBotRequestToolkit { - abstract send(packet: StreamPacket): Promise; + abstract send (packet: StreamPacket): Promise; } export abstract class OneBotAction { actionName: typeof ActionName[keyof typeof ActionName] = ActionName.Unknown; core: NapCatCore; private validate?: ValidateFunction = undefined; payloadSchema?: TSchema = undefined; + returnSchema?: TSchema = undefined; + payloadExample?: unknown = undefined; + returnExample?: unknown = undefined; + actionSummary: string = ''; + actionDescription: string = ''; + actionTags: string[] = []; obContext: NapCatOneBot11Adapter; useStream: boolean = false; + errorExamples: Array<{ code: number, description: string; }> = ActionExamples.Common.errors; constructor (obContext: NapCatOneBot11Adapter, core: NapCatCore) { this.obContext = obContext; diff --git a/packages/napcat-onebot/action/example/ExtendsActionsExamples.ts b/packages/napcat-onebot/action/example/ExtendsActionsExamples.ts new file mode 100644 index 00000000..0b72b34b --- /dev/null +++ b/packages/napcat-onebot/action/example/ExtendsActionsExamples.ts @@ -0,0 +1,45 @@ +export const ExtendsActionsExamples = { + OCRImage: { + payload: { image: 'image_id_123' }, + response: { texts: [{ text: '识别内容', coordinates: [] }] }, + }, + GetAiCharacters: { + payload: { group_id: '123456' }, + response: [ + { + type: 'string', + characters: [ + { character_id: 'id', character_name: 'name', preview_url: 'url' } + ] + } + ], + }, + GetClientkey: { + payload: {}, + response: { clientkey: 'abcdef123456' }, + }, + SetQQAvatar: { + payload: { file: 'base64://...' }, + response: null, + }, + SetGroupKickMembers: { + payload: { group_id: '123456', user_id: ['123456789'], reject_add_request: false }, + response: null, + }, + TranslateEnWordToZn: { + payload: { words: ['hello'] }, + response: { words: ['你好'] }, + }, + GetRkey: { + payload: {}, + response: { rkey: '...' }, + }, + SetLongNick: { + payload: { longNick: '个性签名' }, + response: null, + }, + SetSpecialTitle: { + payload: { group_id: '123456', user_id: '123456789', special_title: '头衔' }, + response: null, + }, +}; diff --git a/packages/napcat-onebot/action/example/FileActionsExamples.ts b/packages/napcat-onebot/action/example/FileActionsExamples.ts new file mode 100644 index 00000000..9db7e976 --- /dev/null +++ b/packages/napcat-onebot/action/example/FileActionsExamples.ts @@ -0,0 +1,22 @@ +export const FileActionsExamples = { + GetFile: { + payload: { file: 'file_id_123' }, + response: { file: '/path/to/file', url: 'http://...', file_size: 1024, file_name: 'test.jpg' }, + }, + GetGroupFileUrl: { + payload: { group_id: '123456', file_id: 'file_id_123', busid: 102 }, + response: { url: 'http://...' }, + }, + GetImage: { + payload: { file: 'image_id_123' }, + response: { file: '/path/to/image', url: 'http://...' }, + }, + GetPrivateFileUrl: { + payload: { user_id: '123456789', file_id: 'file_id_123' }, + response: { url: 'http://...' }, + }, + GetRecord: { + payload: { file: 'record_id_123', out_format: 'mp3' }, + response: { file: '/path/to/record', url: 'http://...' }, + }, +}; diff --git a/packages/napcat-onebot/action/example/GoCQHTTPActionsExamples.ts b/packages/napcat-onebot/action/example/GoCQHTTPActionsExamples.ts new file mode 100644 index 00000000..32c19604 --- /dev/null +++ b/packages/napcat-onebot/action/example/GoCQHTTPActionsExamples.ts @@ -0,0 +1,102 @@ +export const GoCQHTTPActionsExamples = { + GetStrangerInfo: { + payload: { user_id: '123456789' }, + response: { user_id: 123456789, nickname: '昵称', sex: 'unknown' }, + }, + GetGroupHonorInfo: { + payload: { group_id: '123456', type: 'all' }, + response: { group_id: 123456, current_talkative: {}, talkative_list: [] }, + }, + GetForwardMsg: { + payload: { message_id: '123456' }, + response: { messages: [] }, + }, + SendForwardMsg: { + payload: { group_id: '123456', messages: [] }, + response: { message_id: 123456 }, + }, + GetGroupAtAllRemain: { + payload: { group_id: '123456' }, + response: { can_at_all: true, remain_at_all_count_for_group: 10, remain_at_all_count_for_self: 10 }, + }, + CreateGroupFileFolder: { + payload: { group_id: '123456', name: '测试目录' }, + response: { result: {}, groupItem: {} }, + }, + DeleteGroupFile: { + payload: { group_id: '123456', file_id: 'file_uuid_123' }, + response: {}, + }, + DeleteGroupFileFolder: { + payload: { group_id: '123456', folder_id: 'folder_uuid_123' }, + response: {}, + }, + DownloadFile: { + payload: { url: 'https://example.com/file.png', thread_count: 1, headers: 'User-Agent: NapCat' }, + response: { file: '/path/to/downloaded/file' }, + }, + GetFriendMsgHistory: { + payload: { user_id: '123456789', message_seq: 0, count: 20 }, + response: { messages: [] }, + }, + GetGroupFilesByFolder: { + payload: { group_id: '123456', folder_id: 'folder_id' }, + response: { files: [], folders: [] }, + }, + GetGroupFileSystemInfo: { + payload: { group_id: '123456' }, + response: { file_count: 10, limit_count: 10000, used_space: 1024, total_space: 10737418240 }, + }, + GetGroupMsgHistory: { + payload: { group_id: '123456', message_seq: 0, count: 20 }, + response: { messages: [] }, + }, + GetGroupRootFiles: { + payload: { group_id: '123456' }, + response: { files: [], folders: [] }, + }, + GetOnlineClient: { + payload: { no_cache: false }, + response: [], + }, + GoCQHTTPCheckUrlSafely: { + payload: { url: 'https://example.com' }, + response: { level: 1 }, + }, + GoCQHTTPDeleteFriend: { + payload: { user_id: '123456789' }, + response: {}, + }, + GoCQHTTPGetModelShow: { + payload: { model: 'iPhone 13' }, + response: { variants: [] }, + }, + GoCQHTTPSetModelShow: { + payload: { model: 'iPhone 13', model_show: 'iPhone 13' }, + response: {}, + }, + QuickAction: { + payload: { context: {}, operation: {} }, + response: {}, + }, + SendGroupNotice: { + payload: { group_id: '123456', content: '公告内容', image: 'base64://...' }, + response: {}, + }, + SetGroupPortrait: { + payload: { group_id: '123456', file: 'base64://...' }, + response: { result: 0, errMsg: '' }, + }, + SetQQProfile: { + payload: { nickname: '新昵称', personal_note: '个性签名' }, + response: {}, + }, + UploadGroupFile: { + payload: { group_id: '123456', file: '/path/to/file', name: 'test.txt' }, + response: { file_id: 'file_uuid_123' }, + }, + UploadPrivateFile: { + payload: { user_id: '123456789', file: '/path/to/file', name: 'test.txt' }, + response: { file_id: 'file_uuid_123' }, + }, +}; diff --git a/packages/napcat-onebot/action/example/GroupActionsExamples.ts b/packages/napcat-onebot/action/example/GroupActionsExamples.ts new file mode 100644 index 00000000..d17c1b44 --- /dev/null +++ b/packages/napcat-onebot/action/example/GroupActionsExamples.ts @@ -0,0 +1,79 @@ +export const GroupActionsExamples = { + DelEssenceMsg: { + payload: { message_id: 123456 }, + response: null, + }, + DelGroupNotice: { + payload: { group_id: '123456', notice_id: 'notice_123' }, + response: null, + }, + GetGroupDetailInfo: { + payload: { group_id: '123456' }, + response: { group_id: 123456, group_name: '测试群', member_count: 100, max_member_count: 500 }, + }, + GetGroupEssence: { + payload: { group_id: '123456' }, + response: [{ message_id: 123456, sender_id: 123456, sender_nick: '昵称', operator_id: 123456, operator_nick: '昵称', operator_time: 1710000000, content: '精华内容' }], + }, + GetGroupInfo: { + payload: { group_id: '123456' }, + response: { group_id: 123456, group_name: '测试群', member_count: 100, max_member_count: 500 }, + }, + GetGroupList: { + payload: {}, + response: [{ group_id: 123456, group_name: '测试群', member_count: 100, max_member_count: 500 }], + }, + GetGroupMemberInfo: { + payload: { group_id: '123456', user_id: '123456789' }, + response: { group_id: 123456, user_id: 123456789, nickname: '昵称', card: '名片', role: 'member' }, + }, + GetGroupMemberList: { + payload: { group_id: '123456' }, + response: [{ group_id: 123456, user_id: 123456789, nickname: '昵称', card: '名片', role: 'member' }], + }, + GetGroupNotice: { + payload: { group_id: '123456' }, + response: [{ notice_id: 'notice_123', sender_id: 123456, publish_time: 1710000000, message: { text: '公告内容', image: [] } }], + }, + SendGroupMsg: { + payload: { group_id: '123456', message: 'hello' }, + response: { message_id: 123456 }, + }, + SetEssenceMsg: { + payload: { message_id: 123456 }, + response: null, + }, + SetGroupAddRequest: { + payload: { flag: 'flag_123', sub_type: 'add', approve: true }, + response: null, + }, + SetGroupAdmin: { + payload: { group_id: '123456', user_id: '123456789', enable: true }, + response: null, + }, + SetGroupBan: { + payload: { group_id: '123456', user_id: '123456789', duration: 1800 }, + response: null, + }, + SetGroupCard: { + payload: { group_id: '123456', user_id: '123456789', card: '新名片' }, + response: null, + }, + SetGroupKick: { + payload: { group_id: '123456', user_id: '123456789', reject_add_request: false }, + response: null, + }, + SetGroupLeave: { + payload: { group_id: '123456', is_dismiss: false }, + response: null, + }, + SetGroupName: { + payload: { group_id: '123456', group_name: '新群名' }, + response: null, + }, + SetGroupWholeBan: { + payload: { group_id: '123456', enable: true }, + response: null, + }, + +}; diff --git a/packages/napcat-onebot/action/example/GuildActionsExamples.ts b/packages/napcat-onebot/action/example/GuildActionsExamples.ts new file mode 100644 index 00000000..2e0a1fad --- /dev/null +++ b/packages/napcat-onebot/action/example/GuildActionsExamples.ts @@ -0,0 +1,10 @@ +export const GuildActionsExamples = { + GetGuildList: { + payload: {}, + response: [{ guild_id: '123456', guild_name: '测试频道' }], + }, + GetGuildProfile: { + payload: { guild_id: '123456' }, + response: { guild_id: '123456', guild_name: '测试频道', guild_display_id: '123' }, + }, +}; diff --git a/packages/napcat-onebot/action/example/NewActionsExamples.ts b/packages/napcat-onebot/action/example/NewActionsExamples.ts new file mode 100644 index 00000000..6d218793 --- /dev/null +++ b/packages/napcat-onebot/action/example/NewActionsExamples.ts @@ -0,0 +1,10 @@ +export const NewActionsExamples = { + GetDoubtFriendsAddRequest: { + payload: { count: 10 }, + response: [{ user_id: 123456789, nickname: '昵称', age: 20, sex: 'male', reason: '申请理由', flag: 'flag_123' }], + }, + SetDoubtFriendsAddRequest: { + payload: { flag: 'flag_123', approve: true }, + response: {}, + }, +}; diff --git a/packages/napcat-onebot/action/example/PacketActionsExamples.ts b/packages/napcat-onebot/action/example/PacketActionsExamples.ts new file mode 100644 index 00000000..fc4e43ef --- /dev/null +++ b/packages/napcat-onebot/action/example/PacketActionsExamples.ts @@ -0,0 +1,14 @@ +export const PacketActionsExamples = { + GetPacketStatus: { + payload: {}, + response: { status: 'ok' }, + }, + SendPoke: { + payload: { user_id: '123456789' }, + response: {}, + }, + SetGroupTodo: { + payload: { group_id: '123456', message_id: '123456789' }, + response: {}, + }, +}; diff --git a/packages/napcat-onebot/action/example/SystemActionsExamples.ts b/packages/napcat-onebot/action/example/SystemActionsExamples.ts new file mode 100644 index 00000000..19137849 --- /dev/null +++ b/packages/napcat-onebot/action/example/SystemActionsExamples.ts @@ -0,0 +1,42 @@ +export const SystemActionsExamples = { + CanSendImage: { + payload: {}, + response: { yes: true }, + }, + CanSendRecord: { + payload: {}, + response: { yes: true }, + }, + CleanCache: { + payload: {}, + response: {}, + }, + GetCredentials: { + payload: {}, + response: { cookies: '...', csrf_token: 123456789 }, + }, + GetCSRF: { + payload: {}, + response: { token: 123456789 }, + }, + GetLoginInfo: { + payload: {}, + response: { user_id: 123456789, nickname: '机器人' }, + }, + GetStatus: { + payload: {}, + response: { online: true, good: true }, + }, + GetSystemMsg: { + payload: {}, + response: { invited_requests: [], join_requests: [] }, + }, + GetVersionInfo: { + payload: {}, + response: { app_name: 'NapCatQQ', app_version: '1.0.0', protocol_version: 'v11' }, + }, + SetRestart: { + payload: { delay: 0 }, + response: {}, + }, +}; diff --git a/packages/napcat-onebot/action/example/UserActionsExamples.ts b/packages/napcat-onebot/action/example/UserActionsExamples.ts new file mode 100644 index 00000000..558637aa --- /dev/null +++ b/packages/napcat-onebot/action/example/UserActionsExamples.ts @@ -0,0 +1,38 @@ +export const UserActionsExamples = { + GetCookies: { + payload: { domain: 'qun.qq.com' }, + response: { cookies: 'p_skey=xxx; p_uin=o0123456789;' }, + }, + GetFriendList: { + payload: {}, + response: [{ user_id: 123456789, nickname: '昵称', remark: '备注' }], + }, + GetRecentContact: { + payload: { count: 10 }, + response: [ + { + lastestMsg: 'hello', + peerUin: '123456789', + remark: 'remark', + msgTime: '1710000000', + chatType: 1, + msgId: '12345', + sendNickName: 'nick', + sendMemberName: 'card', + peerName: 'name', + }, + ], + }, + SendLike: { + payload: { user_id: '123456789', times: 10 }, + response: {}, + }, + SetFriendAddRequest: { + payload: { flag: 'flag_123', approve: true, remark: '好友' }, + response: {}, + }, + SetFriendRemark: { + payload: { user_id: '123456789', remark: '新备注' }, + response: {}, + }, +}; diff --git a/packages/napcat-onebot/action/extends/BotExit.ts b/packages/napcat-onebot/action/extends/BotExit.ts index e9542cfd..c00e4739 100644 --- a/packages/napcat-onebot/action/extends/BotExit.ts +++ b/packages/napcat-onebot/action/extends/BotExit.ts @@ -1,8 +1,15 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { OneBotAction } from '../OneBotAction'; +import { Type } from '@sinclair/typebox'; export class BotExit extends OneBotAction { override actionName = ActionName.Exit; + override payloadSchema = Type.Void(); + override returnSchema = Type.Void(); + override actionSummary = '退出登录'; + override actionTags = ['系统扩展']; + override payloadExample = {}; + override returnExample = null; async _handle () { process.exit(0); diff --git a/packages/napcat-onebot/action/extends/ClickInlineKeyboardButton.ts b/packages/napcat-onebot/action/extends/ClickInlineKeyboardButton.ts index 0384e2be..7da559c9 100644 --- a/packages/napcat-onebot/action/extends/ClickInlineKeyboardButton.ts +++ b/packages/napcat-onebot/action/extends/ClickInlineKeyboardButton.ts @@ -2,21 +2,36 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { OneBotAction } from '../OneBotAction'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - bot_appid: Type.String(), - button_id: Type.String({ default: '' }), - callback_data: Type.String({ default: '' }), - msg_seq: Type.String({ default: '10086' }), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + bot_appid: Type.String({ description: '机器人AppID' }), + button_id: Type.String({ default: '', description: '按钮ID' }), + callback_data: Type.String({ default: '', description: '回调数据' }), + msg_seq: Type.String({ default: '10086', description: '消息序列号' }), }); -type Payload = Static; +type PayloadType = Static; -export class ClickInlineKeyboardButton extends OneBotAction { +const ReturnSchema = Type.Any({ description: '点击结果' }); + +type ReturnType = Static; + +export class ClickInlineKeyboardButton extends OneBotAction { override actionName = ActionName.ClickInlineKeyboardButton; - override payloadSchema = SchemaData; - - async _handle (payload: Payload) { + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '点击内联键盘按钮'; + override actionTags = ['消息扩展']; + override payloadExample = { + group_id: '123456', + bot_appid: '1234567890', + button_id: 'btn_1', + callback_data: '', + msg_seq: '10086' + }; + override returnExample = { + }; + async _handle (payload: PayloadType) { return await this.core.apis.MsgApi.clickInlineKeyboardButton({ buttonId: payload.button_id, peerId: payload.group_id.toString(), diff --git a/packages/napcat-onebot/action/extends/CreateCollection.ts b/packages/napcat-onebot/action/extends/CreateCollection.ts index 9d21edb5..d1801d3f 100644 --- a/packages/napcat-onebot/action/extends/CreateCollection.ts +++ b/packages/napcat-onebot/action/extends/CreateCollection.ts @@ -2,18 +2,33 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Type, Static } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - rawData: Type.String(), - brief: Type.String(), +const PayloadSchema = Type.Object({ + rawData: Type.String({ description: '原始数据' }), + brief: Type.String({ description: '简要描述' }), }); -type Payload = Static; +type PayloadType = Static; -export class CreateCollection extends OneBotAction { +const ReturnSchema = Type.Any({ description: '创建结果' }); + +type ReturnType = Static; + +export class CreateCollection extends OneBotAction { override actionName = ActionName.CreateCollection; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '创建收藏'; + override actionTags = ['扩展接口']; + override payloadExample = { + rawData: '收藏内容', + brief: '收藏标题' + }; + override returnExample = { + result: 0, + errMsg: '' + }; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { return await this.core.apis.CollectionApi.createCollection( this.core.selfInfo.uin, this.core.selfInfo.uid, diff --git a/packages/napcat-onebot/action/extends/DelGroupAlbumMedia.ts b/packages/napcat-onebot/action/extends/DelGroupAlbumMedia.ts index ce79f7f1..bc5fd595 100644 --- a/packages/napcat-onebot/action/extends/DelGroupAlbumMedia.ts +++ b/packages/napcat-onebot/action/extends/DelGroupAlbumMedia.ts @@ -2,19 +2,34 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.String(), - album_id: Type.String(), - lloc: Type.String(), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + album_id: Type.String({ description: '相册ID' }), + lloc: Type.String({ description: '媒体ID (lloc)' }), }); -type Payload = Static; +type PayloadType = Static; -export class DelGroupAlbumMedia extends OneBotAction { +const ReturnSchema = Type.Any({ description: '删除结果' }); + +type ReturnType = Static; + +export class DelGroupAlbumMedia extends OneBotAction { override actionName = ActionName.DelGroupAlbumMedia; - override payloadSchema = SchemaData; + override actionSummary = '删除群相册媒体'; + override actionTags = ['群组扩展']; + override payloadExample = { + group_id: '123456', + album_id: 'album_id_1', + lloc: 'media_id_1', + }; + override returnExample = { + result: {} + }; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { return await this.core.apis.WebApi.deleteAlbumMediaByNTQQ( payload.group_id, payload.album_id, diff --git a/packages/napcat-onebot/action/extends/DoGroupAlbumComment.ts b/packages/napcat-onebot/action/extends/DoGroupAlbumComment.ts index d5ac79d2..54d73e20 100644 --- a/packages/napcat-onebot/action/extends/DoGroupAlbumComment.ts +++ b/packages/napcat-onebot/action/extends/DoGroupAlbumComment.ts @@ -2,20 +2,32 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.String(), - album_id: Type.String(), - lloc: Type.String(), - content: Type.String(), +export const DoGroupAlbumCommentPayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + album_id: Type.String({ description: '相册 ID' }), + lloc: Type.String({ description: '图片 ID' }), + content: Type.String({ description: '评论内容' }), }); -type Payload = Static; +export type DoGroupAlbumCommentPayload = Static; -export class DoGroupAlbumComment extends OneBotAction { +export class DoGroupAlbumComment extends OneBotAction { override actionName = ActionName.DoGroupAlbumComment; - override payloadSchema = SchemaData; + override actionSummary = '发表群相册评论'; + override actionTags = ['群组扩展']; + override payloadExample = { + group_id: '123456', + album_id: 'album_id_1', + lloc: 'media_id_1', + content: '很有意思' + }; + override returnExample = { + result: {} + }; + override payloadSchema = DoGroupAlbumCommentPayloadSchema; + override returnSchema = Type.Any({ description: '评论结果' }); - async _handle (payload: Payload) { + async _handle (payload: DoGroupAlbumCommentPayload) { return await this.core.apis.WebApi.doAlbumMediaPlainCommentByNTQQ( payload.group_id, payload.album_id, diff --git a/packages/napcat-onebot/action/extends/FetchCustomFace.ts b/packages/napcat-onebot/action/extends/FetchCustomFace.ts index 11d5aa7d..0354bbaf 100644 --- a/packages/napcat-onebot/action/extends/FetchCustomFace.ts +++ b/packages/napcat-onebot/action/extends/FetchCustomFace.ts @@ -2,18 +2,32 @@ import { Type, Static } from '@sinclair/typebox'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; -const SchemaData = Type.Object({ - count: Type.Union([Type.Number(), Type.String()], { default: 48 }), +const PayloadSchema = Type.Object({ + count: Type.Union([Type.Number(), Type.String()], { default: 48, description: '获取数量' }), }); -type Payload = Static; +type PayloadType = Static; -export class FetchCustomFace extends OneBotAction { +const ReturnSchema = Type.Array(Type.String(), { description: '表情URL列表' }); + +type ReturnType = Static; + +export class FetchCustomFace extends OneBotAction { override actionName = ActionName.FetchCustomFace; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取自定义表情'; + override actionTags = ['系统扩展']; + override payloadExample = { + count: 10 + }; + override returnExample = [ + 'http://example.com/face1.png' + ]; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { const ret = await this.core.apis.MsgApi.fetchFavEmojiList(+payload.count); return ret.emojiInfoList.map(e => e.url); } } + diff --git a/packages/napcat-onebot/action/extends/FetchEmojiLike.ts b/packages/napcat-onebot/action/extends/FetchEmojiLike.ts index 8b9d04c1..f619a303 100644 --- a/packages/napcat-onebot/action/extends/FetchEmojiLike.ts +++ b/packages/napcat-onebot/action/extends/FetchEmojiLike.ts @@ -2,29 +2,68 @@ import { Type, Static } from '@sinclair/typebox'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { MessageUnique } from 'napcat-common/src/message-unique'; -import { type NTQQMsgApi } from 'napcat-core/apis'; -const SchemaData = Type.Object({ - message_id: Type.Union([Type.Number(), Type.String()]), - emojiId: Type.Union([Type.Number(), Type.String()]), - emojiType: Type.Union([Type.Number(), Type.String()]), - count: Type.Union([Type.Number(), Type.String()], { default: 20 }), - cookie: Type.String({ default: '' }) +const PayloadSchema = Type.Object({ + message_id: Type.Union([Type.Number(), Type.String()], { description: '消息ID' }), + emojiId: Type.Union([Type.Number(), Type.String()], { description: '表情ID' }), + emojiType: Type.Union([Type.Number(), Type.String()], { description: '表情类型' }), + count: Type.Union([Type.Number(), Type.String()], { default: 20, description: '获取数量' }), + cookie: Type.String({ default: '', description: '分页Cookie' }) }); -type Payload = Static; +type PayloadType = Static; -export class FetchEmojiLike extends OneBotAction>> { +const ReturnSchema = Type.Object({ + emojiLikesList: Type.Array(Type.Object({ + tinyId: Type.String({ description: 'TinyID' }), + nickName: Type.String({ description: '昵称' }), + headUrl: Type.String({ description: '头像URL' }), + }), { description: '表情回应列表' }), + cookie: Type.String({ description: '分页Cookie' }), + isLastPage: Type.Boolean({ description: '是否最后一页' }), + isFirstPage: Type.Boolean({ description: '是否第一页' }), + result: Type.Number({ description: '结果状态码' }), + errMsg: Type.String({ description: '错 误信息' }), +}, { description: '表情回应详情' }); + +type ReturnType = Static; + +export class FetchEmojiLike extends OneBotAction { override actionName = ActionName.FetchEmojiLike; - override payloadSchema = SchemaData; + override actionSummary = '获取表情点赞详情'; + override actionTags = ['消息扩展']; + override payloadExample = { + message_id: 12345, + emojiId: '123', + emojiType: 1, + count: 10, + cookie: '' + }; + override returnExample = { + emojiLikesList: [ + { + tinyId: '123456', + nickName: '测试用户', + headUrl: 'http://example.com/avatar.png' + } + ], + cookie: '', + isLastPage: true, + isFirstPage: true, + result: 0, + errMsg: '' + }; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; - async _handle (payload: Payload) { + async _handle (payload: PayloadType): Promise { const msgIdPeer = MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id); if (!msgIdPeer) throw new Error('消息不存在'); const msg = (await this.core.apis.MsgApi.getMsgsByMsgId(msgIdPeer.Peer, [msgIdPeer.MsgId])).msgList[0]; if (!msg) throw new Error('消息不存在'); - return await this.core.apis.MsgApi.getMsgEmojiLikesList( + const res = await this.core.apis.MsgApi.getMsgEmojiLikesList( msgIdPeer.Peer, msg.msgSeq, payload.emojiId.toString(), payload.emojiType.toString(), payload.cookie, +payload.count ); + return res; } } diff --git a/packages/napcat-onebot/action/extends/GetAiCharacters.ts b/packages/napcat-onebot/action/extends/GetAiCharacters.ts index 2a7bf779..3bdd5b13 100644 --- a/packages/napcat-onebot/action/extends/GetAiCharacters.ts +++ b/packages/napcat-onebot/action/extends/GetAiCharacters.ts @@ -1,30 +1,46 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { GetPacketStatusDepends } from '@/napcat-onebot/action/packet/GetPacketStatus'; -import { AIVoiceChatType } from 'napcat-core/packet/entities/aiChat'; import { Type, Static } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - chat_type: Type.Union([Type.Union([Type.Number(), Type.String()])], { default: 1 }), +import { ExtendsActionsExamples } from '../example/ExtendsActionsExamples'; + +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + chat_type: Type.Union([Type.Number(), Type.String()], { default: 1, description: '聊天类型' }), }); -type Payload = Static; +type PayloadType = Static; -interface GetAiCharactersResponse { - type: string; - characters: { - character_id: string; - character_name: string; - preview_url: string; - }[]; -} +const ReturnSchema = Type.Array( + Type.Object({ + type: Type.String({ description: '角色类型' }), + characters: Type.Array( + Type.Object({ + character_id: Type.String({ description: '角色ID' }), + character_name: Type.String({ description: '角色名称' }), + preview_url: Type.String({ description: '预览URL' }), + }), + { description: '角色列表' } + ), + }), + { description: 'AI角色列表' } +); -export class GetAiCharacters extends GetPacketStatusDepends { +type ReturnType = Static; + +export class GetAiCharacters extends GetPacketStatusDepends { override actionName = ActionName.GetAiCharacters; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取AI角色列表'; + override actionDescription = '获取群聊中的AI角色列表'; + override actionTags = ['扩展接口']; + override payloadExample = ExtendsActionsExamples.GetAiCharacters.payload; + override returnExample = ExtendsActionsExamples.GetAiCharacters.response; - async _handle (payload: Payload) { - const rawList = await this.core.apis.PacketApi.pkt.operation.FetchAiVoiceList(+payload.group_id, +payload.chat_type as AIVoiceChatType); + async _handle (payload: PayloadType) { + const chatTypeNum = Number(payload.chat_type); + const rawList = await this.core.apis.PacketApi.pkt.operation.FetchAiVoiceList(+payload.group_id, chatTypeNum); return rawList?.map((item) => ({ type: item.category, characters: item.voices.map((voice) => ({ diff --git a/packages/napcat-onebot/action/extends/GetClientkey.ts b/packages/napcat-onebot/action/extends/GetClientkey.ts index a028609b..c806fdd7 100644 --- a/packages/napcat-onebot/action/extends/GetClientkey.ts +++ b/packages/napcat-onebot/action/extends/GetClientkey.ts @@ -1,12 +1,24 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { OneBotAction } from '../OneBotAction'; +import { Type, Static } from '@sinclair/typebox'; -interface GetClientkeyResponse { - clientkey?: string; -} +import { ExtendsActionsExamples } from '../example/ExtendsActionsExamples'; -export class GetClientkey extends OneBotAction { +const ReturnSchema = Type.Object({ + clientkey: Type.Optional(Type.String({ description: '客户端Key' })), +}, { description: '获取ClientKey结果' }); + +type ReturnType = Static; + +export class GetClientkey extends OneBotAction { override actionName = ActionName.GetClientkey; + override payloadSchema = Type.Void(); + override returnSchema = ReturnSchema; + override actionSummary = '获取ClientKey'; + override actionDescription = '获取当前登录帐号的ClientKey'; + override actionTags = ['扩展接口']; + override payloadExample = ExtendsActionsExamples.GetClientkey.payload; + override returnExample = ExtendsActionsExamples.GetClientkey.response; async _handle () { return { clientkey: (await this.core.apis.UserApi.forceFetchClientKey()).clientKey }; diff --git a/packages/napcat-onebot/action/extends/GetCollectionList.ts b/packages/napcat-onebot/action/extends/GetCollectionList.ts index eb990860..3d5d2d72 100644 --- a/packages/napcat-onebot/action/extends/GetCollectionList.ts +++ b/packages/napcat-onebot/action/extends/GetCollectionList.ts @@ -1,20 +1,81 @@ -import { type NTQQCollectionApi } from 'napcat-core/apis/collection'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Type, Static } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - category: Type.Union([Type.Number(), Type.String()]), - count: Type.Union([Type.Union([Type.Number(), Type.String()])], { default: 1 }), +const PayloadSchema = Type.Object({ + category: Type.String({ description: '分类ID' }), + count: Type.String({ default: '50', description: '获取数量' }), }); -type Payload = Static; +type PayloadType = Static; -export class GetCollectionList extends OneBotAction>> { +const ReturnSchema = Type.Any({ description: '收藏列表' }); + +type ReturnType = Static; + +export class GetCollectionList extends OneBotAction { override actionName = ActionName.GetCollectionList; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取收藏列表'; + override actionTags = ['系统扩展']; + override payloadExample = { + category: '0', + count: '50' + }; + override returnExample = { + errCode: 0, + errMsg: "", + collectionSearchList: { + collectionItemList: [ + { + cid: "123456", + type: 8, + status: 1, + author: { + type: 2, + numId: "123456", + strId: "昵称", + groupId: "123456", + groupName: "群名", + uid: "123456" + }, + bid: 1, + category: 1, + createTime: "1769169157000", + collectTime: "1769413477691", + modifyTime: "1769413477691", + sequence: "1769413476735", + shareUrl: "", + customGroupId: 0, + securityBeat: false, + summary: { + textSummary: null, + linkSummary: null, + gallerySummary: null, + audioSummary: null, + videoSummary: null, + fileSummary: null, + locationSummary: null, + richMediaSummary: { + title: "", + subTitle: "", + brief: "text", + picList: [], + contentType: 1, + originalUri: "", + publisher: "", + richMediaVersion: 0 + } + } + } + ], + hasMore: false, + bottomTimeStamp: "1769413477691" + } + }; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { return await this.core.apis.CollectionApi.getAllCollection(+payload.category, +payload.count); } } diff --git a/packages/napcat-onebot/action/extends/GetEmojiLikes.ts b/packages/napcat-onebot/action/extends/GetEmojiLikes.ts index 5eaee161..c63acc91 100644 --- a/packages/napcat-onebot/action/extends/GetEmojiLikes.ts +++ b/packages/napcat-onebot/action/extends/GetEmojiLikes.ts @@ -26,7 +26,22 @@ type ReturnType = Static; export class GetEmojiLikes extends OneBotAction { override actionName = ActionName.GetEmojiLikes; + override actionSummary = '获取消息表情点赞列表'; + override actionTags = ['消息扩展']; + override payloadExample = { + message_id: '12345', + emoji_id: '123' + }; + override returnExample = { + emoji_like_list: [ + { + user_id: '654321', + nick_name: '测试用户' + } + ] + }; override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; async _handle (payload: PayloadType) { let peer: Peer; diff --git a/packages/napcat-onebot/action/extends/GetFriendWithCategory.ts b/packages/napcat-onebot/action/extends/GetFriendWithCategory.ts index 6219461e..0d81d652 100644 --- a/packages/napcat-onebot/action/extends/GetFriendWithCategory.ts +++ b/packages/napcat-onebot/action/extends/GetFriendWithCategory.ts @@ -1,12 +1,40 @@ import { OB11Construct } from '@/napcat-onebot/helper/data'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; +import { Type, Static } from '@sinclair/typebox'; +import { OB11UserSchema } from '../schemas'; -export class GetFriendWithCategory extends OneBotAction { +const ReturnSchema = Type.Array( + Type.Object({ + categoryId: Type.Number({ description: '分组ID' }), + categoryName: Type.String({ description: '分组名称' }), + categoryMbCount: Type.Number({ description: '分组内好友数量' }), + buddyList: Type.Array(OB11UserSchema, { description: '好友列表' }), + }), + { description: '带分组的好友列表' } +); + +type ReturnType = Static; + +export class GetFriendWithCategory extends OneBotAction { override actionName = ActionName.GetFriendsWithCategory; + override payloadSchema = Type.Void(); + override returnSchema = ReturnSchema; + override actionSummary = '获取带分组的好友列表'; + override actionTags = ['用户扩展']; + override payloadExample = {}; + override returnExample = [ + { + categoryId: 1, + categoryName: '我的好友', + categoryMbCount: 1, + buddyList: [] + } + ]; async _handle () { - return (await this.core.apis.FriendApi.getBuddyV2ExWithCate()).map(category => ({ + const categories = await this.core.apis.FriendApi.getBuddyV2ExWithCate(); + return categories.map(category => ({ ...category, buddyList: OB11Construct.friends(category.buddyList), })); diff --git a/packages/napcat-onebot/action/extends/GetGroupAddRequest.ts b/packages/napcat-onebot/action/extends/GetGroupAddRequest.ts index 4dedf591..a84258a8 100644 --- a/packages/napcat-onebot/action/extends/GetGroupAddRequest.ts +++ b/packages/napcat-onebot/action/extends/GetGroupAddRequest.ts @@ -1,16 +1,51 @@ import { GroupNotifyMsgStatus } from 'napcat-core'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; -import { Notify } from '@/napcat-onebot/types'; +import { Type, Static } from '@sinclair/typebox'; -export default class GetGroupAddRequest extends OneBotAction { +const ReturnSchema = Type.Array( + Type.Object({ + request_id: Type.Number({ description: '请求ID' }), + invitor_uin: Type.Number({ description: '邀请者QQ' }), + invitor_nick: Type.Optional(Type.String({ description: '邀请者昵称' })), + group_id: Type.Number({ description: '群号' }), + message: Type.Optional(Type.String({ description: '验证信息' })), + group_name: Type.Optional(Type.String({ description: '群名称' })), + checked: Type.Boolean({ description: '是否已处理' }), + actor: Type.Number({ description: '处理者QQ' }), + requester_nick: Type.Optional(Type.String({ description: '请求者昵称' })), + }), + { description: '群通知列表' } +); + +type ReturnType = Static; + +export default class GetGroupAddRequest extends OneBotAction { override actionName = ActionName.GetGroupIgnoreAddRequest; + override payloadSchema = Type.Void(); + override returnSchema = ReturnSchema; + override actionSummary = '获取群被忽略的加群请求'; + override actionTags = ['群组接口']; + override payloadExample = {}; + override returnExample = [ + { + request_id: 12345, + invitor_uin: 123456789, + invitor_nick: '邀请者', + group_id: 123456789, + message: '加群请求', + group_name: '群名称', + checked: false, + actor: 0, + requester_nick: '请求者' + } + ]; - async _handle (): Promise { + async _handle (): Promise { const NTQQUserApi = this.core.apis.UserApi; const NTQQGroupApi = this.core.apis.GroupApi; const ignoredNotifies = await NTQQGroupApi.getSingleScreenNotifies(true, 10); - const retData: Notify[] = []; + const retData: ReturnType = []; const notifyPromises = ignoredNotifies .filter(notify => notify.type === 7) diff --git a/packages/napcat-onebot/action/extends/GetGroupAlbumMediaList.ts b/packages/napcat-onebot/action/extends/GetGroupAlbumMediaList.ts index 25f55534..cc9dce06 100644 --- a/packages/napcat-onebot/action/extends/GetGroupAlbumMediaList.ts +++ b/packages/napcat-onebot/action/extends/GetGroupAlbumMediaList.ts @@ -2,19 +2,35 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.String(), - album_id: Type.String(), - attach_info: Type.String({ default: '' }), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + album_id: Type.String({ description: '相册ID' }), + attach_info: Type.String({ default: '', description: '附加信息(用于分页)' }), }); -type Payload = Static; +type PayloadType = Static; -export class GetGroupAlbumMediaList extends OneBotAction { +const ReturnSchema = Type.Any({ description: '相册媒体列表' }); + +type ReturnType = Static; + +export class GetGroupAlbumMediaList extends OneBotAction { override actionName = ActionName.GetGroupAlbumMediaList; - override payloadSchema = SchemaData; + override actionSummary = '获取群相册媒体列表'; + override actionTags = ['群组扩展']; + override payloadExample = { + group_id: '123456', + album_id: 'album_id_1', + }; + override returnExample = { + media_list: [ + { media_id: 'media_id_1', url: 'http://example.com/1.jpg' } + ] + }; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { return await this.core.apis.WebApi.getAlbumMediaListByNTQQ( payload.group_id, payload.album_id, diff --git a/packages/napcat-onebot/action/extends/GetGroupInfoEx.ts b/packages/napcat-onebot/action/extends/GetGroupInfoEx.ts index c05ae9d6..0d389e91 100644 --- a/packages/napcat-onebot/action/extends/GetGroupInfoEx.ts +++ b/packages/napcat-onebot/action/extends/GetGroupInfoEx.ts @@ -1,17 +1,30 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Type, Static } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), }); -type Payload = Static; +type PayloadType = Static; -export class GetGroupInfoEx extends OneBotAction { +const ReturnSchema = Type.Any({ description: '群扩展信息' }); + +type ReturnType = Static; + +export class GetGroupInfoEx extends OneBotAction { override actionName = ActionName.GetGroupInfoEx; - override payloadSchema = SchemaData; + override actionSummary = '获取群详细信息 (扩展)'; + override actionTags = ['群组扩展']; + override payloadExample = { + group_id: '123456' + }; + override returnExample = { + + }; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { return (await this.core.apis.GroupApi.getGroupExtFE0Info([payload.group_id.toString()])).result.groupExtInfos.get(payload.group_id.toString()); } } diff --git a/packages/napcat-onebot/action/extends/GetMiniAppArk.ts b/packages/napcat-onebot/action/extends/GetMiniAppArk.ts index f72ff005..647f45ad 100644 --- a/packages/napcat-onebot/action/extends/GetMiniAppArk.ts +++ b/packages/napcat-onebot/action/extends/GetMiniAppArk.ts @@ -1,57 +1,79 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { GetPacketStatusDepends } from '@/napcat-onebot/action/packet/GetPacketStatus'; import { MiniAppInfo, MiniAppInfoHelper } from 'napcat-core/packet/utils/helper/miniAppHelper'; -import { MiniAppData, MiniAppRawData, MiniAppReqCustomParams, MiniAppReqParams } from 'napcat-core/packet/entities/miniApp'; +import { MiniAppReqCustomParams, MiniAppReqParams } from 'napcat-core/packet/entities/miniApp'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Union([ +const PayloadSchema = Type.Union([ Type.Object({ - type: Type.Union([Type.Literal('bili'), Type.Literal('weibo')]), - title: Type.String(), - desc: Type.String(), - picUrl: Type.String(), - jumpUrl: Type.String(), - webUrl: Type.Optional(Type.String()), - rawArkData: Type.Optional(Type.Union([Type.String()])), + type: Type.Union([Type.Literal('bili'), Type.Literal('weibo')], { description: '模板类型' }), + title: Type.String({ description: '标题' }), + desc: Type.String({ description: '描述' }), + picUrl: Type.String({ description: '图片URL' }), + jumpUrl: Type.String({ description: '跳转URL' }), + webUrl: Type.Optional(Type.String({ description: '网页URL' })), + rawArkData: Type.Optional(Type.Union([Type.String()], { description: '是否返回原始Ark数据' })), }), Type.Object({ - title: Type.String(), - desc: Type.String(), - picUrl: Type.String(), - jumpUrl: Type.String(), - iconUrl: Type.String(), - webUrl: Type.Optional(Type.String()), - appId: Type.String(), - scene: Type.Union([Type.Number(), Type.String()]), - templateType: Type.Union([Type.Number(), Type.String()]), - businessType: Type.Union([Type.Number(), Type.String()]), - verType: Type.Union([Type.Number(), Type.String()]), - shareType: Type.Union([Type.Number(), Type.String()]), - versionId: Type.String(), - sdkId: Type.String(), - withShareTicket: Type.Union([Type.Number(), Type.String()]), - rawArkData: Type.Optional(Type.Union([Type.String()])), + title: Type.String({ description: '标题' }), + desc: Type.String({ description: '描述' }), + picUrl: Type.String({ description: '图片URL' }), + jumpUrl: Type.String({ description: '跳转URL' }), + iconUrl: Type.String({ description: '图标URL' }), + webUrl: Type.Optional(Type.String({ description: '网页URL' })), + appId: Type.String({ description: '小程序AppID' }), + scene: Type.String({ description: '场景ID' }), + templateType: Type.String({ description: '模板类型' }), + businessType: Type.String({ description: '业务类型' }), + verType: Type.String({ description: '版本类型' }), + shareType: Type.String({ description: '分享类型' }), + versionId: Type.String({ description: '版本ID' }), + sdkId: Type.String({ description: 'SDK ID' }), + withShareTicket: Type.String({ description: '是否携带分享票据' }), + rawArkData: Type.Optional(Type.String({ description: '是否返回原始Ark数据' })), }), -]); -type Payload = Static; +], { description: '小程序Ark参数' }); -export class GetMiniAppArk extends GetPacketStatusDepends { +type PayloadType = Static; + +const ReturnSchema = Type.Object({ + data: Type.Any({ description: 'Ark数据' }), +}, { description: '获取小程序Ark结果' }); + +type ReturnType = Static; + +export class GetMiniAppArk extends GetPacketStatusDepends { override actionName = ActionName.GetMiniAppArk; - override payloadSchema = SchemaData; - - async _handle (payload: Payload) { + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; override actionSummary = '获取小程序 Ark'; + override actionTags = ['系统扩展']; + override payloadExample = { + type: 'bili', + title: '测试标题', + desc: '测试描述', + picUrl: 'http://example.com/pic.jpg', + jumpUrl: 'http://example.com' + }; + override returnExample = { + data: { + ark: 'ark_content' + } + }; + async _handle (payload: PayloadType) { let reqParam: MiniAppReqParams; - const customParams = { + const customParams: MiniAppReqCustomParams = { title: payload.title, desc: payload.desc, picUrl: payload.picUrl, jumpUrl: payload.jumpUrl, - webUrl: payload.webUrl, - } as MiniAppReqCustomParams; + webUrl: payload.webUrl ?? '', + }; if ('type' in payload) { - reqParam = MiniAppInfoHelper.generateReq(customParams, MiniAppInfo.get(payload.type)!.template); + const template = MiniAppInfo.get(payload.type)?.template; + if (!template) { + throw new Error('未知的模板类型'); + } + reqParam = MiniAppInfoHelper.generateReq(customParams, template); } else { const { appId, scene, iconUrl, templateType, businessType, verType, shareType, versionId, withShareTicket } = payload; reqParam = MiniAppInfoHelper.generateReq( diff --git a/packages/napcat-onebot/action/extends/GetProfileLike.ts b/packages/napcat-onebot/action/extends/GetProfileLike.ts index 0155fb64..3dbf7823 100644 --- a/packages/napcat-onebot/action/extends/GetProfileLike.ts +++ b/packages/napcat-onebot/action/extends/GetProfileLike.ts @@ -1,36 +1,65 @@ -import { NTVoteInfo } from 'napcat-core'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Type, Static } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - user_id: Type.Optional(Type.Union([Type.Number(), Type.String()])), - start: Type.Union([Type.Number(), Type.String()], { default: 0 }), - count: Type.Union([Type.Number(), Type.String()], { default: 10 }), +const PayloadSchema = Type.Object({ + user_id: Type.Optional(Type.String({ description: 'QQ号' })), + start: Type.Union([Type.Number(), Type.String()], { default: 0, description: '起始位置' }), + count: Type.Union([Type.Number(), Type.String()], { default: 10, description: '获取数量' }), }); -type Payload = Static; +type PayloadType = Static; -export class GetProfileLike extends OneBotAction; - total_count: number; - last_time: number; - today_count: number; - }; - voteInfo: { - total_count: number; - new_count: number; - new_nearby_count: number; - last_visit_time: number; - userInfos: Array; - }; -}> { +const ReturnSchema = Type.Object({ + uid: Type.String({ description: '用户UID' }), + time: Type.String({ description: '时间' }), + favoriteInfo: Type.Object({ + userInfos: Type.Array(Type.Any(), { description: '点赞用户信息' }), + total_count: Type.Number({ description: '总点赞数' }), + last_time: Type.Number({ description: '最后点赞时间' }), + today_count: Type.Number({ description: '今日点赞数' }), + }), + voteInfo: Type.Object({ + total_count: Type.Number({ description: '总点赞数' }), + new_count: Type.Number({ description: '新增点赞数' }), + new_nearby_count: Type.Number({ description: '新增附近点赞数' }), + last_visit_time: Type.Number({ description: '最后访问时间' }), + userInfos: Type.Array(Type.Any(), { description: '点赞用户信息' }), + }), +}, { description: '点赞详情' }); + +type ReturnType = Static; + +export class GetProfileLike extends OneBotAction { override actionName = ActionName.GetProfileLike; - override payloadSchema = SchemaData; - async _handle (payload: Payload) { + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取资料点赞'; + override actionTags = ['用户扩展']; + override payloadExample = { + user_id: '123456789', + start: 0, + count: 10 + }; + override returnExample = { + uid: 'u_123', + time: '1734567890', + favoriteInfo: { + userInfos: [], + total_count: 10, + last_time: 1734567890, + today_count: 5 + }, + voteInfo: { + total_count: 100, + new_count: 2, + new_nearby_count: 0, + last_visit_time: 1734567890, + userInfos: [] + } + }; + + async _handle (payload: PayloadType): Promise { const isSelf = this.core.selfInfo.uin === payload.user_id || !payload.user_id; const userUid = isSelf || !payload.user_id ? this.core.selfInfo.uid : await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString()); const type = isSelf ? 2 : 1; diff --git a/packages/napcat-onebot/action/extends/GetQunAlbumList.ts b/packages/napcat-onebot/action/extends/GetQunAlbumList.ts index cae53964..c2d2cc12 100644 --- a/packages/napcat-onebot/action/extends/GetQunAlbumList.ts +++ b/packages/napcat-onebot/action/extends/GetQunAlbumList.ts @@ -1,18 +1,37 @@ -import { NTQQWebApi } from 'napcat-core/apis'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.String(), +import { NTQQWebApi } from 'napcat-core/apis'; + +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), }); -type Payload = Static; +type PayloadType = Static; -export class GetQunAlbumList extends OneBotAction>['response']['album_list']> { +const ReturnSchema = Type.Array(Type.Any(), { description: '群相册列表' }); + +type GetQunAlbumListReturn = Awaited>['response']['album_list']; + +export class GetQunAlbumList extends OneBotAction { override actionName = ActionName.GetQunAlbumList; - override payloadSchema = SchemaData; + override actionSummary = '获取群相册列表'; + override actionTags = ['群组扩展']; + override payloadExample = { + group_id: '123456', + }; + override returnExample = [ + { + album_id: 'album_1', + album_name: '测试相册', + cover_url: 'http://example.com/cover.jpg', + create_time: 1734567890 + } + ]; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; - async _handle (payload: Payload) { + async _handle (payload: PayloadType): Promise { return (await this.core.apis.WebApi.getAlbumListByNTQQ(payload.group_id)).response.album_list; } } diff --git a/packages/napcat-onebot/action/extends/GetRkey.ts b/packages/napcat-onebot/action/extends/GetRkey.ts index 0fa087d4..e2eaf681 100644 --- a/packages/napcat-onebot/action/extends/GetRkey.ts +++ b/packages/napcat-onebot/action/extends/GetRkey.ts @@ -1,8 +1,24 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { GetPacketStatusDepends } from '@/napcat-onebot/action/packet/GetPacketStatus'; +import { Type, Static } from '@sinclair/typebox'; -export class GetRkey extends GetPacketStatusDepends> { +const ReturnSchema = Type.Array(Type.Any(), { description: 'Rkey列表' }); + +type ReturnType = Static; + +export class GetRkey extends GetPacketStatusDepends { override actionName = ActionName.GetRkey; + override payloadSchema = Type.Void(); + override returnSchema = ReturnSchema; + override actionSummary = '获取 RKey'; + override actionTags = ['系统扩展']; + override payloadExample = {}; + override returnExample = [ + { + "key": "rkey_value", + "expired": 1734567890 + } + ]; async _handle () { return await this.core.apis.PacketApi.pkt.operation.FetchRkey(); diff --git a/packages/napcat-onebot/action/extends/GetRobotUinRange.ts b/packages/napcat-onebot/action/extends/GetRobotUinRange.ts index 3c7ae570..84e61939 100644 --- a/packages/napcat-onebot/action/extends/GetRobotUinRange.ts +++ b/packages/napcat-onebot/action/extends/GetRobotUinRange.ts @@ -1,8 +1,21 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; +import { Type, Static } from '@sinclair/typebox'; -export class GetRobotUinRange extends OneBotAction> { +const ReturnSchema = Type.Array(Type.Any(), { description: '机器人Uin范围列表' }); + +type ReturnType = Static; + +export class GetRobotUinRange extends OneBotAction { override actionName = ActionName.GetRobotUinRange; + override actionSummary = '获取机器人 UIN 范围'; + override actionTags = ['系统扩展']; + override payloadExample = {}; + override returnExample = [ + { minUin: '12345678', maxUin: '87654321' } + ]; + override payloadSchema = Type.Void(); + override returnSchema = ReturnSchema; async _handle () { return await this.core.apis.UserApi.getRobotUinRange(); diff --git a/packages/napcat-onebot/action/extends/GetUnidirectionalFriendList.ts b/packages/napcat-onebot/action/extends/GetUnidirectionalFriendList.ts index 5d58476f..077d35c1 100644 --- a/packages/napcat-onebot/action/extends/GetUnidirectionalFriendList.ts +++ b/packages/napcat-onebot/action/extends/GetUnidirectionalFriendList.ts @@ -2,26 +2,37 @@ import { PacketBuf } from 'napcat-core/packet/transformer/base'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { ProtoBuf, ProtoBufBase, PBUint32, PBString } from 'napcat.protobuf'; +import { Type, Static } from '@sinclair/typebox'; -interface Friend { - uin: number; - uid: string; - nick_name: string; - age: number; - source: string; -} +const ReturnSchema = Type.Array( + Type.Object({ + uin: Type.Number({ description: 'QQ号' }), + uid: Type.String({ description: '用户UID' }), + nick_name: Type.String({ description: '昵称' }), + age: Type.Number({ description: '年龄' }), + source: Type.String({ description: '来源' }), + }), + { description: '单向好友列表' } +); -interface Block { - str_uid: string; - bytes_source: string; - uint32_sex: number; - uint32_age: number; - bytes_nick: string; - uint64_uin: number; -} +type ReturnType = Static; -export class GetUnidirectionalFriendList extends OneBotAction { +export class GetUnidirectionalFriendList extends OneBotAction { override actionName = ActionName.GetUnidirectionalFriendList; + override payloadSchema = Type.Void(); + override returnSchema = ReturnSchema; + override actionSummary = '获取单向好友列表'; + override actionTags = ['用户扩展']; + override payloadExample = {}; + override returnExample = [ + { + uin: 123456789, + uid: 'u_123', + nick_name: '单向好友', + age: 20, + source: '来源' + } + ]; async pack_data (data: string): Promise { return ProtoBuf(class extends ProtoBufBase { @@ -30,7 +41,7 @@ export class GetUnidirectionalFriendList extends OneBotAction { }).encode(); } - async _handle (): Promise { + async _handle (): Promise { const self_id = this.core.selfInfo.uin; const req_json = { uint64_uin: self_id, @@ -40,10 +51,18 @@ export class GetUnidirectionalFriendList extends OneBotAction { }; const packed_data = await this.pack_data(JSON.stringify(req_json)); const data = Buffer.from(packed_data); - const rsq = { cmd: 'MQUpdateSvc_com_qq_ti.web.OidbSvc.0xe17_0', data: data as PacketBuf }; + const rsq = { cmd: 'MQUpdateSvc_com_qq_ti.web.OidbSvc.0xe17_0', data: data as unknown as PacketBuf }; const rsp_data = await this.core.apis.PacketApi.pkt.operation.sendPacket(rsq, true); const block_json = ProtoBuf(class extends ProtoBufBase { data = PBString(4); }).decode(rsp_data); - const block_list: Block[] = JSON.parse(block_json.data).rpt_block_list; + interface BlockItem { + uint64_uin: number; + str_uid: string; + bytes_nick: string; + uint32_age: number; + bytes_source: string; + } + const block_data: { rpt_block_list: BlockItem[]; } = JSON.parse(block_json.data); + const block_list = block_data.rpt_block_list; return block_list.map((block) => ({ uin: block.uint64_uin, diff --git a/packages/napcat-onebot/action/extends/GetUserStatus.ts b/packages/napcat-onebot/action/extends/GetUserStatus.ts index fd43dcfe..65860762 100644 --- a/packages/napcat-onebot/action/extends/GetUserStatus.ts +++ b/packages/napcat-onebot/action/extends/GetUserStatus.ts @@ -2,17 +2,38 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { GetPacketStatusDepends } from '@/napcat-onebot/action/packet/GetPacketStatus'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - user_id: Type.Union([Type.Number(), Type.String()]), +const PayloadSchema = Type.Object({ + user_id: Type.String({ description: 'QQ号' }), }); -type Payload = Static; +type PayloadType = Static; -export class GetUserStatus extends GetPacketStatusDepends { +const ReturnSchema = Type.Object({ + status: Type.Number({ description: '在线状态' }), + ext_status: Type.Number({ description: '扩展状态' }), +}, { description: '用户状态' }); + +type ReturnType = Static; + +export class GetUserStatus extends GetPacketStatusDepends { override actionName = ActionName.GetUserStatus; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取用户在线状态'; + override actionTags = ['系统扩展']; + override payloadExample = { + user_id: '123456789' + }; + override returnExample = { + status: 10, + ext_status: 0 + }; - async _handle (payload: Payload) { - return await this.core.apis.PacketApi.pkt.operation.GetStrangerStatus(+payload.user_id); + async _handle (payload: PayloadType) { + const res = await this.core.apis.PacketApi.pkt.operation.GetStrangerStatus(+payload.user_id); + if (!res) { + throw new Error('无法获取用户状态'); + } + return res; } } diff --git a/packages/napcat-onebot/action/extends/MoveGroupFile.ts b/packages/napcat-onebot/action/extends/MoveGroupFile.ts index 80b7ab7e..e414b0f3 100644 --- a/packages/napcat-onebot/action/extends/MoveGroupFile.ts +++ b/packages/napcat-onebot/action/extends/MoveGroupFile.ts @@ -3,24 +3,38 @@ import { FileNapCatOneBotUUID } from 'napcat-common/src/file-uuid'; import { GetPacketStatusDepends } from '@/napcat-onebot/action/packet/GetPacketStatus'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - file_id: Type.String(), - current_parent_directory: Type.String(), - target_parent_directory: Type.String(), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + file_id: Type.String({ description: '文件ID' }), + current_parent_directory: Type.String({ description: '当前父目录' }), + target_parent_directory: Type.String({ description: '目标父目录' }), }); -type Payload = Static; +type PayloadType = Static; -interface MoveGroupFileResponse { - ok: boolean; -} +const ReturnSchema = Type.Object({ + ok: Type.Boolean({ description: '是否成功' }), +}, { description: '移动文件结果' }); -export class MoveGroupFile extends GetPacketStatusDepends { +type ReturnType = Static; + +export class MoveGroupFile extends GetPacketStatusDepends { override actionName = ActionName.MoveGroupFile; - override payloadSchema = SchemaData; + override actionSummary = '移动群文件'; + override actionTags = ['文件扩展']; + override payloadExample = { + group_id: '123456', + file_id: '/file_id', + current_parent_directory: '/current_folder_id', + target_parent_directory: '/target_folder_id', + }; + override returnExample = { + ok: true + }; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { const contextMsgFile = FileNapCatOneBotUUID.decode(payload.file_id) || FileNapCatOneBotUUID.decodeModelId(payload.file_id); if (contextMsgFile?.fileUUID) { await this.core.apis.PacketApi.pkt.operation.MoveGroupFile(+payload.group_id, contextMsgFile.fileUUID, payload.current_parent_directory, payload.target_parent_directory); diff --git a/packages/napcat-onebot/action/extends/OCRImage.ts b/packages/napcat-onebot/action/extends/OCRImage.ts index ab3df90c..aef48823 100644 --- a/packages/napcat-onebot/action/extends/OCRImage.ts +++ b/packages/napcat-onebot/action/extends/OCRImage.ts @@ -3,18 +3,29 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { checkFileExist, uriToLocalFile } from 'napcat-common/src/file'; import fs from 'fs'; import { Static, Type } from '@sinclair/typebox'; -import { GeneralCallResultStatus } from 'napcat-core'; -const SchemaData = Type.Object({ - image: Type.String(), +import { ExtendsActionsExamples } from '../example/ExtendsActionsExamples'; + +const PayloadSchema = Type.Object({ + image: Type.String({ description: '图片路径、URL或Base64' }), }); -type Payload = Static; +type PayloadType = Static; -class OCRImageBase extends OneBotAction { - override payloadSchema = SchemaData; +const ReturnSchema = Type.Any({ description: 'OCR结果' }); - async _handle (payload: Payload) { +type ReturnType = Static; + +class OCRImageBase extends OneBotAction { + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '图片 OCR 识别'; + override actionDescription = '识别图片中的文字内容(仅Windows端支持)'; + override actionTags = ['扩展接口']; + override payloadExample = ExtendsActionsExamples.OCRImage.payload; + override returnExample = ExtendsActionsExamples.OCRImage.response; + + async _handle (payload: PayloadType): Promise { const { path, success } = await uriToLocalFile(this.core.NapCatTempPath, payload.image); if (!success) { throw new Error(`OCR ${payload.image}失败, image字段可能格式不正确`); @@ -37,8 +48,10 @@ class OCRImageBase extends OneBotAction { export class OCRImage extends OCRImageBase { override actionName = ActionName.OCRImage; + override actionSummary = '图片 OCR 识别'; } export class IOCRImage extends OCRImageBase { override actionName = ActionName.IOCRImage; + override actionSummary = '图片 OCR 识别 (内部)'; } diff --git a/packages/napcat-onebot/action/extends/RenameGroupFile.ts b/packages/napcat-onebot/action/extends/RenameGroupFile.ts index 44d290d9..63e859cc 100644 --- a/packages/napcat-onebot/action/extends/RenameGroupFile.ts +++ b/packages/napcat-onebot/action/extends/RenameGroupFile.ts @@ -3,24 +3,38 @@ import { FileNapCatOneBotUUID } from 'napcat-common/src/file-uuid'; import { GetPacketStatusDepends } from '@/napcat-onebot/action/packet/GetPacketStatus'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - file_id: Type.String(), - current_parent_directory: Type.String(), - new_name: Type.String(), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + file_id: Type.String({ description: '文件ID' }), + current_parent_directory: Type.String({ description: '当前父目录' }), + new_name: Type.String({ description: '新文件名' }), }); -type Payload = Static; +type PayloadType = Static; -interface RenameGroupFileResponse { - ok: boolean; -} +const ReturnSchema = Type.Object({ + ok: Type.Boolean({ description: '是否成功' }), +}, { description: '重命名文件结果' }); -export class RenameGroupFile extends GetPacketStatusDepends { +type ReturnType = Static; + +export class RenameGroupFile extends GetPacketStatusDepends { override actionName = ActionName.RenameGroupFile; - override payloadSchema = SchemaData; + override actionSummary = '重命名群文件'; + override actionTags = ['文件扩展']; + override payloadExample = { + group_id: '123456', + file_id: '/file_id', + current_parent_directory: '/', + new_name: 'new_name.jpg' + }; + override returnExample = { + ok: true + }; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { const contextMsgFile = FileNapCatOneBotUUID.decode(payload.file_id) || FileNapCatOneBotUUID.decodeModelId(payload.file_id); if (contextMsgFile?.fileUUID) { await this.core.apis.PacketApi.pkt.operation.RenameGroupFile(+payload.group_id, contextMsgFile.fileUUID, payload.current_parent_directory, payload.new_name); diff --git a/packages/napcat-onebot/action/extends/SendPacket.ts b/packages/napcat-onebot/action/extends/SendPacket.ts index 2a395ece..9f687943 100644 --- a/packages/napcat-onebot/action/extends/SendPacket.ts +++ b/packages/napcat-onebot/action/extends/SendPacket.ts @@ -3,20 +3,35 @@ import { GetPacketStatusDepends } from '@/napcat-onebot/action/packet/GetPacketS import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - cmd: Type.String(), - data: Type.String(), - rsp: Type.Union([Type.String(), Type.Boolean()], { default: true }), +const PayloadSchema = Type.Object({ + cmd: Type.String({ description: '命令字' }), + data: Type.String({ description: '十六进制数据' }), + rsp: Type.Union([Type.String(), Type.Boolean()], { default: true, description: '是否等待响应' }), }); -type Payload = Static; +type PayloadType = Static; -export class SendPacket extends GetPacketStatusDepends { - override payloadSchema = SchemaData; +const ReturnSchema = Type.Union([Type.String({ description: '响应十六进制数据' }), Type.Undefined()], { description: '发包结果' }); + +type ReturnType = Static; + +export class SendPacket extends GetPacketStatusDepends { + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; override actionName = ActionName.SendPacket; - async _handle (payload: Payload) { + override actionSummary = '发送原始数据包'; + override actionTags = ['系统扩展']; + override payloadExample = { + cmd: 'Example.Cmd', + data: '123456', + rsp: true + }; + override returnExample = '123456'; + + async _handle (payload: PayloadType) { const rsp = typeof payload.rsp === 'boolean' ? payload.rsp : payload.rsp === 'true'; - const data = await this.core.apis.PacketApi.pkt.operation.sendPacket({ cmd: payload.cmd, data: Buffer.from(payload.data, 'hex') as PacketBuf }, rsp); + const packetData = Buffer.from(payload.data, 'hex') as unknown as PacketBuf; + const data = await this.core.apis.PacketApi.pkt.operation.sendPacket({ cmd: payload.cmd, data: packetData }, rsp); return typeof data === 'object' ? data.toString('hex') : undefined; } } diff --git a/packages/napcat-onebot/action/extends/SetDiyOnlineStatus.ts b/packages/napcat-onebot/action/extends/SetDiyOnlineStatus.ts index 8ed77387..1f211c13 100644 --- a/packages/napcat-onebot/action/extends/SetDiyOnlineStatus.ts +++ b/packages/napcat-onebot/action/extends/SetDiyOnlineStatus.ts @@ -2,19 +2,31 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - face_id: Type.Union([Type.Number(), Type.String()]), // 参考 face_config.json 的 QSid - face_type: Type.Union([Type.Number(), Type.String()], { default: '1' }), - wording: Type.String({ default: ' ' }), +const PayloadSchema = Type.Object({ + face_id: Type.Union([Type.Number(), Type.String()], { description: '图标ID' }), // 参考 face_config.json 的 QSid + face_type: Type.Union([Type.Number(), Type.String()], { default: '1', description: '图标类型' }), + wording: Type.String({ default: ' ', description: '状态文字内容' }), }); -type Payload = Static; +type PayloadType = Static; -export class SetDiyOnlineStatus extends OneBotAction { +const ReturnSchema = Type.String({ description: '错误信息(如果有)' }); + +type ReturnType = Static; + +export class SetDiyOnlineStatus extends OneBotAction { override actionName = ActionName.SetDiyOnlineStatus; - override payloadSchema = SchemaData; - - async _handle (payload: Payload) { + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; override actionSummary = '设置自定义在线状态'; + override actionDescription = '设置自定义在线状态'; + override actionTags = ['用户扩展']; + override payloadExample = { + face_id: '123', + face_type: '1', + wording: '自定义状态' + }; + override returnExample = ''; + async _handle (payload: PayloadType) { const ret = await this.core.apis.UserApi.setDiySelfOnlineStatus( payload.face_id.toString(), payload.wording, diff --git a/packages/napcat-onebot/action/extends/SetGroupAddOption.ts b/packages/napcat-onebot/action/extends/SetGroupAddOption.ts index dcd275c7..fddd5ba2 100644 --- a/packages/napcat-onebot/action/extends/SetGroupAddOption.ts +++ b/packages/napcat-onebot/action/extends/SetGroupAddOption.ts @@ -2,19 +2,31 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.String(), - add_type: Type.Number(), - group_question: Type.Optional(Type.String()), - group_answer: Type.Optional(Type.String()), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + add_type: Type.Number({ description: '加群方式' }), + group_question: Type.Optional(Type.String({ description: '加群问题' })), + group_answer: Type.Optional(Type.String({ description: '加群答案' })), }); -type Payload = Static; +type PayloadType = Static; -export default class SetGroupAddOption extends OneBotAction { +const ReturnSchema = Type.Null({ description: '返回结果' }); + +type ReturnType = Static; + +export default class SetGroupAddOption extends OneBotAction { override actionName = ActionName.SetGroupAddOption; - override payloadSchema = SchemaData; - async _handle (payload: Payload): Promise { + override actionSummary = '设置群加群选项'; + override actionTags = ['群组扩展']; + override payloadExample = { + group_id: '123456', + add_type: 1, + }; + override returnExample = null; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + async _handle (payload: PayloadType): Promise { const ret = await this.core.apis.GroupApi.setGroupAddOption(payload.group_id, { addOption: payload.add_type, groupQuestion: payload.group_question, diff --git a/packages/napcat-onebot/action/extends/SetGroupAlbumMediaLike.ts b/packages/napcat-onebot/action/extends/SetGroupAlbumMediaLike.ts index 3edc245a..f60e8549 100644 --- a/packages/napcat-onebot/action/extends/SetGroupAlbumMediaLike.ts +++ b/packages/napcat-onebot/action/extends/SetGroupAlbumMediaLike.ts @@ -2,21 +2,37 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.String(), - album_id: Type.String(), - lloc: Type.String(), - id: Type.String(), // 421_1_0_1012959257|V61Yiali4PELg90bThrH4Bo2iI1M5Kab|V5bCgAxMDEyOTU5MjU3.PyqaPndPxg!^||^421_1_0_1012959257|V61Yiali4PELg90bThrH4Bo2iI1M5Kab|17560363448^||^1 - set: Type.Boolean({ default: true }), // true=点赞 false=取消点赞 未实现 +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + album_id: Type.String({ description: '相册ID' }), + lloc: Type.String({ description: '媒体ID (lloc)' }), + id: Type.String({ description: '点赞ID' }), // 421_1_0_1012959257|V61Yiali4PELg90bThrH4Bo2iI1M5Kab|V5bCgAxMDEyOTU5MjU3.PyqaPndPxg!^||^421_1_0_1012959257|V61Yiali4PELg90bThrH4Bo2iI1M5Kab|17560363448^||^1 + set: Type.Boolean({ default: true, description: '是否点赞' }), // true=点赞 false=取消点赞 未实现 }); -type Payload = Static; +type PayloadType = Static; -export class SetGroupAlbumMediaLike extends OneBotAction { +const ReturnSchema = Type.Any({ description: '操作结果' }); + +type ReturnType = Static; + +export class SetGroupAlbumMediaLike extends OneBotAction { override actionName = ActionName.SetGroupAlbumMediaLike; - override payloadSchema = SchemaData; + override actionSummary = '点赞群相册媒体'; + override actionTags = ['群组扩展']; + override payloadExample = { + group_id: '123456', + album_id: 'album_id_1', + lloc: 'media_id_1', + id: '123456', + }; + override returnExample = { + result: {} + }; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { return await this.core.apis.WebApi.doAlbumMediaLikeByNTQQ( payload.group_id, payload.album_id, diff --git a/packages/napcat-onebot/action/extends/SetGroupKickMembers.ts b/packages/napcat-onebot/action/extends/SetGroupKickMembers.ts index 8ed8f82d..158000ce 100644 --- a/packages/napcat-onebot/action/extends/SetGroupKickMembers.ts +++ b/packages/napcat-onebot/action/extends/SetGroupKickMembers.ts @@ -2,19 +2,31 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.String(), - user_id: Type.Array(Type.String()), - reject_add_request: Type.Optional(Type.Union([Type.Boolean(), Type.String()])), +import { ExtendsActionsExamples } from '../example/ExtendsActionsExamples'; + +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + user_id: Type.Array(Type.String(), { description: 'QQ号列表' }), + reject_add_request: Type.Optional(Type.Union([Type.Boolean(), Type.String()], { description: '是否拒绝加群请求' })), }); -type Payload = Static; +type PayloadType = Static; -export default class SetGroupKickMembers extends OneBotAction { +const ReturnSchema = Type.Null({ description: '返回结果' }); + +type ReturnType = Static; + +export default class SetGroupKickMembers extends OneBotAction { override actionName = ActionName.SetGroupKickMembers; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '批量踢出群成员'; + override actionDescription = '从指定群聊中批量踢出多个成员'; + override actionTags = ['扩展接口']; + override payloadExample = ExtendsActionsExamples.SetGroupKickMembers.payload; + override returnExample = ExtendsActionsExamples.SetGroupKickMembers.response; - async _handle (payload: Payload): Promise { + async _handle (payload: PayloadType): Promise { const rejectReq = payload.reject_add_request?.toString() === 'true'; const uids: string[] = await Promise.all(payload.user_id.map(async uin => await this.core.apis.UserApi.getUidByUinV2(uin))); await this.core.apis.GroupApi.kickMember(payload.group_id.toString(), uids.filter(uid => !!uid), rejectReq); diff --git a/packages/napcat-onebot/action/extends/SetGroupRemark.ts b/packages/napcat-onebot/action/extends/SetGroupRemark.ts index ff2adbc9..4c56a244 100644 --- a/packages/napcat-onebot/action/extends/SetGroupRemark.ts +++ b/packages/napcat-onebot/action/extends/SetGroupRemark.ts @@ -2,17 +2,31 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.String(), - remark: Type.String(), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + remark: Type.String({ description: '备注' }), }); -type Payload = Static; +type PayloadType = Static; -export default class SetGroupRemark extends OneBotAction { +const ReturnSchema = Type.Null({ description: '返回结果' }); + +type ReturnType = Static; + +export default class SetGroupRemark extends OneBotAction { override actionName = ActionName.SetGroupRemark; - override payloadSchema = SchemaData; - async _handle (payload: Payload): Promise { + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '设置群备注'; + override actionDescription = '设置群备注'; + override actionTags = ['群组扩展']; + override payloadExample = { + group_id: '123456', + remark: '测试群备注' + }; + override returnExample = null; + + async _handle (payload: PayloadType): Promise { const ret = await this.core.apis.GroupApi.setGroupRemark(payload.group_id, payload.remark); if (ret.result !== 0) { throw new Error(`设置群备注失败, ${ret.result}:${ret.errMsg}`); diff --git a/packages/napcat-onebot/action/extends/SetGroupRobotAddOption.ts b/packages/napcat-onebot/action/extends/SetGroupRobotAddOption.ts index 72811783..b0d56d9d 100644 --- a/packages/napcat-onebot/action/extends/SetGroupRobotAddOption.ts +++ b/packages/napcat-onebot/action/extends/SetGroupRobotAddOption.ts @@ -2,18 +2,29 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.String(), - robot_member_switch: Type.Optional(Type.Number()), - robot_member_examine: Type.Optional(Type.Number()), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + robot_member_switch: Type.Optional(Type.Number({ description: '机器人成员开关' })), + robot_member_examine: Type.Optional(Type.Number({ description: '机器人成员审核' })), }); -type Payload = Static; +type PayloadType = Static; -export default class SetGroupRobotAddOption extends OneBotAction { +const ReturnSchema = Type.Null({ description: '返回结果' }); + +type ReturnType = Static; + +export default class SetGroupRobotAddOption extends OneBotAction { override actionName = ActionName.SetGroupRobotAddOption; - override payloadSchema = SchemaData; - async _handle (payload: Payload): Promise { + override actionSummary = '设置群机器人加群选项'; + override actionTags = ['群组扩展']; + override payloadExample = { + group_id: '123456' + }; + override returnExample = null; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + async _handle (payload: PayloadType): Promise { const ret = await this.core.apis.GroupApi.setGroupRobotAddOption( payload.group_id, payload.robot_member_switch, diff --git a/packages/napcat-onebot/action/extends/SetGroupSearch.ts b/packages/napcat-onebot/action/extends/SetGroupSearch.ts index 9ce5ff6d..c63d8339 100644 --- a/packages/napcat-onebot/action/extends/SetGroupSearch.ts +++ b/packages/napcat-onebot/action/extends/SetGroupSearch.ts @@ -2,18 +2,29 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.String(), - no_code_finger_open: Type.Optional(Type.Number()), - no_finger_open: Type.Optional(Type.Number()), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + no_code_finger_open: Type.Optional(Type.Number({ description: '未知' })), + no_finger_open: Type.Optional(Type.Number({ description: '未知' })), }); -type Payload = Static; +type PayloadType = Static; -export default class SetGroupSearch extends OneBotAction { +const ReturnSchema = Type.Null({ description: '返回结果' }); + +type ReturnType = Static; + +export default class SetGroupSearch extends OneBotAction { override actionName = ActionName.SetGroupSearch; - override payloadSchema = SchemaData; - async _handle (payload: Payload): Promise { + override actionSummary = '设置群搜索选项'; + override actionTags = ['群组扩展']; + override payloadExample = { + group_id: '123456' + }; + override returnExample = null; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + async _handle (payload: PayloadType): Promise { const ret = await this.core.apis.GroupApi.setGroupSearch(payload.group_id, { noCodeFingerOpenFlag: payload.no_code_finger_open, noFingerOpenFlag: payload.no_finger_open, diff --git a/packages/napcat-onebot/action/extends/SetGroupSign.ts b/packages/napcat-onebot/action/extends/SetGroupSign.ts index e8739ed5..9769964e 100644 --- a/packages/napcat-onebot/action/extends/SetGroupSign.ts +++ b/packages/napcat-onebot/action/extends/SetGroupSign.ts @@ -2,16 +2,27 @@ import { GetPacketStatusDepends } from '@/napcat-onebot/action/packet/GetPacketS import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), }); -type Payload = Static; +type PayloadType = Static; -class SetGroupSignBase extends GetPacketStatusDepends { - override payloadSchema = SchemaData; +const ReturnSchema = Type.Void({ description: '打卡结果' }); - async _handle (payload: Payload) { +type ReturnType = Static; + +class SetGroupSignBase extends GetPacketStatusDepends { + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '群打卡'; + override actionTags = ['群组扩展']; + override payloadExample = { + group_id: '123456789' + }; + override returnExample = null; + + async _handle (payload: PayloadType) { return await this.core.apis.PacketApi.pkt.operation.GroupSign(+payload.group_id); } } diff --git a/packages/napcat-onebot/action/extends/SetInputStatus.ts b/packages/napcat-onebot/action/extends/SetInputStatus.ts index d66224cd..89a49f27 100644 --- a/packages/napcat-onebot/action/extends/SetInputStatus.ts +++ b/packages/napcat-onebot/action/extends/SetInputStatus.ts @@ -3,17 +3,30 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { ChatType } from 'napcat-core'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - user_id: Type.Union([Type.Number(), Type.String()]), - event_type: Type.Number(), +const PayloadSchema = Type.Object({ + user_id: Type.String({ description: 'QQ号' }), + event_type: Type.Number({ description: '事件类型' }), }); -type Payload = Static; +type PayloadType = Static; -export class SetInputStatus extends OneBotAction { +const ReturnSchema = Type.Any({ description: '设置结果' }); + +type ReturnType = Static; + +export class SetInputStatus extends OneBotAction { override actionName = ActionName.SetInputStatus; - override payloadSchema = SchemaData; - async _handle (payload: Payload) { + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '设置输入状态'; + override actionTags = ['系统扩展']; + override payloadExample = { + user_id: '123456789', + event_type: 1 + }; + override returnExample = null; + + async _handle (payload: PayloadType) { const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString()); if (!uid) throw new Error('uid is empty'); const peer = { diff --git a/packages/napcat-onebot/action/extends/SetLongNick.ts b/packages/napcat-onebot/action/extends/SetLongNick.ts index 64868a21..3873273b 100644 --- a/packages/napcat-onebot/action/extends/SetLongNick.ts +++ b/packages/napcat-onebot/action/extends/SetLongNick.ts @@ -2,17 +2,29 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - longNick: Type.String(), +import { ExtendsActionsExamples } from '../example/ExtendsActionsExamples'; + +const PayloadSchema = Type.Object({ + longNick: Type.String({ description: '签名内容' }), }); -type Payload = Static; +type PayloadType = Static; -export class SetLongNick extends OneBotAction { +const ReturnSchema = Type.Any({ description: '设置结果' }); + +type ReturnType = Static; + +export class SetLongNick extends OneBotAction { override actionName = ActionName.SetLongNick; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '设置个性签名'; + override actionDescription = '修改当前登录帐号的个性签名'; + override actionTags = ['扩展接口']; + override payloadExample = ExtendsActionsExamples.SetLongNick.payload; + override returnExample = ExtendsActionsExamples.SetLongNick.response; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { return await this.core.apis.UserApi.setLongNick(payload.longNick); } } diff --git a/packages/napcat-onebot/action/extends/SetOnlineStatus.ts b/packages/napcat-onebot/action/extends/SetOnlineStatus.ts index b54ed3d1..1d0dddaf 100644 --- a/packages/napcat-onebot/action/extends/SetOnlineStatus.ts +++ b/packages/napcat-onebot/action/extends/SetOnlineStatus.ts @@ -2,19 +2,33 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - status: Type.Union([Type.Number(), Type.String()]), - ext_status: Type.Union([Type.Number(), Type.String()]), - battery_status: Type.Union([Type.Number(), Type.String()]), +const PayloadSchema = Type.Object({ + status: Type.Union([Type.Number(), Type.String()], { description: '在线状态' }), + ext_status: Type.Union([Type.Number(), Type.String()], { description: '扩展状态' }), + battery_status: Type.Union([Type.Number(), Type.String()], { description: '电量状态' }), }); -type Payload = Static; +type PayloadType = Static; -export class SetOnlineStatus extends OneBotAction { +const ReturnSchema = Type.Null({ description: '设置结果' }); + +type ReturnType = Static; + +export class SetOnlineStatus extends OneBotAction { override actionName = ActionName.SetOnlineStatus; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '设置在线状态'; + override actionDescription = statusText; + override actionTags = ['系统扩展']; + override payloadExample = { + status: 11, + ext_status: 0, + battery_status: 100 + }; + override returnExample = null; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { const ret = await this.core.apis.UserApi.setSelfOnlineStatus( +payload.status, +payload.ext_status, @@ -26,3 +40,216 @@ export class SetOnlineStatus extends OneBotAction { return null; } } + +const statusText = ` +## 状态列表 + +### 在线 +\`\`\`json5; +{ "status": 10, "ext_status": 0, "battery_status": 0; } +\`\`\` + +### Q我吧 +\`\`\`json5; +{ "status": 60, "ext_status": 0, "battery_status": 0; } +\`\`\` + +### 离开 +\`\`\`json5; +{ "status": 30, "ext_status": 0, "battery_status": 0; } +\`\`\` + +### 忙碌 +\`\`\`json5; +{ "status": 50, "ext_status": 0, "battery_status": 0; } +\`\`\` + +### 请勿打扰 +\`\`\`json5; +{ "status": 70, "ext_status": 0, "battery_status": 0; } +\`\`\` + +### 隐身 +\`\`\`json5; +{ "status": 40, "ext_status": 0, "battery_status": 0; } +\`\`\` + +### 听歌中 +\`\`\`json5; +{ "status": 10, "ext_status": 1028, "battery_status": 0; } +\`\`\` + +### 春日限定 +\`\`\`json5; +{ "status": 10, "ext_status": 2037, "battery_status": 0; } +\`\`\` + +### 一起元梦 +\`\`\`json5; +{ "status": 10, "ext_status": 2025, "battery_status": 0; } +\`\`\` + +### 求星搭子 +\`\`\`json5; +{ "status": 10, "ext_status": 2026, "battery_status": 0; } +\`\`\` + +### 被掏空 +\`\`\`json5; +{ "status": 10, "ext_status": 2014, "battery_status": 0; } +\`\`\` + +### 今日天气 +\`\`\`json5; +{ "status": 10, "ext_status": 1030, "battery_status": 0; } +\`\`\` + +### 我crash了 +\`\`\`json5; +{ "status": 10, "ext_status": 2019, "battery_status": 0; } +\`\`\` + +### 爱你 +\`\`\`json5; +{ "status": 10, "ext_status": 2006, "battery_status": 0; } +\`\`\` + +### 恋爱中 +\`\`\`json5; +{ "status": 10, "ext_status": 1051, "battery_status": 0; } +\`\`\` + +### 好运锦鲤 +\`\`\`json5; +{ "status": 10, "ext_status": 1071, "battery_status": 0; } +\`\`\` + +### 水逆退散 +\`\`\`json5; +{ "status": 10, "ext_status": 1201, "battery_status": 0; } +\`\`\` + +### 嗨到飞起 +\`\`\`json5; +{ "status": 10, "ext_status": 1056, "battery_status": 0; } +\`\`\` + +### 元气满满 +\`\`\`json5; +{ "status": 10, "ext_status": 1058, "battery_status": 0; } +\`\`\` + +### 宝宝认证 +\`\`\`json5; +{ "status": 10, "ext_status": 1070, "battery_status": 0; } +\`\`\` + +### 一言难尽 +\`\`\`json5; +{ "status": 10, "ext_status": 1063, "battery_status": 0; } +\`\`\` + +### 难得糊涂 +\`\`\`json5; +{ "status": 10, "ext_status": 2001, "battery_status": 0; } +\`\`\` + +### emo中 +\`\`\`json5; +{ "status": 10, "ext_status": 1401, "battery_status": 0; } +\`\`\` + +### 我太难了 +\`\`\`json5; +{ "status": 10, "ext_status": 1062, "battery_status": 0; } +\`\`\` + +### 我想开了 +\`\`\`json5; +{ "status": 10, "ext_status": 2013, "battery_status": 0; } +\`\`\` + +### 我没事 +\`\`\`json5; +{ "status": 10, "ext_status": 1052, "battery_status": 0; } +\`\`\` + +### 想静静 +\`\`\`json5; +{ "status": 10, "ext_status": 1061, "battery_status": 0; } +\`\`\` + +### 悠哉哉 +\`\`\`json5; +{ "status": 10, "ext_status": 1059, "battery_status": 0; } +\`\`\` + +### 去旅行 +\`\`\`json5; +{ "status": 10, "ext_status": 2015, "battery_status": 0; } +\`\`\` + +### 信号弱 +\`\`\`json5; +{ "status": 10, "ext_status": 1011, "battery_status": 0; } +\`\`\` + +### 出去浪 +\`\`\`json5; +{ "status": 10, "ext_status": 2003, "battery_status": 0; } +\`\`\` + +### 肝作业 +\`\`\`json5; +{ "status": 10, "ext_status": 2012, "battery_status": 0; } +\`\`\` + +### 学习中 +\`\`\`json5; +{ "status": 10, "ext_status": 1018, "battery_status": 0; } +\`\`\` + +### 搬砖中 +\`\`\`json5; +{ "status": 10, "ext_status": 2023, "battery_status": 0; } +\`\`\` + +### 摸鱼中 +\`\`\`json5; +{ "status": 10, "ext_status": 1300, "battery_status": 0; } +\`\`\` + +### 无聊中 +\`\`\`json5; +{ "status": 10, "ext_status": 1060, "battery_status": 0; } +\`\`\` + +### timi中 +\`\`\`json5; +{ "status": 10, "ext_status": 1027, "battery_status": 0; } +\`\`\` + +### 睡觉中 +\`\`\`json5; +{ "status": 10, "ext_status": 1016, "battery_status": 0; } +\`\`\` + +### 熬夜中 +\`\`\`json5; +{ "status": 10, "ext_status": 1032, "battery_status": 0; } +\`\`\` + +### 追剧中 +\`\`\`json5; +{ "status": 10, "ext_status": 1021, "battery_status": 0; } +\`\`\` + +### 我的电量 +\`\`\`json5; +{ + "status": 10, + "ext_status": 1000, + "battery_status": 0; +} +\`\`\` +`; \ No newline at end of file diff --git a/packages/napcat-onebot/action/extends/SetQQAvatar.ts b/packages/napcat-onebot/action/extends/SetQQAvatar.ts index f33909f1..25cb197e 100644 --- a/packages/napcat-onebot/action/extends/SetQQAvatar.ts +++ b/packages/napcat-onebot/action/extends/SetQQAvatar.ts @@ -4,16 +4,29 @@ import fs from 'node:fs/promises'; import { checkFileExist, uriToLocalFile } from 'napcat-common/src/file'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - file: Type.String(), +import { ExtendsActionsExamples } from '../example/ExtendsActionsExamples'; + +const PayloadSchema = Type.Object({ + file: Type.String({ description: '图片路径、URL或Base64' }), }); -type Payload = Static; +type PayloadType = Static; -export default class SetAvatar extends OneBotAction { +const ReturnSchema = Type.Null({ description: '设置结果' }); + +type ReturnType = Static; + +export default class SetAvatar extends OneBotAction { override actionName = ActionName.SetQQAvatar; - override payloadSchema = SchemaData; - async _handle (payload: Payload): Promise { + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '设置QQ头像'; + override actionDescription = '修改当前账号的QQ头像'; + override actionTags = ['扩展接口']; + override payloadExample = ExtendsActionsExamples.SetQQAvatar.payload; + override returnExample = ExtendsActionsExamples.SetQQAvatar.response; + + async _handle (payload: PayloadType): Promise { const { path, success } = (await uriToLocalFile(this.core.NapCatTempPath, payload.file)); if (!success) { throw new Error(`头像${payload.file}设置失败,file字段可能格式不正确`); @@ -26,7 +39,7 @@ export default class SetAvatar extends OneBotAction { throw new Error(`头像${payload.file}设置失败,api无返回`); } // log(`头像设置返回:${JSON.stringify(ret)}`) - if (ret.result as number === 1004022) { + if (Number(ret.result) === 1004022) { throw new Error(`头像${payload.file}设置失败,文件可能不是图片格式`); } else if (ret.result !== 0) { throw new Error(`头像${payload.file}设置失败,未知的错误,${ret.result}:${ret.errMsg}`); diff --git a/packages/napcat-onebot/action/extends/SetSpecialTitle.ts b/packages/napcat-onebot/action/extends/SetSpecialTitle.ts index 06914edb..f5b9783a 100644 --- a/packages/napcat-onebot/action/extends/SetSpecialTitle.ts +++ b/packages/napcat-onebot/action/extends/SetSpecialTitle.ts @@ -2,19 +2,31 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { GetPacketStatusDepends } from '@/napcat-onebot/action/packet/GetPacketStatus'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - user_id: Type.Union([Type.Number(), Type.String()]), - special_title: Type.String({ default: '' }), +import { ExtendsActionsExamples } from '../example/ExtendsActionsExamples'; + +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + user_id: Type.String({ description: 'QQ号' }), + special_title: Type.String({ default: '', description: '专属头衔' }), }); -type Payload = Static; +type PayloadType = Static; -export class SetSpecialTitle extends GetPacketStatusDepends { +const ReturnSchema = Type.Void({ description: '设置结果' }); + +type ReturnType = Static; + +export class SetSpecialTitle extends GetPacketStatusDepends { override actionName = ActionName.SetSpecialTitle; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '设置专属头衔'; + override actionDescription = '设置群聊中指定成员的专属头衔'; + override actionTags = ['扩展接口']; + override payloadExample = ExtendsActionsExamples.SetSpecialTitle.payload; + override returnExample = ExtendsActionsExamples.SetSpecialTitle.response; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString()); if (!uid) throw new Error('User not found'); await this.core.apis.PacketApi.pkt.operation.SetGroupSpecialTitle(+payload.group_id, uid, payload.special_title); diff --git a/packages/napcat-onebot/action/extends/ShareContact.ts b/packages/napcat-onebot/action/extends/ShareContact.ts index 63d60a67..31ed0df5 100644 --- a/packages/napcat-onebot/action/extends/ShareContact.ts +++ b/packages/napcat-onebot/action/extends/ShareContact.ts @@ -1,24 +1,35 @@ -import { GeneralCallResult } from 'napcat-core'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - user_id: Type.Optional(Type.Union([Type.Number(), Type.String()])), - group_id: Type.Optional(Type.Union([Type.Number(), Type.String()])), - phone_number: Type.String({ default: '' }), +const PayloadSchema = Type.Object({ + user_id: Type.Optional(Type.String({ description: 'QQ号' })), + group_id: Type.Optional(Type.String({ description: '群号' })), + phone_number: Type.String({ default: '', description: '手机号' }), }); -type Payload = Static; +type PayloadType = Static; -export class SharePeerBase extends OneBotAction { +const ReturnSchema = Type.Any({ description: '分享结果' }); - override payloadSchema = SchemaData; +type ReturnType = Static; - async _handle (payload: Payload) { +export class SharePeerBase extends OneBotAction { + + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '分享用户 (Ark)'; + override actionDescription = '获取用户推荐的 Ark 内容'; + override actionTags = ['消息扩展']; + override payloadExample = { + user_id: '123456', + phone_number: '' + }; + override returnExample = { + ark: '...' + }; + + async _handle (payload: PayloadType) { if (payload.group_id) { return await this.core.apis.GroupApi.getGroupRecommendContactArkJson(payload.group_id.toString()); } else if (payload.user_id) { @@ -28,18 +39,30 @@ export class SharePeerBase extends OneBotAction; +type PayloadTypeGroupEx = Static; -export class ShareGroupExBase extends OneBotAction { - override payloadSchema = SchemaDataGroupEx; +const ReturnSchemaGroupEx = Type.String({ description: 'Ark Json内容' }); - async _handle (payload: PayloadGroupEx) { +type ReturnTypeGroupEx = Static; + +export class ShareGroupExBase extends OneBotAction { + override payloadSchema = PayloadSchemaGroupEx; + override returnSchema = ReturnSchemaGroupEx; + override actionSummary = '分享群 (Ark)'; + override actionDescription = '获取群分享的 Ark 内容'; + override actionTags = ['消息扩展']; + override payloadExample = { + group_id: '123456' + }; + override returnExample = '{"app": "com.tencent.structmsg", ...}'; + + async _handle (payload: PayloadTypeGroupEx) { return await this.core.apis.GroupApi.getArkJsonGroupShare(payload.group_id.toString()); } } diff --git a/packages/napcat-onebot/action/extends/TransGroupFile.ts b/packages/napcat-onebot/action/extends/TransGroupFile.ts index a5e42177..222a1fdc 100644 --- a/packages/napcat-onebot/action/extends/TransGroupFile.ts +++ b/packages/napcat-onebot/action/extends/TransGroupFile.ts @@ -3,22 +3,34 @@ import { FileNapCatOneBotUUID } from 'napcat-common/src/file-uuid'; import { GetPacketStatusDepends } from '@/napcat-onebot/action/packet/GetPacketStatus'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - file_id: Type.String(), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + file_id: Type.String({ description: '文件ID' }), }); -type Payload = Static; +type PayloadType = Static; -interface TransGroupFileResponse { - ok: boolean; -} +const ReturnSchema = Type.Object({ + ok: Type.Boolean({ description: '是否成功' }), +}, { description: '转发文件结果' }); -export class TransGroupFile extends GetPacketStatusDepends { +type ReturnType = Static; + +export class TransGroupFile extends GetPacketStatusDepends { override actionName = ActionName.TransGroupFile; - override payloadSchema = SchemaData; + override actionSummary = '传输群文件'; + override actionTags = ['文件扩展']; + override payloadExample = { + group_id: '123456', + file_id: '/file_id' + }; + override returnExample = { + ok: true + }; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { const contextMsgFile = FileNapCatOneBotUUID.decode(payload.file_id) || FileNapCatOneBotUUID.decodeModelId(payload.file_id); if (contextMsgFile?.fileUUID) { const result = await this.core.apis.GroupApi.transGroupFile(payload.group_id.toString(), contextMsgFile.fileUUID); diff --git a/packages/napcat-onebot/action/extends/TranslateEnWordToZn.ts b/packages/napcat-onebot/action/extends/TranslateEnWordToZn.ts index 31f1ae5a..0c48e6cb 100644 --- a/packages/napcat-onebot/action/extends/TranslateEnWordToZn.ts +++ b/packages/napcat-onebot/action/extends/TranslateEnWordToZn.ts @@ -2,21 +2,37 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - words: Type.Array(Type.String()), +import { ExtendsActionsExamples } from '../example/ExtendsActionsExamples'; + +const PayloadSchema = Type.Object({ + words: Type.Array(Type.String(), { description: '待翻译单词列表' }), }); -type Payload = Static; +type PayloadType = Static; -export class TranslateEnWordToZn extends OneBotAction | null> { +const ReturnSchema = Type.Object({ + words: Type.Array(Type.String(), { description: '翻译结果列表' }), +}, { description: '翻译结果' }); + +type ReturnType = Static; + +export class TranslateEnWordToZn extends OneBotAction { override actionName = ActionName.TranslateEnWordToZn; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '英文单词翻译'; + override actionDescription = '将英文单词列表翻译为中文'; + override actionTags = ['扩展接口']; + override payloadExample = ExtendsActionsExamples.TranslateEnWordToZn.payload; + override returnExample = ExtendsActionsExamples.TranslateEnWordToZn.response; - async _handle (payload: Payload) { + async _handle (payload: PayloadType): Promise { const ret = await this.core.apis.SystemApi.translateEnWordToZn(payload.words); if (ret.result !== 0) { throw new Error('翻译失败'); } - return ret.words; + return { + words: ret.words + }; } } diff --git a/packages/napcat-onebot/action/extends/UploadImageToQunAlbum.ts b/packages/napcat-onebot/action/extends/UploadImageToQunAlbum.ts index b1e16738..486acd5b 100644 --- a/packages/napcat-onebot/action/extends/UploadImageToQunAlbum.ts +++ b/packages/napcat-onebot/action/extends/UploadImageToQunAlbum.ts @@ -5,20 +5,36 @@ import { Static, Type } from '@sinclair/typebox'; import { existsSync } from 'node:fs'; import { unlink } from 'node:fs/promises'; -const SchemaData = Type.Object({ - group_id: Type.String(), - album_id: Type.String(), - album_name: Type.String(), - file: Type.String(), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + album_id: Type.String({ description: '相册ID' }), + album_name: Type.String({ description: '相册名称' }), + file: Type.String({ description: '图片路径、URL或Base64' }), }); -type Payload = Static; +type PayloadType = Static; -export class UploadImageToQunAlbum extends OneBotAction { +const ReturnSchema = Type.Any({ description: '上传结果' }); + +type ReturnType = Static; + +export class UploadImageToQunAlbum extends OneBotAction { override actionName = ActionName.UploadImageToQunAlbum; - override payloadSchema = SchemaData; + override actionSummary = '上传图片到群相册'; + override actionTags = ['群组扩展']; + override payloadExample = { + group_id: '123456', + album_id: 'album_id_1', + album_name: '相册1', + file: '/path/to/image.jpg' + }; + override returnExample = { + result: null + }; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { const downloadResult = await uriToLocalFile(this.core.NapCatTempPath, payload.file); try { return await this.core.apis.WebApi.uploadImageToQunAlbum(payload.group_id, payload.album_id, payload.album_name, downloadResult.path); diff --git a/packages/napcat-onebot/action/file/GetFile.ts b/packages/napcat-onebot/action/file/GetFile.ts index a7ffa2b0..518a7ad2 100644 --- a/packages/napcat-onebot/action/file/GetFile.ts +++ b/packages/napcat-onebot/action/file/GetFile.ts @@ -5,23 +5,29 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { OB11MessageImage, OB11MessageVideo } from '@/napcat-onebot/types'; import { Static, Type } from '@sinclair/typebox'; -export interface GetFileResponse { - file?: string; // path - url?: string; - file_size?: string; - file_name?: string; - base64?: string; -} +import { FileActionsExamples } from '../example/FileActionsExamples'; -const GetFileBase_PayloadSchema = Type.Object({ - file: Type.Optional(Type.String()), - file_id: Type.Optional(Type.String()), +export const GetFilePayloadSchema = Type.Object({ + file: Type.Optional(Type.String({ description: '文件路径、URL或Base64' })), + file_id: Type.Optional(Type.String({ description: '文件ID' })), }); -export type GetFilePayload = Static; +export type GetFilePayload = Static; + +export const GetFileReturnSchema = Type.Object({ + file: Type.Optional(Type.String({ description: '本地路径' })), + url: Type.Optional(Type.String({ description: '下载URL' })), + file_size: Type.Optional(Type.String({ description: '文件大小' })), + file_name: Type.Optional(Type.String({ description: '文件名' })), + base64: Type.Optional(Type.String({ description: 'Base64编码' })), +}, { description: '文件信息' }); + +export type GetFileResponse = Static; export class GetFileBase extends OneBotAction { - override payloadSchema = GetFileBase_PayloadSchema; + override payloadSchema = GetFilePayloadSchema; + override returnSchema = GetFileReturnSchema; + override actionTags = ['文件接口']; async _handle (payload: GetFilePayload): Promise { payload.file ||= payload.file_id || ''; @@ -40,12 +46,12 @@ export class GetFileBase extends OneBotAction { let url = ''; if (mixElement?.picElement && rawMessage) { const tempData = - await this.obContext.apis.MsgApi.rawToOb11Converters.picElement?.(mixElement?.picElement, rawMessage, mixElement, { parseMultMsg: false, disableGetUrl: false, quick_reply: true }) as OB11MessageImage | undefined; + await this.obContext.apis.MsgApi.rawToOb11Converters.picElement?.(mixElement?.picElement, rawMessage, mixElement, { parseMultMsg: false, disableGetUrl: false, quick_reply: true }) as OB11MessageImage | undefined; url = tempData?.data.url ?? ''; } if (mixElement?.videoElement && rawMessage) { const tempData = - await this.obContext.apis.MsgApi.rawToOb11Converters.videoElement?.(mixElement?.videoElement, rawMessage, mixElement, { parseMultMsg: false, disableGetUrl: false, quick_reply: true }) as OB11MessageVideo | undefined; + await this.obContext.apis.MsgApi.rawToOb11Converters.videoElement?.(mixElement?.videoElement, rawMessage, mixElement, { parseMultMsg: false, disableGetUrl: false, quick_reply: true }) as OB11MessageVideo | undefined; url = tempData?.data.url ?? ''; } const res: GetFileResponse = { @@ -113,4 +119,9 @@ export class GetFileBase extends OneBotAction { export default class GetFile extends GetFileBase { override actionName = ActionName.GetFile; + override actionSummary = '获取文件'; + override actionDescription = '获取指定文件的详细信息及下载路径'; + override actionTags = ['文件接口']; + override payloadExample = FileActionsExamples.GetFile.payload; + override returnExample = FileActionsExamples.GetFile.response; } diff --git a/packages/napcat-onebot/action/file/GetGroupFileUrl.ts b/packages/napcat-onebot/action/file/GetGroupFileUrl.ts index e141167d..2fadb0f2 100644 --- a/packages/napcat-onebot/action/file/GetGroupFileUrl.ts +++ b/packages/napcat-onebot/action/file/GetGroupFileUrl.ts @@ -3,22 +3,32 @@ import { FileNapCatOneBotUUID } from 'napcat-common/src/file-uuid'; import { GetPacketStatusDepends } from '@/napcat-onebot/action/packet/GetPacketStatus'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - file_id: Type.String(), +import { FileActionsExamples } from '../example/FileActionsExamples'; + +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + file_id: Type.String({ description: '文件ID' }), }); -type Payload = Static; +type PayloadType = Static; -interface GetGroupFileUrlResponse { - url?: string; -} +const ReturnSchema = Type.Object({ + url: Type.Optional(Type.String({ description: '文件下载链接' })), +}, { description: '群文件URL信息' }); -export class GetGroupFileUrl extends GetPacketStatusDepends { +type ReturnType = Static; + +export class GetGroupFileUrl extends GetPacketStatusDepends { override actionName = ActionName.GOCQHTTP_GetGroupFileUrl; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取群文件URL'; + override actionDescription = '获取指定群文件的下载链接'; + override actionTags = ['文件接口']; + override payloadExample = FileActionsExamples.GetGroupFileUrl.payload; + override returnExample = FileActionsExamples.GetGroupFileUrl.response; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { const contextMsgFile = FileNapCatOneBotUUID.decode(payload.file_id) || FileNapCatOneBotUUID.decodeModelId(payload.file_id); if (contextMsgFile?.fileUUID) { return { diff --git a/packages/napcat-onebot/action/file/GetImage.ts b/packages/napcat-onebot/action/file/GetImage.ts index 23158f3f..dbf75a15 100644 --- a/packages/napcat-onebot/action/file/GetImage.ts +++ b/packages/napcat-onebot/action/file/GetImage.ts @@ -1,6 +1,13 @@ import { GetFileBase } from './GetFile'; import { ActionName } from '@/napcat-onebot/action/router'; +import { FileActionsExamples } from '../example/FileActionsExamples'; + export default class GetImage extends GetFileBase { override actionName = ActionName.GetImage; + override actionSummary = '获取图片'; + override actionDescription = '获取指定图片的信息及路径'; + override actionTags = ['文件接口']; + override payloadExample = FileActionsExamples.GetImage.payload; + override returnExample = FileActionsExamples.GetImage.response; } diff --git a/packages/napcat-onebot/action/file/GetPrivateFileUrl.ts b/packages/napcat-onebot/action/file/GetPrivateFileUrl.ts index 34ebe6da..7390ef76 100644 --- a/packages/napcat-onebot/action/file/GetPrivateFileUrl.ts +++ b/packages/napcat-onebot/action/file/GetPrivateFileUrl.ts @@ -3,21 +3,31 @@ import { FileNapCatOneBotUUID } from 'napcat-common/src/file-uuid'; import { GetPacketStatusDepends } from '@/napcat-onebot/action/packet/GetPacketStatus'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - file_id: Type.String(), +import { FileActionsExamples } from '../example/FileActionsExamples'; + +const PayloadSchema = Type.Object({ + file_id: Type.String({ description: '文件ID' }), }); -type Payload = Static; +type PayloadType = Static; -interface GetPrivateFileUrlResponse { - url?: string; -} +const ReturnSchema = Type.Object({ + url: Type.Optional(Type.String({ description: '文件下载链接' })), +}, { description: '私聊文件URL信息' }); -export class GetPrivateFileUrl extends GetPacketStatusDepends { +type ReturnType = Static; + +export class GetPrivateFileUrl extends GetPacketStatusDepends { override actionName = ActionName.NapCat_GetPrivateFileUrl; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取私聊文件URL'; + override actionDescription = '获取指定私聊文件的下载链接'; + override actionTags = ['文件接口']; + override payloadExample = FileActionsExamples.GetPrivateFileUrl.payload; + override returnExample = FileActionsExamples.GetPrivateFileUrl.response; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { const contextMsgFile = FileNapCatOneBotUUID.decode(payload.file_id); if (contextMsgFile?.fileUUID && contextMsgFile.msgId) { diff --git a/packages/napcat-onebot/action/file/GetRecord.ts b/packages/napcat-onebot/action/file/GetRecord.ts index b444f44f..f1976e13 100644 --- a/packages/napcat-onebot/action/file/GetRecord.ts +++ b/packages/napcat-onebot/action/file/GetRecord.ts @@ -2,22 +2,35 @@ import { GetFileBase, GetFilePayload, GetFileResponse } from './GetFile'; import { ActionName } from '@/napcat-onebot/action/router'; import { promises as fs } from 'fs'; import { FFmpegService } from '@/napcat-core/helper/ffmpeg/ffmpeg'; +import { Static, Type } from '@sinclair/typebox'; -const out_format = ['mp3', 'amr', 'wma', 'm4a', 'spx', 'ogg', 'wav', 'flac']; +import { FileActionsExamples } from '../example/FileActionsExamples'; -type Payload = { - out_format: string; -} & GetFilePayload; +const out_format_list = ['mp3', 'amr', 'wma', 'm4a', 'spx', 'ogg', 'wav', 'flac']; + +const PayloadSchema = Type.Object({ + file: Type.Optional(Type.String({ description: '文件路径、URL或Base64' })), + file_id: Type.Optional(Type.String({ description: '文件ID' })), + out_format: Type.String({ description: '输出格式' }), +}); + +type PayloadType = Static; export default class GetRecord extends GetFileBase { override actionName = ActionName.GetRecord; + override payloadSchema = PayloadSchema; + override actionSummary = '获取语音'; + override actionDescription = '获取指定语音文件的信息,并支持格式转换'; + override actionTags = ['文件接口']; + override payloadExample = FileActionsExamples.GetRecord.payload; + override returnExample = FileActionsExamples.GetRecord.response; - override async _handle (payload: Payload): Promise { - const res = await super._handle(payload); + override async _handle (payload: PayloadType): Promise { + const res = await super._handle(payload as GetFilePayload); if (payload.out_format && typeof payload.out_format === 'string') { const inputFile = res.file; if (!inputFile) throw new Error('file not found'); - if (!out_format.includes(payload.out_format)) { + if (!out_format_list.includes(payload.out_format)) { throw new Error('转换失败 out_format 字段可能格式不正确'); } const outputFile = `${inputFile}.${payload.out_format}`; diff --git a/packages/napcat-onebot/action/file/flash/CreateFlashTask.ts b/packages/napcat-onebot/action/file/flash/CreateFlashTask.ts index 32ba1347..a1270a9e 100644 --- a/packages/napcat-onebot/action/file/flash/CreateFlashTask.ts +++ b/packages/napcat-onebot/action/file/flash/CreateFlashTask.ts @@ -1,6 +1,6 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; -import { Static, Type, Optional } from '@sinclair/typebox'; +import { Static, Type } from '@sinclair/typebox'; import path from 'node:path'; const richMediaList = [ @@ -8,22 +8,31 @@ const richMediaList = [ '.png', '.gif', '.jpg', '.jpeg', '.webp', '.bmp', ]; -// 不全部使用json因为:一个文件解析Form-data会变字符串!!! 但是api文档就写List -const SchemaData = Type.Object({ +export const CreateFlashTaskPayloadSchema = Type.Object({ files: Type.Union([ Type.Array(Type.String()), Type.String(), - ]), - name: Optional(Type.String()), - thumb_path: Optional(Type.String()), + ], { description: '文件列表或单个文件路径' }), + name: Type.Optional(Type.String({ description: '任务名称' })), + thumb_path: Type.Optional(Type.String({ description: '缩略图路径' })), }); -type Payload = Static; +export type CreateFlashTaskPayload = Static; -export class CreateFlashTask extends OneBotAction { +export class CreateFlashTask extends OneBotAction { override actionName = ActionName.CreateFlashTask; - override payloadSchema = SchemaData; + override payloadSchema = CreateFlashTaskPayloadSchema; + override returnSchema = Type.Any({ description: '任务创建结果' }); + override actionSummary = '创建闪照任务'; + override actionTags = ['文件扩展']; + override payloadExample = { + files: 'C:\\test.jpg', + name: 'test_task' + }; + override returnExample = { + task_id: 'task_123' + }; - async _handle (payload: Payload) { + async _handle (payload: CreateFlashTaskPayload) { const fileList = Array.isArray(payload.files) ? payload.files : [payload.files]; let thumbPath: string = ''; diff --git a/packages/napcat-onebot/action/file/flash/DownloadFileset.ts b/packages/napcat-onebot/action/file/flash/DownloadFileset.ts index 0cb84c9f..6c770e77 100644 --- a/packages/napcat-onebot/action/file/flash/DownloadFileset.ts +++ b/packages/napcat-onebot/action/file/flash/DownloadFileset.ts @@ -2,17 +2,24 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - fileset_id: Type.String(), +export const DownloadFilesetPayloadSchema = Type.Object({ + fileset_id: Type.String({ description: '文件集 ID' }), }); -type Payload = Static; +export type DownloadFilesetPayload = Static; -export class DownloadFileset extends OneBotAction { +export class DownloadFileset extends OneBotAction { override actionName = ActionName.DownloadFileset; - override payloadSchema = SchemaData; + override payloadSchema = DownloadFilesetPayloadSchema; + override returnSchema = Type.Any({ description: '下载结果' }); + override actionSummary = '下载文件集'; + override actionTags = ['文件扩展']; + override payloadExample = { + fileset_id: 'set_123' + }; + override returnExample = null; - async _handle (payload: Payload) { + async _handle (payload: DownloadFilesetPayload) { // 默认路径 / fileset_id /为下载路径 return await this.core.apis.FlashApi.downloadFileSetBySetId(payload.fileset_id); } diff --git a/packages/napcat-onebot/action/file/flash/GetFilesetIdByCode.ts b/packages/napcat-onebot/action/file/flash/GetFilesetIdByCode.ts index 1662c0c2..ebd8a722 100644 --- a/packages/napcat-onebot/action/file/flash/GetFilesetIdByCode.ts +++ b/packages/napcat-onebot/action/file/flash/GetFilesetIdByCode.ts @@ -2,19 +2,31 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - share_code: Type.String(), +export const GetFilesetIdPayloadSchema = Type.Object({ + share_code: Type.String({ description: '分享码或分享链接' }), }); -type Payload = Static; +export type GetFilesetIdPayload = Static; -export class GetFilesetId extends OneBotAction { +export class GetFilesetId extends OneBotAction { override actionName = ActionName.GetFilesetId; - override payloadSchema = SchemaData; + override payloadSchema = GetFilesetIdPayloadSchema; + override returnSchema = Type.Object({ + fileset_id: Type.String({ description: '文件集 ID' }) + }); + override actionSummary = '获取文件集 ID'; + override actionTags = ['文件扩展']; + override payloadExample = { + share_code: '123456' + }; + override returnExample = { + fileset_id: 'set_123' + }; - async _handle (payload: Payload) { + async _handle (payload: GetFilesetIdPayload) { // 适配share_link 防止被传 Link无法解析 const code = payload.share_code.includes('=') ? payload.share_code.split('=').slice(1).join('=') : payload.share_code; - return await this.core.apis.FlashApi.fromShareLinkFindSetId(code); + const result = await this.core.apis.FlashApi.fromShareLinkFindSetId(code); + return { fileset_id: result.fileSetId }; } } diff --git a/packages/napcat-onebot/action/file/flash/GetFilesetInfo.ts b/packages/napcat-onebot/action/file/flash/GetFilesetInfo.ts index 7fc77d0c..50534cf8 100644 --- a/packages/napcat-onebot/action/file/flash/GetFilesetInfo.ts +++ b/packages/napcat-onebot/action/file/flash/GetFilesetInfo.ts @@ -2,17 +2,27 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - fileset_id: Type.String(), +export const GetFilesetInfoPayloadSchema = Type.Object({ + fileset_id: Type.String({ description: '文件集 ID' }), }); -type Payload = Static; +export type GetFilesetInfoPayload = Static; -export class GetFilesetInfo extends OneBotAction { +export class GetFilesetInfo extends OneBotAction { override actionName = ActionName.GetFilesetInfo; - override payloadSchema = SchemaData; + override payloadSchema = GetFilesetInfoPayloadSchema; + override returnSchema = Type.Any({ description: '文件集信息' }); + override actionSummary = '获取文件集信息'; + override actionTags = ['文件扩展']; + override payloadExample = { + fileset_id: 'set_123' + }; + override returnExample = { + fileset_id: 'set_123', + file_list: [] + }; - async _handle (payload: Payload) { + async _handle (payload: GetFilesetInfoPayload) { return await this.core.apis.FlashApi.getFileSetIndoBySetId(payload.fileset_id); } } diff --git a/packages/napcat-onebot/action/file/flash/GetFlashFileList.ts b/packages/napcat-onebot/action/file/flash/GetFlashFileList.ts index e8ee1ea9..871483f9 100644 --- a/packages/napcat-onebot/action/file/flash/GetFlashFileList.ts +++ b/packages/napcat-onebot/action/file/flash/GetFlashFileList.ts @@ -2,17 +2,29 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - fileset_id: Type.String(), +export const GetFlashFileListPayloadSchema = Type.Object({ + fileset_id: Type.String({ description: '文件集 ID' }), }); -type Payload = Static; +export type GetFlashFileListPayload = Static; -export class GetFlashFileList extends OneBotAction { +export class GetFlashFileList extends OneBotAction { override actionName = ActionName.GetFlashFileList; - override payloadSchema = SchemaData; + override payloadSchema = GetFlashFileListPayloadSchema; + override returnSchema = Type.Any({ description: '文件列表' }); + override actionSummary = '获取闪照文件列表'; + override actionTags = ['文件扩展']; + override payloadExample = { + fileset_id: 'set_123' + }; + override returnExample = [ + { + file_name: 'test.jpg', + size: 1024 + } + ]; - async _handle (payload: Payload) { + async _handle (payload: GetFlashFileListPayload) { return await this.core.apis.FlashApi.getFileListBySetId(payload.fileset_id); } } diff --git a/packages/napcat-onebot/action/file/flash/GetFlashFileUrl.ts b/packages/napcat-onebot/action/file/flash/GetFlashFileUrl.ts index 403ad02f..27c1391f 100644 --- a/packages/napcat-onebot/action/file/flash/GetFlashFileUrl.ts +++ b/packages/napcat-onebot/action/file/flash/GetFlashFileUrl.ts @@ -2,19 +2,28 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - fileset_id: Type.String(), - file_name: Type.Optional(Type.String()), - file_index: Type.Optional(Type.Number()), +export const GetFlashFileUrlPayloadSchema = Type.Object({ + fileset_id: Type.String({ description: '文件集 ID' }), + file_name: Type.Optional(Type.String({ description: '文件名' })), + file_index: Type.Optional(Type.Number({ description: '文件索引' })), }); -type Payload = Static; +export type GetFlashFileUrlPayload = Static; -export class GetFlashFileUrl extends OneBotAction { +export class GetFlashFileUrl extends OneBotAction { override actionName = ActionName.GetFlashFileUrl; - override payloadSchema = SchemaData; + override payloadSchema = GetFlashFileUrlPayloadSchema; + override returnSchema = Type.Any({ description: '文件下载链接' }); + override actionSummary = '获取闪照文件链接'; + override actionTags = ['文件扩展']; + override payloadExample = { + fileset_id: 'set_123' + }; + override returnExample = { + url: 'http://example.com/flash.jpg' + }; - async _handle (payload: Payload) { + async _handle (payload: GetFlashFileUrlPayload) { // 文件的索引依旧从0开始 return await this.core.apis.FlashApi.getFileTransUrl(payload.fileset_id, { fileName: payload.file_name, diff --git a/packages/napcat-onebot/action/file/flash/GetShareLink.ts b/packages/napcat-onebot/action/file/flash/GetShareLink.ts index ea749cbd..7598bb69 100644 --- a/packages/napcat-onebot/action/file/flash/GetShareLink.ts +++ b/packages/napcat-onebot/action/file/flash/GetShareLink.ts @@ -2,17 +2,24 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - fileset_id: Type.String(), +export const GetShareLinkPayloadSchema = Type.Object({ + fileset_id: Type.String({ description: '文件集 ID' }), }); -type Payload = Static; +export type GetShareLinkPayload = Static; -export class GetShareLink extends OneBotAction { +export class GetShareLink extends OneBotAction { override actionName = ActionName.GetShareLink; - override payloadSchema = SchemaData; + override payloadSchema = GetShareLinkPayloadSchema; + override returnSchema = Type.Any({ description: '分享链接' }); + override actionSummary = '获取文件分享链接'; + override actionTags = ['文件扩展']; + override payloadExample = { + fileset_id: 'set_123' + }; + override returnExample = 'http://example.com/share'; - async _handle (payload: Payload) { + async _handle (payload: GetShareLinkPayload) { return await this.core.apis.FlashApi.getShareLinkBySetId(payload.fileset_id); } } diff --git a/packages/napcat-onebot/action/file/flash/SendFlashMsg.ts b/packages/napcat-onebot/action/file/flash/SendFlashMsg.ts index abc71cba..73583d00 100644 --- a/packages/napcat-onebot/action/file/flash/SendFlashMsg.ts +++ b/packages/napcat-onebot/action/file/flash/SendFlashMsg.ts @@ -3,19 +3,29 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; import { ChatType, Peer } from 'napcat-core/types'; -const SchemaData = Type.Object({ - fileset_id: Type.String(), - user_id: Type.Optional(Type.Union([Type.Number(), Type.String()])), - group_id: Type.Optional(Type.Union([Type.Number(), Type.String()])), +export const SendFlashMsgPayloadSchema = Type.Object({ + fileset_id: Type.String({ description: '文件集 ID' }), + user_id: Type.Optional(Type.String({ description: '用户 QQ' })), + group_id: Type.Optional(Type.String({ description: '群号' })), }); -type Payload = Static; +export type SendFlashMsgPayload = Static; -export class SendFlashMsg extends OneBotAction { +export class SendFlashMsg extends OneBotAction { override actionName = ActionName.SendFlashMsg; - override payloadSchema = SchemaData; + override payloadSchema = SendFlashMsgPayloadSchema; + override returnSchema = Type.Any({ description: '发送结果' }); + override actionSummary = '发送闪照消息'; + override actionTags = ['文件扩展']; + override payloadExample = { + fileset_id: 'set_123', + user_id: '123456789' + }; + override returnExample = { + message_id: 123456 + }; - async _handle (payload: Payload) { + async _handle (payload: SendFlashMsgPayload) { let peer: Peer; if (payload.group_id) { diff --git a/packages/napcat-onebot/action/file/online/CancelOnlineFile.ts b/packages/napcat-onebot/action/file/online/CancelOnlineFile.ts index 384798f0..4ab31d8d 100644 --- a/packages/napcat-onebot/action/file/online/CancelOnlineFile.ts +++ b/packages/napcat-onebot/action/file/online/CancelOnlineFile.ts @@ -3,18 +3,26 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; import { ChatType } from 'napcat-core/types'; -const SchemaData = Type.Object({ - user_id: Type.Union([Type.Number(), Type.String()]), - msg_id: Type.String(), +export const CancelOnlineFilePayloadSchema = Type.Object({ + user_id: Type.String({ description: '用户 QQ' }), + msg_id: Type.String({ description: '消息 ID' }), }); -type Payload = Static; +export type CancelOnlineFilePayload = Static; -export class CancelOnlineFile extends OneBotAction { +export class CancelOnlineFile extends OneBotAction { override actionName = ActionName.CancelOnlineFile; - override payloadSchema = SchemaData; + override payloadSchema = CancelOnlineFilePayloadSchema; + override returnSchema = Type.Any({ description: '取消结果' }); + override actionSummary = '取消在线文件'; + override actionTags = ['文件扩展']; + override payloadExample = { + user_id: '123456789', + msg_id: '123' + }; + override returnExample = null; - async _handle (payload: Payload) { + async _handle (payload: CancelOnlineFilePayload) { const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString()); if (!uid) throw new Error('User not found'); diff --git a/packages/napcat-onebot/action/file/online/GetOnlineFileMessages.ts b/packages/napcat-onebot/action/file/online/GetOnlineFileMessages.ts index 0cd0a320..d3bf26b1 100644 --- a/packages/napcat-onebot/action/file/online/GetOnlineFileMessages.ts +++ b/packages/napcat-onebot/action/file/online/GetOnlineFileMessages.ts @@ -3,17 +3,24 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; import { ChatType } from 'napcat-core/types'; -const SchemaData = Type.Object({ - user_id: Type.Union([Type.Number(), Type.String()]), +export const GetOnlineFileMessagesPayloadSchema = Type.Object({ + user_id: Type.String({ description: '用户 QQ' }), }); -type Payload = Static; +export type GetOnlineFileMessagesPayload = Static; -export class GetOnlineFileMessages extends OneBotAction { +export class GetOnlineFileMessages extends OneBotAction { override actionName = ActionName.GetOnlineFileMessages; - override payloadSchema = SchemaData; + override payloadSchema = GetOnlineFileMessagesPayloadSchema; + override returnSchema = Type.Any({ description: '在线文件消息列表' }); + override actionSummary = '获取在线文件消息'; + override actionTags = ['文件扩展']; + override payloadExample = { + user_id: '123456789' + }; + override returnExample = []; - async _handle (payload: Payload) { + async _handle (payload: GetOnlineFileMessagesPayload) { const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString()); if (!uid) throw new Error('User not found'); diff --git a/packages/napcat-onebot/action/file/online/ReceiveOnlineFile.ts b/packages/napcat-onebot/action/file/online/ReceiveOnlineFile.ts index 5204d1d1..dccf3905 100644 --- a/packages/napcat-onebot/action/file/online/ReceiveOnlineFile.ts +++ b/packages/napcat-onebot/action/file/online/ReceiveOnlineFile.ts @@ -3,19 +3,28 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; import { ChatType } from 'napcat-core/types'; -const SchemaData = Type.Object({ - user_id: Type.Union([Type.Number(), Type.String()]), - msg_id: Type.String(), - element_id: Type.String(), +export const ReceiveOnlineFilePayloadSchema = Type.Object({ + user_id: Type.String({ description: '用户 QQ' }), + msg_id: Type.String({ description: '消息 ID' }), + element_id: Type.String({ description: '元素 ID' }), }); -type Payload = Static; +export type ReceiveOnlineFilePayload = Static; -export class ReceiveOnlineFile extends OneBotAction { +export class ReceiveOnlineFile extends OneBotAction { override actionName = ActionName.ReceiveOnlineFile; - override payloadSchema = SchemaData; + override payloadSchema = ReceiveOnlineFilePayloadSchema; + override returnSchema = Type.Any({ description: '接收结果' }); + override actionSummary = '接收在线文件'; + override actionTags = ['文件扩展']; + override payloadExample = { + user_id: '123456789', + msg_id: '123', + save_path: 'C:\\save' + }; + override returnExample = null; - async _handle (payload: Payload) { + async _handle (payload: ReceiveOnlineFilePayload) { // 默认下载路径 const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString()); if (!uid) throw new Error('User not found'); diff --git a/packages/napcat-onebot/action/file/online/RefuseOnlineFile.ts b/packages/napcat-onebot/action/file/online/RefuseOnlineFile.ts index 6b3ff972..c17f1fb5 100644 --- a/packages/napcat-onebot/action/file/online/RefuseOnlineFile.ts +++ b/packages/napcat-onebot/action/file/online/RefuseOnlineFile.ts @@ -3,19 +3,27 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; import { ChatType } from 'napcat-core/types'; -const SchemaData = Type.Object({ - user_id: Type.Union([Type.Number(), Type.String()]), - msg_id: Type.String(), - element_id: Type.String(), +export const RefuseOnlineFilePayloadSchema = Type.Object({ + user_id: Type.String({ description: '用户 QQ' }), + msg_id: Type.String({ description: '消息 ID' }), + element_id: Type.String({ description: '元素 ID' }), }); -type Payload = Static; +export type RefuseOnlineFilePayload = Static; -export class RefuseOnlineFile extends OneBotAction { +export class RefuseOnlineFile extends OneBotAction { override actionName = ActionName.RefuseOnlineFile; - override payloadSchema = SchemaData; + override payloadSchema = RefuseOnlineFilePayloadSchema; + override returnSchema = Type.Any({ description: '拒绝结果' }); + override actionSummary = '拒绝在线文件'; + override actionTags = ['文件扩展']; + override payloadExample = { + user_id: '123456789', + msg_id: '123' + }; + override returnExample = null; - async _handle (payload: Payload) { + async _handle (payload: RefuseOnlineFilePayload) { const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString()); if (!uid) throw new Error('User not found'); diff --git a/packages/napcat-onebot/action/file/online/SendOnlineFile.ts b/packages/napcat-onebot/action/file/online/SendOnlineFile.ts index b5a657a3..8c0ba336 100644 --- a/packages/napcat-onebot/action/file/online/SendOnlineFile.ts +++ b/packages/napcat-onebot/action/file/online/SendOnlineFile.ts @@ -3,19 +3,28 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; import { ChatType } from 'napcat-core/types'; -const SchemaData = Type.Object({ - user_id: Type.Union([Type.Number(), Type.String()]), - file_path: Type.String(), - file_name: Type.Optional(Type.String()), +export const SendOnlineFilePayloadSchema = Type.Object({ + user_id: Type.String({ description: '用户 QQ' }), + file_path: Type.String({ description: '本地文件路径' }), + file_name: Type.Optional(Type.String({ description: '文件名 (可选)' })), }); -type Payload = Static; +export type SendOnlineFilePayload = Static; -export class SendOnlineFile extends OneBotAction { +export class SendOnlineFile extends OneBotAction { override actionName = ActionName.SendOnlineFile; - override payloadSchema = SchemaData; + override payloadSchema = SendOnlineFilePayloadSchema; + override returnSchema = Type.Any({ description: '发送结果' }); + override actionSummary = '发送在线文件'; + override actionTags = ['文件扩展']; + override payloadExample = { + user_id: '123456789', + file_path: 'C:\\path\\to\\file.txt', + file_name: 'test.txt' + }; + override returnExample = null; - async _handle (payload: Payload) { + async _handle (payload: SendOnlineFilePayload) { const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString()); if (!uid) throw new Error('User not found'); diff --git a/packages/napcat-onebot/action/file/online/SendOnlineFolder.ts b/packages/napcat-onebot/action/file/online/SendOnlineFolder.ts index a4da4855..6a3d0a79 100644 --- a/packages/napcat-onebot/action/file/online/SendOnlineFolder.ts +++ b/packages/napcat-onebot/action/file/online/SendOnlineFolder.ts @@ -3,19 +3,27 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; import { ChatType } from 'napcat-core/types'; -const SchemaData = Type.Object({ - user_id: Type.Union([Type.Number(), Type.String()]), - folder_path: Type.String(), - folder_name: Type.Optional(Type.String()), +export const SendOnlineFolderPayloadSchema = Type.Object({ + user_id: Type.String({ description: '用户 QQ' }), + folder_path: Type.String({ description: '本地文件夹路径' }), + folder_name: Type.Optional(Type.String({ description: '文件夹名称 (可选)' })), }); -type Payload = Static; +export type SendOnlineFolderPayload = Static; -export class SendOnlineFolder extends OneBotAction { +export class SendOnlineFolder extends OneBotAction { override actionName = ActionName.SendOnlineFolder; - override payloadSchema = SchemaData; + override payloadSchema = SendOnlineFolderPayloadSchema; + override returnSchema = Type.Any({ description: '发送结果' }); + override actionSummary = '发送在线文件夹'; + override actionTags = ['文件扩展']; + override payloadExample = { + user_id: '123456789', + folder_path: 'C:\\path\\to\\folder' + }; + override returnExample = null; - async _handle (payload: Payload) { + async _handle (payload: SendOnlineFolderPayload) { const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString()); if (!uid) throw new Error('User not found'); diff --git a/packages/napcat-onebot/action/go-cqhttp/CreateGroupFileFolder.ts b/packages/napcat-onebot/action/go-cqhttp/CreateGroupFileFolder.ts index c10a58f6..a02060b5 100644 --- a/packages/napcat-onebot/action/go-cqhttp/CreateGroupFileFolder.ts +++ b/packages/napcat-onebot/action/go-cqhttp/CreateGroupFileFolder.ts @@ -2,23 +2,40 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), // 兼容gocq 与name二选一 - folder_name: Type.Optional(Type.String()), + folder_name: Type.Optional(Type.String({ description: '文件夹名称' })), // 兼容gocq 与folder_name二选一 - name: Type.Optional(Type.String()), + name: Type.Optional(Type.String({ description: '文件夹名称' })), }); -type Payload = Static; -interface ResponseType { - result: unknown; - groupItem: unknown; -} -export class CreateGroupFileFolder extends OneBotAction { +type PayloadType = Static; + +const ReturnSchema = Type.Object({ + result: Type.Any({ description: '操作结果' }), + groupItem: Type.Any({ description: '群项信息' }), +}, { description: '创建文件夹结果' }); + +type ReturnType = Static; + +export class CreateGroupFileFolder extends OneBotAction { override actionName = ActionName.GoCQHTTP_CreateGroupFileFolder; - override payloadSchema = SchemaData; - async _handle (payload: Payload) { + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '创建群文件目录'; + override actionDescription = '在群文件系统中创建新的文件夹'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = { + group_id: '123456789', + folder_name: '新建文件夹' + }; + override returnExample = { + result: {}, + groupItem: {} + }; + + async _handle (payload: PayloadType) { const folderName = payload.folder_name || payload.name; return (await this.core.apis.GroupApi.creatGroupFileFolder(payload.group_id.toString(), folderName!)).resultWithGroupItem; } diff --git a/packages/napcat-onebot/action/go-cqhttp/DeleteGroupFile.ts b/packages/napcat-onebot/action/go-cqhttp/DeleteGroupFile.ts index a61fe537..ef1b24fa 100644 --- a/packages/napcat-onebot/action/go-cqhttp/DeleteGroupFile.ts +++ b/packages/napcat-onebot/action/go-cqhttp/DeleteGroupFile.ts @@ -2,19 +2,30 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { FileNapCatOneBotUUID } from 'napcat-common/src/file-uuid'; import { Static, Type } from '@sinclair/typebox'; -import { NTQQGroupApi } from 'napcat-core/apis'; +import { GoCQHTTPActionsExamples } from '../example/GoCQHTTPActionsExamples'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - file_id: Type.String(), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + file_id: Type.String({ description: '文件ID' }), }); -type Payload = Static; +type PayloadType = Static; -export class DeleteGroupFile extends OneBotAction>> { +const ReturnSchema = Type.Any({ description: '删除结果' }); + +type ReturnType = Static; + +export class DeleteGroupFile extends OneBotAction { override actionName = ActionName.GOCQHTTP_DeleteGroupFile; - override payloadSchema = SchemaData; - async _handle (payload: Payload) { + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '删除群文件'; + override actionDescription = '在群文件系统中删除指定的文件'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.DeleteGroupFile.payload; + override returnExample = GoCQHTTPActionsExamples.DeleteGroupFile.response; + + async _handle (payload: PayloadType) { const data = FileNapCatOneBotUUID.decodeModelId(payload.file_id); if (!data || !data.fileId) throw new Error('Invalid file_id'); return await this.core.apis.GroupApi.delGroupFile(payload.group_id.toString(), [data.fileId]); diff --git a/packages/napcat-onebot/action/go-cqhttp/DeleteGroupFileFolder.ts b/packages/napcat-onebot/action/go-cqhttp/DeleteGroupFileFolder.ts index 4a96a6fc..b7ed1508 100644 --- a/packages/napcat-onebot/action/go-cqhttp/DeleteGroupFileFolder.ts +++ b/packages/napcat-onebot/action/go-cqhttp/DeleteGroupFileFolder.ts @@ -1,20 +1,31 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { Static, Type } from '@sinclair/typebox'; -import { NTQQGroupApi } from 'napcat-core/apis'; +import { GoCQHTTPActionsExamples } from '../example/GoCQHTTPActionsExamples'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - folder_id: Type.Optional(Type.String()), - folder: Type.Optional(Type.String()), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + folder_id: Type.Optional(Type.String({ description: '文件夹ID' })), + folder: Type.Optional(Type.String({ description: '文件夹ID' })), }); -type Payload = Static; +type PayloadType = Static; -export class DeleteGroupFileFolder extends OneBotAction>['groupFileCommonResult']> { +const ReturnSchema = Type.Any({ description: '删除结果' }); + +type ReturnType = Static; + +export class DeleteGroupFileFolder extends OneBotAction { override actionName = ActionName.GoCQHTTP_DeleteGroupFileFolder; - override payloadSchema = SchemaData; - async _handle (payload: Payload) { + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '删除群文件目录'; + override actionDescription = '在群文件系统中删除指定的文件夹'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.DeleteGroupFileFolder.payload; + override returnExample = GoCQHTTPActionsExamples.DeleteGroupFileFolder.response; + + async _handle (payload: PayloadType) { return (await this.core.apis.GroupApi.delGroupFileFolder( payload.group_id.toString(), payload.folder ?? payload.folder_id ?? '')).groupFileCommonResult; } diff --git a/packages/napcat-onebot/action/go-cqhttp/DownloadFile.ts b/packages/napcat-onebot/action/go-cqhttp/DownloadFile.ts index 15c77500..b8e9e227 100644 --- a/packages/napcat-onebot/action/go-cqhttp/DownloadFile.ts +++ b/packages/napcat-onebot/action/go-cqhttp/DownloadFile.ts @@ -5,28 +5,37 @@ import { join as joinPath } from 'node:path'; import { calculateFileMD5, uriToLocalFile } from 'napcat-common/src/file'; import { randomUUID } from 'crypto'; import { Static, Type } from '@sinclair/typebox'; +import { GoCQHTTPActionsExamples } from '../example/GoCQHTTPActionsExamples'; -interface FileResponse { - file: string; -} - -const SchemaData = Type.Object({ - url: Type.Optional(Type.String()), - base64: Type.Optional(Type.String()), - name: Type.Optional(Type.String()), - headers: Type.Optional(Type.Union([Type.String(), Type.Array(Type.String())])), +const PayloadSchema = Type.Object({ + url: Type.Optional(Type.String({ description: '下载链接' })), + base64: Type.Optional(Type.String({ description: 'base64数据' })), + name: Type.Optional(Type.String({ description: '文件名' })), + headers: Type.Optional(Type.Union([Type.String(), Type.Array(Type.String())], { description: '请求头' })), }); -type Payload = Static; +type PayloadType = Static; -export default class GoCQHTTPDownloadFile extends OneBotAction { +const ReturnSchema = Type.Object({ + file: Type.String({ description: '文件路径' }), +}, { description: '下载结果' }); + +type ReturnType = Static; + +export default class GoCQHTTPDownloadFile extends OneBotAction { override actionName = ActionName.GoCQHTTP_DownloadFile; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '下载文件'; + override actionDescription = '下载网络文件到本地临时目录'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.DownloadFile.payload; + override returnExample = GoCQHTTPActionsExamples.DownloadFile.response; - async _handle (payload: Payload): Promise { + async _handle (payload: PayloadType): Promise { const isRandomName = !payload.name; const name = payload.name || randomUUID(); - let result: Awaited>; + let result: Awaited>; if (payload.base64) { result = await uriToLocalFile(this.core.NapCatTempPath, `base64://${payload.base64}`, name); diff --git a/packages/napcat-onebot/action/go-cqhttp/GetForwardMsg.ts b/packages/napcat-onebot/action/go-cqhttp/GetForwardMsg.ts index e165320b..bc09d448 100644 --- a/packages/napcat-onebot/action/go-cqhttp/GetForwardMsg.ts +++ b/packages/napcat-onebot/action/go-cqhttp/GetForwardMsg.ts @@ -5,18 +5,34 @@ import { MessageUnique } from 'napcat-common/src/message-unique'; import { Static, Type } from '@sinclair/typebox'; import { ChatType, ElementType, MsgSourceType, NTMsgType, RawMessage } from 'napcat-core'; import { isNumeric } from 'napcat-common/src/helper'; +import { GoCQHTTPActionsExamples } from '../example/GoCQHTTPActionsExamples'; -const SchemaData = Type.Object({ - message_id: Type.Optional(Type.String()), - id: Type.Optional(Type.String()), +const PayloadSchema = Type.Object({ + message_id: Type.Optional(Type.String({ description: '消息ID' })), + id: Type.Optional(Type.String({ description: '消息ID' })), }); -type Payload = Static; -export class GoCQHTTPGetForwardMsgAction extends OneBotAction { +type PayloadType = Static; + +const ReturnSchema = Type.Object({ + messages: Type.Optional(Type.Array(Type.Unknown(), { description: '消息列表' })), +}, { description: '合并转发消息' }); + +type ReturnType = Static; + +function isForward (msg: OB11MessageData | string): msg is OB11MessageForward { + return typeof msg !== 'string' && msg.type === OB11MessageDataType.forward; +} + +export class GoCQHTTPGetForwardMsgAction extends OneBotAction { override actionName = ActionName.GoCQHTTP_GetForwardMsg; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取合并转发消息'; + override actionDescription = '获取合并转发消息的具体内容'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.GetForwardMsg.payload; + override returnExample = GoCQHTTPActionsExamples.GetForwardMsg.response; private createTemplateNode (message: OB11Message): OB11MessageNode { return { @@ -37,13 +53,18 @@ export class GoCQHTTPGetForwardMsgAction extends OneBotAction { - return { + const fakeMsg: RawMessage = { chatType: ChatType.KCHATTYPEGROUP, elements: [{ elementType: ElementType.MULTIFORWARD, @@ -74,7 +95,7 @@ export class GoCQHTTPGetForwardMsgAction extends OneBotAction { const ob = (await this.obContext.apis.MsgApi.parseMessageV2(createFakeForwardMsg(resId), true))?.arrayMsg; - if (ob) { + const firstMsg = ob?.message?.[0]; + if (firstMsg && isForward(firstMsg)) { return { - messages: (ob?.message?.[0] as OB11MessageForward)?.data?.content, + messages: firstMsg.data.content, }; } throw new Error('protocolFallbackLogic: 找不到相关的聊天记录'); @@ -132,9 +155,12 @@ export class GoCQHTTPGetForwardMsgAction extends OneBotAction; +type PayloadType = Static; -export default class GetFriendMsgHistory extends OneBotAction { +const ReturnSchema = Type.Object({ + messages: Type.Array(Type.Any(), { description: '消息列表' }), +}, { description: '好友历史消息' }); + +type ReturnType = Static; + +export default class GetFriendMsgHistory extends OneBotAction { override actionName = ActionName.GetFriendMsgHistory; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取好友历史消息'; + override actionDescription = '获取指定好友的历史聊天记录'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.GetFriendMsgHistory.payload; + override returnExample = GoCQHTTPActionsExamples.GetFriendMsgHistory.response; - async _handle (payload: Payload, _adapter: string, config: NetworkAdapterConfig): Promise { + async _handle (payload: PayloadType, _adapter: string, config: NetworkAdapterConfig): Promise { // 处理参数 const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString()); if (!uid) throw new Error(`记录${payload.user_id}不存在`); @@ -46,7 +56,7 @@ export default class GetFriendMsgHistory extends OneBotAction // 烘焙消息 const ob11MsgList = (await Promise.all( msgList.map(msg => this.obContext.apis.MsgApi.parseMessage(msg, config.messagePostFormat, payload.parse_mult_msg, payload.disable_get_url))) - ).filter(msg => msg !== undefined); + ).filter((msg): msg is OB11Message => msg !== undefined); return { messages: ob11MsgList }; } } diff --git a/packages/napcat-onebot/action/go-cqhttp/GetGroupAtAllRemain.ts b/packages/napcat-onebot/action/go-cqhttp/GetGroupAtAllRemain.ts index 207c5efc..aceac0e4 100644 --- a/packages/napcat-onebot/action/go-cqhttp/GetGroupAtAllRemain.ts +++ b/packages/napcat-onebot/action/go-cqhttp/GetGroupAtAllRemain.ts @@ -1,22 +1,33 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; +import { GoCQHTTPActionsExamples } from '../example/GoCQHTTPActionsExamples'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), }); -type Payload = Static; -interface ResponseType { - can_at_all: boolean; - remain_at_all_count_for_group: number; - remain_at_all_count_for_uin: number; -} -export class GoCQHTTPGetGroupAtAllRemain extends OneBotAction { - override actionName = ActionName.GoCQHTTP_GetGroupAtAllRemain; - override payloadSchema = SchemaData; +type PayloadType = Static; - async _handle (payload: Payload) { +const ReturnSchema = Type.Object({ + can_at_all: Type.Boolean({ description: '是否可以艾特全体' }), + remain_at_all_count_for_group: Type.Number({ description: '群艾特全体剩余次数' }), + remain_at_all_count_for_uin: Type.Number({ description: '个人艾特全体剩余次数' }), +}, { description: '群艾特全体剩余次数' }); + +type ReturnType = Static; + +export class GoCQHTTPGetGroupAtAllRemain extends OneBotAction { + override actionName = ActionName.GoCQHTTP_GetGroupAtAllRemain; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取群艾特全体剩余次数'; + override actionDescription = '获取指定群聊中艾特全体成员的剩余次数'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.GetGroupAtAllRemain.payload; + override returnExample = GoCQHTTPActionsExamples.GetGroupAtAllRemain.response; + + async _handle (payload: PayloadType) { const ret = await this.core.apis.GroupApi.getGroupRemainAtTimes(payload.group_id.toString()); const data = { can_at_all: ret.atInfo.canAtAll, diff --git a/packages/napcat-onebot/action/go-cqhttp/GetGroupFileSystemInfo.ts b/packages/napcat-onebot/action/go-cqhttp/GetGroupFileSystemInfo.ts index 1f23d383..1a01b61e 100644 --- a/packages/napcat-onebot/action/go-cqhttp/GetGroupFileSystemInfo.ts +++ b/packages/napcat-onebot/action/go-cqhttp/GetGroupFileSystemInfo.ts @@ -1,23 +1,34 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; +import { GoCQHTTPActionsExamples } from '../example/GoCQHTTPActionsExamples'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), }); -type Payload = Static; +type PayloadType = Static; -export class GetGroupFileSystemInfo extends OneBotAction { +const ReturnSchema = Type.Object({ + file_count: Type.Number({ description: '文件总数' }), + limit_count: Type.Number({ description: '文件上限' }), + used_space: Type.Number({ description: '已使用空间' }), + total_space: Type.Number({ description: '总空间' }), +}, { description: '群文件系统信息' }); + +type ReturnType = Static; + +export class GetGroupFileSystemInfo extends OneBotAction { override actionName = ActionName.GoCQHTTP_GetGroupFileSystemInfo; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取群文件系统信息'; + override actionDescription = '获取群聊文件系统的空间及状态信息'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.GetGroupFileSystemInfo.payload; + override returnExample = GoCQHTTPActionsExamples.GetGroupFileSystemInfo.response; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { const groupFileCount = (await this.core.apis.GroupApi.getGroupFileCount([payload.group_id.toString()])).groupFileCounts[0]; if (!groupFileCount) { throw new Error('Group not found'); diff --git a/packages/napcat-onebot/action/go-cqhttp/GetGroupFilesByFolder.ts b/packages/napcat-onebot/action/go-cqhttp/GetGroupFilesByFolder.ts index 51875a91..8fc45483 100644 --- a/packages/napcat-onebot/action/go-cqhttp/GetGroupFilesByFolder.ts +++ b/packages/napcat-onebot/action/go-cqhttp/GetGroupFilesByFolder.ts @@ -2,35 +2,48 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { OB11Construct } from '@/napcat-onebot/helper/data'; import { Static, Type } from '@sinclair/typebox'; +import { GoCQHTTPActionsExamples } from '../example/GoCQHTTPActionsExamples'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - folder_id: Type.Optional(Type.String()), - folder: Type.Optional(Type.String()), - file_count: Type.Union([Type.Number(), Type.String()], { default: 50 }), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + folder_id: Type.Optional(Type.String({ description: '文件夹ID' })), + folder: Type.Optional(Type.String({ description: '文件夹ID' })), + file_count: Type.Union([Type.Number(), Type.String()], { default: 50, description: '文件数量' }), }); -type Payload = Static; +type PayloadType = Static; -export class GetGroupFilesByFolder extends OneBotAction[], - folders: never[], -}> { +const ReturnSchema = Type.Object({ + files: Type.Array(Type.Unknown(), { description: '文件列表' }), + folders: Type.Array(Type.Unknown(), { description: '文件夹列表' }), +}, { description: '群文件夹文件列表' }); + +type ReturnType = Static; + +export class GetGroupFilesByFolder extends OneBotAction { override actionName = ActionName.GoCQHTTP_GetGroupFilesByFolder; - override payloadSchema = SchemaData; - async _handle (payload: Payload) { - const ret = await this.core.apis.MsgApi.getGroupFileList(payload.group_id.toString(), { + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取群文件夹文件列表'; + override actionDescription = '获取指定群文件夹下的文件及子文件夹列表'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.GetGroupFilesByFolder.payload; + override returnExample = GoCQHTTPActionsExamples.GetGroupFilesByFolder.response; + + async _handle (payload: PayloadType): Promise { + const retRaw = await this.core.apis.MsgApi.getGroupFileList(payload.group_id.toString(), { sortType: 1, fileCount: +payload.file_count, startIndex: 0, sortOrder: 2, showOnlinedocFolder: 0, folderId: payload.folder ?? payload.folder_id ?? '', - }).catch(() => []); + }); + const ret = Array.isArray(retRaw) ? retRaw : []; return { files: ret.filter(item => item.fileInfo) .map(item => OB11Construct.file(item.peerId, item.fileInfo!)), - folders: [] as [], + folders: [], }; } } diff --git a/packages/napcat-onebot/action/go-cqhttp/GetGroupHonorInfo.ts b/packages/napcat-onebot/action/go-cqhttp/GetGroupHonorInfo.ts index 233df28f..df0f226f 100644 --- a/packages/napcat-onebot/action/go-cqhttp/GetGroupHonorInfo.ts +++ b/packages/napcat-onebot/action/go-cqhttp/GetGroupHonorInfo.ts @@ -2,29 +2,38 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { WebHonorType } from 'napcat-core/types'; import { Static, Type } from '@sinclair/typebox'; +import { GoCQHTTPActionsExamples } from '../example/GoCQHTTPActionsExamples'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - type: Type.Optional(Type.Enum(WebHonorType)), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + type: Type.Optional(Type.Enum(WebHonorType, { description: '荣誉类型' })), }); -type Payload = Static; +type PayloadType = Static; -interface HonorInfo { - group_id: number; - current_talkative: Record; - talkative_list: unknown[]; - performer_list: unknown[]; - legend_list: unknown[]; - emotion_list: unknown[]; - strong_newbie_list: unknown[]; -} +const ReturnSchema = Type.Object({ + group_id: Type.Number({ description: '群号' }), + current_talkative: Type.Record(Type.String(), Type.Unknown(), { description: '当前龙王' }), + talkative_list: Type.Array(Type.Unknown(), { description: '龙王列表' }), + performer_list: Type.Array(Type.Unknown(), { description: '群聊之火列表' }), + legend_list: Type.Array(Type.Unknown(), { description: '群聊炽热列表' }), + emotion_list: Type.Array(Type.Unknown(), { description: '快乐源泉列表' }), + strong_newbie_list: Type.Array(Type.Unknown(), { description: '冒尖小春笋列表' }), +}, { description: '群荣誉信息' }); -export class GetGroupHonorInfo extends OneBotAction { +type ReturnType = Static; + +export class GetGroupHonorInfo extends OneBotAction { override actionName = ActionName.GetGroupHonorInfo; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取群荣誉信息'; + override actionDescription = '获取指定群聊的荣誉信息,如龙王等'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.GetGroupHonorInfo.payload; + override returnExample = GoCQHTTPActionsExamples.GetGroupHonorInfo.response; - async _handle (payload: Payload) { + async _handle (payload: PayloadType): Promise { if (!payload.type) { payload.type = WebHonorType.ALL; } diff --git a/packages/napcat-onebot/action/go-cqhttp/GetGroupMsgHistory.ts b/packages/napcat-onebot/action/go-cqhttp/GetGroupMsgHistory.ts index 47407b3d..a5718eda 100644 --- a/packages/napcat-onebot/action/go-cqhttp/GetGroupMsgHistory.ts +++ b/packages/napcat-onebot/action/go-cqhttp/GetGroupMsgHistory.ts @@ -5,29 +5,38 @@ import { ChatType, Peer } from 'napcat-core/types'; import { MessageUnique } from 'napcat-common/src/message-unique'; import { Static, Type } from '@sinclair/typebox'; import { NetworkAdapterConfig } from '@/napcat-onebot/config/config'; +import { GoCQHTTPActionsExamples } from '../example/GoCQHTTPActionsExamples'; -interface Response { - messages: OB11Message[]; -} - -const SchemaData = Type.Object({ - group_id: Type.String(), - message_seq: Type.Optional(Type.String()), - count: Type.Number({ default: 20 }), - reverse_order: Type.Boolean({ default: false }), - disable_get_url: Type.Boolean({ default: false }), - parse_mult_msg: Type.Boolean({ default: true }), - quick_reply: Type.Boolean({ default: false }), - reverseOrder: Type.Boolean({ default: false }),// @deprecated 兼容旧版本 +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + message_seq: Type.Optional(Type.String({ description: '起始消息序号' })), + count: Type.Number({ default: 20, description: '获取消息数量' }), + reverse_order: Type.Boolean({ default: false, description: '是否反向排序' }), + disable_get_url: Type.Boolean({ default: false, description: '是否禁用获取URL' }), + parse_mult_msg: Type.Boolean({ default: true, description: '是否解析合并消息' }), + quick_reply: Type.Boolean({ default: false, description: '是否快速回复' }), + reverseOrder: Type.Boolean({ default: false, description: '是否反向排序(旧版本兼容)' }), }); -type Payload = Static; +type PayloadType = Static; -export default class GoCQHTTPGetGroupMsgHistory extends OneBotAction { +const ReturnSchema = Type.Object({ + messages: Type.Array(Type.Any(), { description: '消息列表' }), +}, { description: '群历史消息' }); + +type ReturnType = Static; + +export default class GoCQHTTPGetGroupMsgHistory extends OneBotAction { override actionName = ActionName.GoCQHTTP_GetGroupMsgHistory; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取群历史消息'; + override actionDescription = '获取指定群聊的历史聊天记录'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.GetGroupMsgHistory.payload; + override returnExample = GoCQHTTPActionsExamples.GetGroupMsgHistory.response; - async _handle (payload: Payload, _adapter: string, config: NetworkAdapterConfig): Promise { + async _handle (payload: PayloadType, _adapter: string, config: NetworkAdapterConfig): Promise { const peer: Peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: payload.group_id.toString() }; const hasMessageSeq = !payload.message_seq ? !!payload.message_seq : !(payload.message_seq?.toString() === '' || payload.message_seq?.toString() === '0'); // 拉取消息 @@ -43,7 +52,7 @@ export default class GoCQHTTPGetGroupMsgHistory extends OneBotAction this.obContext.apis.MsgApi.parseMessage(msg, config.messagePostFormat, payload.parse_mult_msg, payload.disable_get_url, payload.quick_reply))) - ).filter(msg => msg !== undefined); + ).filter((msg): msg is OB11Message => msg !== undefined); return { messages: ob11MsgList }; } } diff --git a/packages/napcat-onebot/action/go-cqhttp/GetGroupRootFiles.ts b/packages/napcat-onebot/action/go-cqhttp/GetGroupRootFiles.ts index a0737471..cc20cf5f 100644 --- a/packages/napcat-onebot/action/go-cqhttp/GetGroupRootFiles.ts +++ b/packages/napcat-onebot/action/go-cqhttp/GetGroupRootFiles.ts @@ -1,23 +1,34 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; -import { OB11GroupFile, OB11GroupFileFolder } from '@/napcat-onebot/index'; import { OB11Construct } from '@/napcat-onebot/helper/data'; import { Static, Type } from '@sinclair/typebox'; +import { GoCQHTTPActionsExamples } from '../example/GoCQHTTPActionsExamples'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - file_count: Type.Union([Type.Number(), Type.String()], { default: 50 }), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + file_count: Type.Union([Type.Number(), Type.String()], { default: 50, description: '文件数量' }), }); -type Payload = Static; +type PayloadType = Static; -export class GetGroupRootFiles extends OneBotAction { +const ReturnSchema = Type.Object({ + files: Type.Array(Type.Any(), { description: '文件列表' }), + folders: Type.Array(Type.Any(), { description: '文件夹列表' }), +}, { description: '群根目录文件列表' }); + +type ReturnType = Static; + +export class GetGroupRootFiles extends OneBotAction { override actionName = ActionName.GoCQHTTP_GetGroupRootFiles; - override payloadSchema = SchemaData; - async _handle (payload: Payload) { + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取群根目录文件列表'; + override actionDescription = '获取群文件根目录下的所有文件和文件夹'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.GetGroupRootFiles.payload; + override returnExample = GoCQHTTPActionsExamples.GetGroupRootFiles.response; + + async _handle (payload: PayloadType) { const ret = await this.core.apis.MsgApi.getGroupFileList(payload.group_id.toString(), { sortType: 1, fileCount: +payload.file_count, diff --git a/packages/napcat-onebot/action/go-cqhttp/GetOnlineClient.ts b/packages/napcat-onebot/action/go-cqhttp/GetOnlineClient.ts index 57b748db..071e4179 100644 --- a/packages/napcat-onebot/action/go-cqhttp/GetOnlineClient.ts +++ b/packages/napcat-onebot/action/go-cqhttp/GetOnlineClient.ts @@ -1,9 +1,27 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { sleep } from 'napcat-common/src/helper'; +import { Static, Type } from '@sinclair/typebox'; +import { GoCQHTTPActionsExamples } from '../example/GoCQHTTPActionsExamples'; -export class GetOnlineClient extends OneBotAction> { +const PayloadSchema = Type.Object({}, { description: '在线客户端负载' }); + +type PayloadType = Static; + +const ReturnSchema = Type.Array(Type.Any(), { description: '在线客户端列表' }); + +type ReturnType = Static; + +export class GetOnlineClient extends OneBotAction { override actionName = ActionName.GetOnlineClient; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取在线客户端'; + override actionDescription = '获取当前登录账号的在线客户端列表'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.GetOnlineClient.payload; + override returnExample = GoCQHTTPActionsExamples.GetOnlineClient.response; + async _handle () { // 注册监听 this.core.apis.SystemApi.getOnlineDev(); diff --git a/packages/napcat-onebot/action/go-cqhttp/GetStrangerInfo.ts b/packages/napcat-onebot/action/go-cqhttp/GetStrangerInfo.ts index 0c9d9ff7..7610917e 100644 --- a/packages/napcat-onebot/action/go-cqhttp/GetStrangerInfo.ts +++ b/packages/napcat-onebot/action/go-cqhttp/GetStrangerInfo.ts @@ -1,21 +1,49 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; -import { OB11User, OB11UserSex } from '@/napcat-onebot/index'; +import { OB11UserSex } from '@/napcat-onebot/index'; import { OB11Construct } from '@/napcat-onebot/helper/data'; import { ActionName } from '@/napcat-onebot/action/router'; import { calcQQLevel } from 'napcat-common/src/helper'; import { Static, Type } from '@sinclair/typebox'; +import { GoCQHTTPActionsExamples } from '../example/GoCQHTTPActionsExamples'; -const SchemaData = Type.Object({ - user_id: Type.Union([Type.Number(), Type.String()]), - no_cache: Type.Union([Type.Boolean(), Type.String()], { default: false }), +const PayloadSchema = Type.Object({ + user_id: Type.String({ description: '用户QQ' }), + no_cache: Type.Union([Type.Boolean(), Type.String()], { default: false, description: '是否不使用缓存' }), }); -type Payload = Static; +type PayloadType = Static; -export default class GoCQHTTPGetStrangerInfo extends OneBotAction { +const ReturnSchema = Type.Object({ + user_id: Type.Number({ description: '用户QQ' }), + uid: Type.String({ description: 'UID' }), + nickname: Type.String({ description: '昵称' }), + age: Type.Number({ description: '年龄' }), + qid: Type.String({ description: 'QID' }), + qqLevel: Type.Number({ description: 'QQ等级' }), + sex: Type.String({ description: '性别' }), + long_nick: Type.String({ description: '个性签名' }), + reg_time: Type.Number({ description: '注册时间' }), + is_vip: Type.Boolean({ description: '是否VIP' }), + is_years_vip: Type.Boolean({ description: '是否年费VIP' }), + vip_level: Type.Number({ description: 'VIP等级' }), + remark: Type.String({ description: '备注' }), + status: Type.Number({ description: '状态' }), + login_days: Type.Number({ description: '登录天数' }), +}, { description: '陌生人信息' }); + +type ReturnType = Static; + +export default class GoCQHTTPGetStrangerInfo extends OneBotAction { override actionName = ActionName.GoCQHTTP_GetStrangerInfo; - override payloadSchema = SchemaData; - async _handle (payload: Payload) { + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取陌生人信息'; + override actionDescription = '获取指定非好友用户的信息'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.GetStrangerInfo.payload; + override returnExample = GoCQHTTPActionsExamples.GetStrangerInfo.response; + + async _handle (payload: PayloadType): Promise { const user_id = payload.user_id.toString(); const isNocache = typeof payload.no_cache === 'string' ? payload.no_cache === 'true' : !!payload.no_cache; const extendData = await this.core.apis.UserApi.getUserDetailInfoByUin(user_id); @@ -37,11 +65,11 @@ export default class GoCQHTTPGetStrangerInfo extends OneBotAction; +export type GoCQHTTPCheckUrlSafelyPayload = Static; -export class GoCQHTTPCheckUrlSafely extends OneBotAction { +export const GoCQHTTPCheckUrlSafelyReturnSchema = Type.Object({ + level: Type.Number({ description: '安全等级 (1: 安全, 2: 未知, 3: 危险)' }), +}); + +export type GoCQHTTPCheckUrlSafelyReturn = Static; + +export class GoCQHTTPCheckUrlSafely extends OneBotAction { override actionName = ActionName.GoCQHTTP_CheckUrlSafely; - override payloadSchema = SchemaData; + override payloadSchema = GoCQHTTPCheckUrlSafelyPayloadSchema; + override returnSchema = GoCQHTTPCheckUrlSafelyReturnSchema; + override actionSummary = '检查URL安全性'; + override actionDescription = '检查指定URL的安全等级'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.GoCQHTTPCheckUrlSafely.payload; + override returnExample = GoCQHTTPActionsExamples.GoCQHTTPCheckUrlSafely.response; async _handle () { return { level: 1 }; diff --git a/packages/napcat-onebot/action/go-cqhttp/GoCQHTTPDeleteFriend.ts b/packages/napcat-onebot/action/go-cqhttp/GoCQHTTPDeleteFriend.ts index c37a172e..a47baa07 100644 --- a/packages/napcat-onebot/action/go-cqhttp/GoCQHTTPDeleteFriend.ts +++ b/packages/napcat-onebot/action/go-cqhttp/GoCQHTTPDeleteFriend.ts @@ -1,21 +1,28 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; +import { GoCQHTTPActionsExamples } from '../example/GoCQHTTPActionsExamples'; -const SchemaData = Type.Object({ - friend_id: Type.Optional(Type.Union([Type.String(), Type.Number()])), - user_id: Type.Optional(Type.Union([Type.String(), Type.Number()])), - temp_block: Type.Optional(Type.Boolean()), - temp_both_del: Type.Optional(Type.Boolean()), +export const GoCQHTTPDeleteFriendPayloadSchema = Type.Object({ + friend_id: Type.Optional(Type.Union([Type.String(), Type.Number()], { description: '好友 QQ 号' })), + user_id: Type.Optional(Type.Union([Type.String(), Type.Number()], { description: '用户 QQ 号' })), + temp_block: Type.Optional(Type.Boolean({ description: '是否加入黑名单' })), + temp_both_del: Type.Optional(Type.Boolean({ description: '是否双向删除' })), }); -type Payload = Static; +export type GoCQHTTPDeleteFriendPayload = Static; -export class GoCQHTTPDeleteFriend extends OneBotAction { +export class GoCQHTTPDeleteFriend extends OneBotAction { override actionName = ActionName.GoCQHTTP_DeleteFriend; - override payloadSchema = SchemaData; + override payloadSchema = GoCQHTTPDeleteFriendPayloadSchema; + override returnSchema = Type.Any(); + override actionSummary = '删除好友'; + override actionDescription = '从好友列表中删除指定用户'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.GoCQHTTPDeleteFriend.payload; + override returnExample = GoCQHTTPActionsExamples.GoCQHTTPDeleteFriend.response; - async _handle (payload: Payload) { + async _handle (payload: GoCQHTTPDeleteFriendPayload) { const uin = payload.friend_id ?? payload.user_id ?? ''; const uid = await this.core.apis.UserApi.getUidByUinV2(uin.toString()); diff --git a/packages/napcat-onebot/action/go-cqhttp/GoCQHTTPGetModelShow.ts b/packages/napcat-onebot/action/go-cqhttp/GoCQHTTPGetModelShow.ts index d8123af4..82c24697 100644 --- a/packages/napcat-onebot/action/go-cqhttp/GoCQHTTPGetModelShow.ts +++ b/packages/napcat-onebot/action/go-cqhttp/GoCQHTTPGetModelShow.ts @@ -1,23 +1,34 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; +import { GoCQHTTPActionsExamples } from '../example/GoCQHTTPActionsExamples'; -const SchemaData = Type.Object({ - model: Type.Optional(Type.String()), +export const GoCQHTTPGetModelShowPayloadSchema = Type.Object({ + model: Type.Optional(Type.String({ description: '模型名称' })), }); -type Payload = Static; +export type GoCQHTTPGetModelShowPayload = Static; -export class GoCQHTTPGetModelShow extends OneBotAction> { +export const GoCQHTTPGetModelShowReturnSchema = Type.Array(Type.Object({ + variants: Type.Object({ + model_show: Type.String({ description: '显示名称' }), + need_pay: Type.Boolean({ description: '是否需要付费' }), + }), +}), { description: '机型显示列表' }); + +export type GoCQHTTPGetModelShowReturn = Static; + +export class GoCQHTTPGetModelShow extends OneBotAction { override actionName = ActionName.GoCQHTTP_GetModelShow; - override payloadSchema = SchemaData; + override payloadSchema = GoCQHTTPGetModelShowPayloadSchema; + override returnSchema = GoCQHTTPGetModelShowReturnSchema; + override actionSummary = '获取机型显示'; + override actionDescription = '获取当前账号可用的设备机型显示名称列表'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.GoCQHTTPGetModelShow.payload; + override returnExample = GoCQHTTPActionsExamples.GoCQHTTPGetModelShow.response; - async _handle (payload: Payload) { + async _handle (payload: GoCQHTTPGetModelShowPayload) { if (!payload.model) { payload.model = 'napcat'; } diff --git a/packages/napcat-onebot/action/go-cqhttp/GoCQHTTPSetModelShow.ts b/packages/napcat-onebot/action/go-cqhttp/GoCQHTTPSetModelShow.ts index a104f897..90ce0af4 100644 --- a/packages/napcat-onebot/action/go-cqhttp/GoCQHTTPSetModelShow.ts +++ b/packages/napcat-onebot/action/go-cqhttp/GoCQHTTPSetModelShow.ts @@ -1,8 +1,18 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; +import { Type } from '@sinclair/typebox'; +import { GoCQHTTPActionsExamples } from '../example/GoCQHTTPActionsExamples'; + // 兼容性代码 export class GoCQHTTPSetModelShow extends OneBotAction { override actionName = ActionName.GoCQHTTP_SetModelShow; + override payloadSchema = Type.Object({}); + override returnSchema = Type.Null(); + override actionSummary = '设置机型'; + override actionDescription = '设置当前账号的设备机型名称'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.GoCQHTTPSetModelShow.payload; + override returnExample = GoCQHTTPActionsExamples.GoCQHTTPSetModelShow.response; async _handle () { diff --git a/packages/napcat-onebot/action/go-cqhttp/QuickAction.ts b/packages/napcat-onebot/action/go-cqhttp/QuickAction.ts index 1e9f1558..e1e26147 100644 --- a/packages/napcat-onebot/action/go-cqhttp/QuickAction.ts +++ b/packages/napcat-onebot/action/go-cqhttp/QuickAction.ts @@ -1,19 +1,77 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { QuickAction, QuickActionEvent } from '@/napcat-onebot/types'; +import { Static, Type } from '@sinclair/typebox'; +import { GoCQHTTPActionsExamples } from '../example/GoCQHTTPActionsExamples'; -interface Payload { - context: QuickActionEvent, - operation: QuickAction -} +const SenderSchema = Type.Object({ + user_id: Type.String({ description: '用户ID' }), + nickname: Type.String({ description: '昵称' }), + sex: Type.Optional(Type.String({ description: '性别' })), + age: Type.Optional(Type.Number({ description: '年龄' })), + card: Type.Optional(Type.String({ description: '群名片' })), + level: Type.Optional(Type.String({ description: '群等级' })), + role: Type.Optional(Type.String({ description: '群角色' })), +}); -export class GoCQHTTPHandleQuickAction extends OneBotAction { +// 定义 QuickAction 的详细 Schema +const QuickActionSchema = Type.Object({ + reply: Type.Optional(Type.String({ description: '回复内容' })), + auto_escape: Type.Optional(Type.Boolean({ description: '是否作为纯文本发送' })), + at_sender: Type.Optional(Type.Boolean({ description: '是否 @ 发送者' })), + delete: Type.Optional(Type.Boolean({ description: '是否撤回该消息' })), + kick: Type.Optional(Type.Boolean({ description: '是否踢出发送者' })), + ban: Type.Optional(Type.Boolean({ description: '是否禁言发送者' })), + ban_duration: Type.Optional(Type.Number({ description: '禁言时长' })), + approve: Type.Optional(Type.Boolean({ description: '是否同意请求/加群' })), + remark: Type.Optional(Type.String({ description: '好友备注' })), + reason: Type.Optional(Type.String({ description: '拒绝理由' })), +}, { description: '快速操作内容' }); + +// 定义 QuickActionEvent 的详细 Schema +const QuickActionEventSchema = Type.Object({ + time: Type.Number({ description: '事件发生时间' }), + self_id: Type.Number({ description: '收到事件的机器人 QQ 号' }), + post_type: Type.String({ description: '上报类型' }), + message_type: Type.Optional(Type.String({ description: '消息类型' })), + sub_type: Type.Optional(Type.String({ description: '消息子类型' })), + user_id: Type.String({ description: '发送者 QQ 号' }), + group_id: Type.Optional(Type.String({ description: '群号' })), + message_id: Type.Optional(Type.Number({ description: '消息 ID' })), + message_seq: Type.Optional(Type.Number({ description: '消息序列号' })), + real_id: Type.Optional(Type.Number({ description: '真实消息 ID' })), + sender: Type.Optional(SenderSchema), + message: Type.Optional(Type.Any({ description: '消息内容' })), + message_format: Type.Optional(Type.String({ description: '消息格式' })), + raw_message: Type.Optional(Type.String({ description: '原始消息内容' })), + font: Type.Optional(Type.Number({ description: '字体' })), + notice_type: Type.Optional(Type.String({ description: '通知类型' })), + meta_event_type: Type.Optional(Type.String({ description: '元事件类型' })), +}, { description: '事件上下文' }); + +export const GoCQHTTPHandleQuickActionPayloadSchema = Type.Object({ + context: QuickActionEventSchema, + operation: QuickActionSchema, +}); + +export type GoCQHTTPHandleQuickActionPayload = { + context: QuickActionEvent; + operation: QuickAction; +} & Static; + +export class GoCQHTTPHandleQuickAction extends OneBotAction { override actionName = ActionName.GoCQHTTP_HandleQuickAction; + override payloadSchema = GoCQHTTPHandleQuickActionPayloadSchema; + override returnSchema = Type.Null(); + override actionSummary = '处理快速操作'; + override actionDescription = '处理来自事件上报的快速操作请求'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.QuickAction.payload; + override returnExample = GoCQHTTPActionsExamples.QuickAction.response; - async _handle (payload: Payload): Promise { + async _handle (payload: GoCQHTTPHandleQuickActionPayload): Promise { this.obContext.apis.QuickActionApi .handleQuickOperation(payload.context, payload.operation) .catch(e => this.core.context.logger.logError(e)); - return null; } } diff --git a/packages/napcat-onebot/action/go-cqhttp/SendForwardMsg.ts b/packages/napcat-onebot/action/go-cqhttp/SendForwardMsg.ts index 1a2e7f4a..abbe57bd 100644 --- a/packages/napcat-onebot/action/go-cqhttp/SendForwardMsg.ts +++ b/packages/napcat-onebot/action/go-cqhttp/SendForwardMsg.ts @@ -1,32 +1,62 @@ -import { ContextMode, normalize, ReturnDataType, SendMsgBase } from '@/napcat-onebot/action/msg/SendMsg'; -import { OB11PostSendMsg } from '@/napcat-onebot/types'; +import { OB11MessageMixType } from '@/napcat-onebot/types'; +import { ContextMode, normalize, ReturnDataType, SendMsgBase, SendMsgPayload } from '@/napcat-onebot/action/msg/SendMsg'; import { ActionName } from '@/napcat-onebot/action/router'; // 未验证 +type GoCQHTTPSendForwardMsgPayload = SendMsgPayload & { messages?: OB11MessageMixType; }; + export class GoCQHTTPSendForwardMsgBase extends SendMsgBase { - protected override async check (payload: OB11PostSendMsg) { + protected override async check (payload: GoCQHTTPSendForwardMsgPayload) { if (payload.messages) payload.message = normalize(payload.messages); return super.check(payload); } } export class GoCQHTTPSendForwardMsg extends GoCQHTTPSendForwardMsgBase { override actionName = ActionName.GoCQHTTP_SendForwardMsg; + override actionSummary = '发送合并转发消息'; + override actionDescription = '发送合并转发消息'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = { + group_id: '123456789', + messages: [] + }; + override returnExample = { + message_id: 123456 + }; - protected override async check (payload: OB11PostSendMsg) { + protected override async check (payload: GoCQHTTPSendForwardMsgPayload) { if (payload.messages) payload.message = normalize(payload.messages); return super.check(payload); } } export class GoCQHTTPSendPrivateForwardMsg extends GoCQHTTPSendForwardMsgBase { override actionName = ActionName.GoCQHTTP_SendPrivateForwardMsg; - override async _handle (payload: OB11PostSendMsg): Promise { + override actionSummary = '发送私聊合并转发消息'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = { + user_id: '123456789', + messages: [] + }; + override returnExample = { + message_id: 123456 + }; + override async _handle (payload: GoCQHTTPSendForwardMsgPayload): Promise { return this.base_handle(payload, ContextMode.Private); } } export class GoCQHTTPSendGroupForwardMsg extends GoCQHTTPSendForwardMsgBase { override actionName = ActionName.GoCQHTTP_SendGroupForwardMsg; - override async _handle (payload: OB11PostSendMsg): Promise { + override actionSummary = '发送群合并转发消息'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = { + group_id: '123456789', + messages: [] + }; + override returnExample = { + message_id: 123456 + }; + override async _handle (payload: GoCQHTTPSendForwardMsgPayload): Promise { return this.base_handle(payload, ContextMode.Group); } } diff --git a/packages/napcat-onebot/action/go-cqhttp/SendGroupNotice.ts b/packages/napcat-onebot/action/go-cqhttp/SendGroupNotice.ts index 13ca961f..9e7a5465 100644 --- a/packages/napcat-onebot/action/go-cqhttp/SendGroupNotice.ts +++ b/packages/napcat-onebot/action/go-cqhttp/SendGroupNotice.ts @@ -3,24 +3,32 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { unlink } from 'node:fs/promises'; import { Static, Type } from '@sinclair/typebox'; +import { GoCQHTTPActionsExamples } from '../example/GoCQHTTPActionsExamples'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - content: Type.String(), - image: Type.Optional(Type.String()), - pinned: Type.Union([Type.Number(), Type.String()], { default: 0 }), - type: Type.Union([Type.Number(), Type.String()], { default: 1 }), - confirm_required: Type.Union([Type.Number(), Type.String()], { default: 1 }), - is_show_edit_card: Type.Union([Type.Number(), Type.String()], { default: 0 }), - tip_window_type: Type.Union([Type.Number(), Type.String()], { default: 0 }), +export const SendGroupNoticePayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + content: Type.String({ description: '公告内容' }), + image: Type.Optional(Type.String({ description: '公告图片路径或 URL' })), + pinned: Type.Union([Type.Number(), Type.String()], { default: 0, description: '是否置顶 (0/1)' }), + type: Type.Union([Type.Number(), Type.String()], { default: 1, description: '类型 (默认为 1)' }), + confirm_required: Type.Union([Type.Number(), Type.String()], { default: 1, description: '是否需要确认 (0/1)' }), + is_show_edit_card: Type.Union([Type.Number(), Type.String()], { default: 0, description: '是否显示修改群名片引导 (0/1)' }), + tip_window_type: Type.Union([Type.Number(), Type.String()], { default: 0, description: '弹窗类型 (默认为 0)' }), }); -type Payload = Static; +export type SendGroupNoticePayload = Static; -export class SendGroupNotice extends OneBotAction { +export class SendGroupNotice extends OneBotAction { override actionName = ActionName.GoCQHTTP_SendGroupNotice; - override payloadSchema = SchemaData; - async _handle (payload: Payload) { + override payloadSchema = SendGroupNoticePayloadSchema; + override returnSchema = Type.Null(); + override actionSummary = '发送群公告'; + override actionDescription = '在指定群聊中发布新的公告'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.SendGroupNotice.payload; + override returnExample = GoCQHTTPActionsExamples.SendGroupNotice.response; + + async _handle (payload: SendGroupNoticePayload) { let UploadImage: { id: string, width: number, height: number; } | undefined; if (payload.image) { // 公告图逻辑 @@ -59,6 +67,5 @@ export class SendGroupNotice extends OneBotAction { if (!publishGroupBulletinResult || publishGroupBulletinResult.ec !== 0) { throw new Error(`设置群公告失败,错误信息:${publishGroupBulletinResult?.em}`); } - return null; } } diff --git a/packages/napcat-onebot/action/go-cqhttp/SetGroupPortrait.ts b/packages/napcat-onebot/action/go-cqhttp/SetGroupPortrait.ts index c81e9344..fdc8f393 100644 --- a/packages/napcat-onebot/action/go-cqhttp/SetGroupPortrait.ts +++ b/packages/napcat-onebot/action/go-cqhttp/SetGroupPortrait.ts @@ -3,19 +3,33 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { checkFileExistV2, uriToLocalFile } from 'napcat-common/src/file'; import { Static, Type } from '@sinclair/typebox'; import fs from 'node:fs/promises'; -import { GeneralCallResult } from 'napcat-core'; -const SchemaData = Type.Object({ - file: Type.String(), - group_id: Type.Union([Type.Number(), Type.String()]), +import { GoCQHTTPActionsExamples } from '../example/GoCQHTTPActionsExamples'; + +export const SetGroupPortraitPayloadSchema = Type.Object({ + file: Type.String({ description: '头像文件路径或 URL' }), + group_id: Type.String({ description: '群号' }), }); -type Payload = Static; +export type SetGroupPortraitPayload = Static; -export default class SetGroupPortrait extends OneBotAction { +const ReturnSchema = Type.Object({ + result: Type.Number(), + errMsg: Type.String(), +}, { description: '设置结果' }); + +export type ReturnType = Static; + +export default class SetGroupPortrait extends OneBotAction { override actionName = ActionName.SetGroupPortrait; - override payloadSchema = SchemaData; + override payloadSchema = SetGroupPortraitPayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '设置群头像'; + override actionDescription = '修改指定群聊的头像'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.SetGroupPortrait.payload; + override returnExample = GoCQHTTPActionsExamples.SetGroupPortrait.response; - async _handle (payload: Payload): Promise { + async _handle (payload: SetGroupPortraitPayload): Promise { const { path, success } = (await uriToLocalFile(this.core.NapCatTempPath, payload.file)); if (!success) { throw new Error(`头像${payload.file}设置失败,file字段可能格式不正确`); @@ -27,12 +41,15 @@ export default class SetGroupPortrait extends OneBotAction { }); throw new Error(`头像${payload.file}设置失败,无法获取头像,文件可能不存在`); diff --git a/packages/napcat-onebot/action/go-cqhttp/SetQQProfile.ts b/packages/napcat-onebot/action/go-cqhttp/SetQQProfile.ts index 2d23286b..13ca70cd 100644 --- a/packages/napcat-onebot/action/go-cqhttp/SetQQProfile.ts +++ b/packages/napcat-onebot/action/go-cqhttp/SetQQProfile.ts @@ -1,20 +1,26 @@ -import { NTQQUserApi } from 'napcat-core/apis'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; +import { GoCQHTTPActionsExamples } from '../example/GoCQHTTPActionsExamples'; -const SchemaData = Type.Object({ - nickname: Type.String(), - personal_note: Type.Optional(Type.String()), - sex: Type.Optional(Type.Union([Type.Number(), Type.String()])), // 传Sex值?建议传0 +export const SetQQProfilePayloadSchema = Type.Object({ + nickname: Type.String({ description: '昵称' }), + personal_note: Type.Optional(Type.String({ description: '个性签名' })), + sex: Type.Optional(Type.Union([Type.Number(), Type.String()], { description: '性别 (0: 未知, 1: 男, 2: 女)' })), // 传Sex值?建议传0 }); -type Payload = Static; -export class SetQQProfile extends OneBotAction> | null> { +export type SetQQProfilePayload = Static; +export class SetQQProfile extends OneBotAction { override actionName = ActionName.SetQQProfile; - override payloadSchema = SchemaData; + override payloadSchema = SetQQProfilePayloadSchema; + override returnSchema = Type.Any({ description: '设置结果' }); + override actionSummary = '设置QQ资料'; + override actionDescription = '修改当前账号的昵称、个性签名等资料'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.SetQQProfile.payload; + override returnExample = GoCQHTTPActionsExamples.SetQQProfile.response; - async _handle (payload: Payload) { + async _handle (payload: SetQQProfilePayload) { const self = this.core.selfInfo; const OldProfile = await this.core.apis.UserApi.getUserDetailInfo(self.uid); return await this.core.apis.UserApi.modifySelfProfile({ diff --git a/packages/napcat-onebot/action/go-cqhttp/UploadGroupFile.ts b/packages/napcat-onebot/action/go-cqhttp/UploadGroupFile.ts index 11bfe4b9..fde2b349 100644 --- a/packages/napcat-onebot/action/go-cqhttp/UploadGroupFile.ts +++ b/packages/napcat-onebot/action/go-cqhttp/UploadGroupFile.ts @@ -5,27 +5,36 @@ import fs from 'fs'; import { uriToLocalFile } from 'napcat-common/src/file'; import { SendMessageContext } from '@/napcat-onebot/api'; import { Static, Type } from '@sinclair/typebox'; +import { GoCQHTTPActionsExamples } from '../example/GoCQHTTPActionsExamples'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - file: Type.String(), - name: Type.String(), - folder: Type.Optional(Type.String()), - folder_id: Type.Optional(Type.String()), // 临时扩展 - upload_file: Type.Boolean({ default: true }), +export const GoCQHTTPUploadGroupFilePayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + file: Type.String({ description: '资源路径或URL' }), + name: Type.String({ description: '文件名' }), + folder: Type.Optional(Type.String({ description: '父目录 ID' })), + folder_id: Type.Optional(Type.String({ description: '父目录 ID (兼容性字段)' })), // 临时扩展 + upload_file: Type.Boolean({ default: true, description: '是否执行上传' }), }); -type Payload = Static; +export type GoCQHTTPUploadGroupFilePayload = Static; -interface UploadGroupFileResponse { - file_id: string | null; -} +export const GoCQHTTPUploadGroupFileReturnSchema = Type.Object({ + file_id: Type.Union([Type.String(), Type.Null()], { description: '文件 ID' }), +}); -export default class GoCQHTTPUploadGroupFile extends OneBotAction { +export type GoCQHTTPUploadGroupFileResponse = Static; + +export default class GoCQHTTPUploadGroupFile extends OneBotAction { override actionName = ActionName.GoCQHTTP_UploadGroupFile; - override payloadSchema = SchemaData; + override payloadSchema = GoCQHTTPUploadGroupFilePayloadSchema; + override returnSchema = GoCQHTTPUploadGroupFileReturnSchema; + override actionSummary = '上传群文件'; + override actionDescription = '上传资源路径或URL指定的文件到指定群聊的文件系统中'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.UploadGroupFile.payload; + override returnExample = GoCQHTTPActionsExamples.UploadGroupFile.response; - async _handle (payload: Payload): Promise { + async _handle (payload: GoCQHTTPUploadGroupFilePayload): Promise { let file = payload.file; if (fs.existsSync(file)) { file = `file://${file}`; diff --git a/packages/napcat-onebot/action/go-cqhttp/UploadPrivateFile.ts b/packages/napcat-onebot/action/go-cqhttp/UploadPrivateFile.ts index 9ad46aec..5375fead 100644 --- a/packages/napcat-onebot/action/go-cqhttp/UploadPrivateFile.ts +++ b/packages/napcat-onebot/action/go-cqhttp/UploadPrivateFile.ts @@ -6,25 +6,34 @@ import { uriToLocalFile } from 'napcat-common/src/file'; import { SendMessageContext } from '@/napcat-onebot/api'; import { ContextMode, createContext } from '@/napcat-onebot/action/msg/SendMsg'; import { Static, Type } from '@sinclair/typebox'; +import { GoCQHTTPActionsExamples } from '../example/GoCQHTTPActionsExamples'; -const SchemaData = Type.Object({ - user_id: Type.Union([Type.Number(), Type.String()]), - file: Type.String(), - name: Type.String(), - upload_file: Type.Boolean({ default: true }), +export const GoCQHTTPUploadPrivateFilePayloadSchema = Type.Object({ + user_id: Type.String({ description: '用户 QQ' }), + file: Type.String({ description: '资源路径或URL' }), + name: Type.String({ description: '文件名' }), + upload_file: Type.Boolean({ default: true, description: '是否执行上传' }), }); -type Payload = Static; +export type GoCQHTTPUploadPrivateFilePayload = Static; -interface UploadPrivateFileResponse { - file_id: string | null; -} +export const GoCQHTTPUploadPrivateFileReturnSchema = Type.Object({ + file_id: Type.Union([Type.String(), Type.Null()], { description: '文件 ID' }), +}); -export default class GoCQHTTPUploadPrivateFile extends OneBotAction { +export type GoCQHTTPUploadPrivateFileResponse = Static; + +export default class GoCQHTTPUploadPrivateFile extends OneBotAction { override actionName = ActionName.GOCQHTTP_UploadPrivateFile; - override payloadSchema = SchemaData; + override payloadSchema = GoCQHTTPUploadPrivateFilePayloadSchema; + override returnSchema = GoCQHTTPUploadPrivateFileReturnSchema; + override actionSummary = '上传私聊文件'; + override actionDescription = '上传本地文件到指定私聊会话中'; + override actionTags = ['Go-CQHTTP']; + override payloadExample = GoCQHTTPActionsExamples.UploadPrivateFile.payload; + override returnExample = GoCQHTTPActionsExamples.UploadPrivateFile.response; - async getPeer (payload: Payload): Promise { + async getPeer (payload: GoCQHTTPUploadPrivateFilePayload): Promise { if (payload.user_id) { const peerUid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString()); if (!peerUid) { @@ -36,7 +45,7 @@ export default class GoCQHTTPUploadPrivateFile extends OneBotAction { + async _handle (payload: GoCQHTTPUploadPrivateFilePayload): Promise { let file = payload.file; if (fs.existsSync(file)) { file = `file://${file}`; diff --git a/packages/napcat-onebot/action/group/DelEssenceMsg.ts b/packages/napcat-onebot/action/group/DelEssenceMsg.ts index 0dcb5837..51788c82 100644 --- a/packages/napcat-onebot/action/group/DelEssenceMsg.ts +++ b/packages/napcat-onebot/action/group/DelEssenceMsg.ts @@ -3,19 +3,32 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { MessageUnique } from 'napcat-common/src/message-unique'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - message_id: Type.Optional(Type.Union([Type.Number(), Type.String()])), - msg_seq: Type.Optional(Type.String()), - msg_random: Type.Optional(Type.String()), - group_id: Type.Optional(Type.String()), +import { GroupActionsExamples } from '../example/GroupActionsExamples'; + +const PayloadSchema = Type.Object({ + message_id: Type.Optional(Type.Union([Type.Number(), Type.String()], { description: '消息ID' })), + msg_seq: Type.Optional(Type.String({ description: '消息序号' })), + msg_random: Type.Optional(Type.String({ description: '消息随机数' })), + group_id: Type.Optional(Type.String({ description: '群号' })), }); -type Payload = Static; -export default class DelEssenceMsg extends OneBotAction { - override actionName = ActionName.DelEssenceMsg; - override payloadSchema = SchemaData; +type PayloadType = Static; - async _handle (payload: Payload): Promise { +const ReturnSchema = Type.Any({ description: '操作结果' }); + +type ReturnType = Static; + +export default class DelEssenceMsg extends OneBotAction { + override actionName = ActionName.DelEssenceMsg; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '移出精华消息'; + override actionDescription = '将一条消息从群精华消息列表中移出'; + override actionTags = ['群组接口']; + override payloadExample = GroupActionsExamples.DelEssenceMsg.payload; + override returnExample = GroupActionsExamples.DelEssenceMsg.response; + + async _handle (payload: PayloadType): Promise { // 如果直接提供了 msg_seq, msg_random, group_id,优先使用 if (payload.msg_seq && payload.msg_random && payload.group_id) { return await this.core.apis.GroupApi.removeGroupEssenceBySeq( @@ -34,7 +47,7 @@ export default class DelEssenceMsg extends OneBotAction { if (!msg) { const data = this.core.apis.GroupApi.essenceLRU.getValue(+payload.message_id); if (!data) throw new Error('消息不存在'); - const { msg_seq, msg_random, group_id } = JSON.parse(data) as { msg_seq: string, msg_random: string, group_id: string }; + const { msg_seq, msg_random, group_id } = JSON.parse(data) as { msg_seq: string, msg_random: string, group_id: string; }; return await this.core.apis.GroupApi.removeGroupEssenceBySeq(group_id, msg_seq, msg_random); } return await this.core.apis.GroupApi.removeGroupEssence( diff --git a/packages/napcat-onebot/action/group/DelGroupNotice.ts b/packages/napcat-onebot/action/group/DelGroupNotice.ts index 024c3891..eb17a2aa 100644 --- a/packages/napcat-onebot/action/group/DelGroupNotice.ts +++ b/packages/napcat-onebot/action/group/DelGroupNotice.ts @@ -2,18 +2,30 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - notice_id: Type.String(), +import { GroupActionsExamples } from '../example/GroupActionsExamples'; + +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + notice_id: Type.String({ description: '公告ID' }), }); -type Payload = Static; +type PayloadType = Static; -export class DelGroupNotice extends OneBotAction { +const ReturnSchema = Type.Any({ description: '操作结果' }); + +type ReturnType = Static; + +export class DelGroupNotice extends OneBotAction { override actionName = ActionName.DelGroupNotice; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '删除群公告'; + override actionDescription = '删除群聊中的公告'; + override actionTags = ['群组接口']; + override payloadExample = GroupActionsExamples.DelGroupNotice.payload; + override returnExample = GroupActionsExamples.DelGroupNotice.response; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { const group = payload.group_id.toString(); const noticeId = payload.notice_id; return await this.core.apis.GroupApi.deleteGroupBulletin(group, noticeId); diff --git a/packages/napcat-onebot/action/group/GetAiRecord.ts b/packages/napcat-onebot/action/group/GetAiRecord.ts index b96501fd..a0ea8e61 100644 --- a/packages/napcat-onebot/action/group/GetAiRecord.ts +++ b/packages/napcat-onebot/action/group/GetAiRecord.ts @@ -3,19 +3,33 @@ import { GetPacketStatusDepends } from '@/napcat-onebot/action/packet/GetPacketS import { AIVoiceChatType } from 'napcat-core/packet/entities/aiChat'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - character: Type.String(), - group_id: Type.Union([Type.Number(), Type.String()]), - text: Type.String(), +const PayloadSchema = Type.Object({ + character: Type.String({ description: '角色ID' }), + group_id: Type.String({ description: '群号' }), + text: Type.String({ description: '语音文本内容' }), }); -type Payload = Static; +type PayloadType = Static; -export class GetAiRecord extends GetPacketStatusDepends { +const ReturnSchema = Type.String({ description: '语音URL' }); + +type ReturnType = Static; + +export class GetAiRecord extends GetPacketStatusDepends { override actionName = ActionName.GetAiRecord; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取 AI 语音'; + override actionDescription = '通过 AI 语音引擎获取指定文本的语音 URL'; + override actionTags = ['AI 扩展']; + override payloadExample = { + character: 'ai_char_1', + group_id: '123456', + text: '你好' + }; + override returnExample = 'http://example.com/ai_voice.silk'; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { const rawRsp = await this.core.apis.PacketApi.pkt.operation.GetAiVoice(+payload.group_id, payload.character, payload.text, AIVoiceChatType.Sound); if (!rawRsp.msgInfoBody[0]) { throw new Error('No voice data'); diff --git a/packages/napcat-onebot/action/group/GetGroupDetailInfo.ts b/packages/napcat-onebot/action/group/GetGroupDetailInfo.ts index d9fdff2c..f948a92a 100644 --- a/packages/napcat-onebot/action/group/GetGroupDetailInfo.ts +++ b/packages/napcat-onebot/action/group/GetGroupDetailInfo.ts @@ -2,17 +2,36 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), +import { GroupActionsExamples } from '../example/GroupActionsExamples'; + +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), }); -type Payload = Static; +type PayloadType = Static; -export class GetGroupDetailInfo extends OneBotAction { +const ReturnSchema = Type.Object({ + group_id: Type.Number({ description: '群号' }), + group_name: Type.String({ description: '群名称' }), + member_count: Type.Number({ description: '成员数量' }), + max_member_count: Type.Number({ description: '最大成员数量' }), + group_all_shut: Type.Number({ description: '全员禁言状态' }), + group_remark: Type.String({ description: '群备注' }), +}, { description: '群详细信息' }); + +type ReturnType = Static; + +export class GetGroupDetailInfo extends OneBotAction { override actionName = ActionName.GetGroupDetailInfo; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取群详细信息'; + override actionDescription = '获取群聊的详细信息,包括成员数、最大成员数等'; + override actionTags = ['群组接口']; + override payloadExample = GroupActionsExamples.GetGroupDetailInfo.payload; + override returnExample = GroupActionsExamples.GetGroupDetailInfo.response; - async _handle (payload: Payload) { + async _handle (payload: PayloadType): Promise { const data = await this.core.apis.GroupApi.fetchGroupDetail(payload.group_id.toString()); return { ...data, diff --git a/packages/napcat-onebot/action/group/GetGroupEssence.ts b/packages/napcat-onebot/action/group/GetGroupEssence.ts index 9ae88c2b..f72f486f 100644 --- a/packages/napcat-onebot/action/group/GetGroupEssence.ts +++ b/packages/napcat-onebot/action/group/GetGroupEssence.ts @@ -5,16 +5,39 @@ import { MessageUnique } from 'napcat-common/src/message-unique'; import crypto from 'crypto'; import { Static, Type } from '@sinclair/typebox'; import { NetworkAdapterConfig } from '@/napcat-onebot/config/config'; +import { OB11MessageData, OB11MessageDataType } from '@/napcat-onebot/types'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), +import { GroupActionsExamples } from '../example/GroupActionsExamples'; + +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), }); -type Payload = Static; +type PayloadType = Static; -export class GetGroupEssence extends OneBotAction { +const ReturnSchema = Type.Array(Type.Object({ + msg_seq: Type.Number({ description: '消息序号' }), + msg_random: Type.Number({ description: '消息随机数' }), + sender_id: Type.Number({ description: '发送者QQ' }), + sender_nick: Type.String({ description: '发送者昵称' }), + operator_id: Type.Number({ description: '操作者QQ' }), + operator_nick: Type.String({ description: '操作者昵称' }), + message_id: Type.Number({ description: '消息ID' }), + operator_time: Type.Number({ description: '操作时间' }), + content: Type.Array(Type.Any(), { description: '消息内容' }), +}), { description: '精华消息列表' }); + +type ReturnType = Static; + +export class GetGroupEssence extends OneBotAction { override actionName = ActionName.GoCQHTTP_GetEssenceMsg; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取群精华消息'; + override actionDescription = '获取指定群聊中的精华消息列表'; + override actionTags = ['群组接口']; + override payloadExample = GroupActionsExamples.GetGroupEssence.payload; + override returnExample = GroupActionsExamples.GetGroupEssence.response; private async msgSeqToMsgId (peer: Peer, msgSeq: string, msgRandom: string) { const replyMsgList = (await this.core.apis.MsgApi.getMsgsBySeqAndCount(peer, msgSeq, 1, true, true)).msgList.find((msg) => msg.msgSeq === msgSeq && msg.msgRandom === msgRandom); @@ -27,10 +50,10 @@ export class GetGroupEssence extends OneBotAction { }; } - async _handle (payload: Payload, _adapter: string, config: NetworkAdapterConfig) { + async _handle (payload: PayloadType, _adapter: string, config: NetworkAdapterConfig): Promise { const msglist = (await this.core.apis.WebApi.getGroupEssenceMsgAll(payload.group_id.toString())) .flatMap((e) => e?.data?.msg_list) - // 在群精华回空的时候会出现[null]的情况~ https://github.com/NapNeko/NapCatQQ/issues/1334 + // 在群精华回空的时候会出现[null]的情况~ https://github.com/NapNeko/NapCatQQ/issues/1334 .filter(Boolean); if (!msglist) { throw new Error('获取失败'); @@ -42,6 +65,15 @@ export class GetGroupEssence extends OneBotAction { }, msg.msg_seq.toString(), msg.msg_random.toString()); if (msgOriginData) { const { id: message_id, msg: rawMessage } = msgOriginData; + const parsed = await this.obContext.apis.MsgApi.parseMessage(rawMessage, config.messagePostFormat); + let content: OB11MessageData[] = []; + if (parsed) { + if (Array.isArray(parsed.message)) { + content = parsed.message; + } else { + content = [{ type: OB11MessageDataType.text, data: { text: parsed.message } }]; + } + } return { msg_seq: msg.msg_seq, msg_random: msg.msg_random, @@ -51,7 +83,7 @@ export class GetGroupEssence extends OneBotAction { operator_nick: msg.add_digest_nick, message_id, operator_time: msg.add_digest_time, - content: (await this.obContext.apis.MsgApi.parseMessage(rawMessage, config.messagePostFormat))?.message, + content, }; } const msgTempData = JSON.stringify({ @@ -75,24 +107,25 @@ export class GetGroupEssence extends OneBotAction { operator_nick: msg.add_digest_nick, message_id: shortId, operator_time: msg.add_digest_time, - content: msg.msg_content.map((msg) => { + content: msg.msg_content.map((msg): OB11MessageData | undefined => { if (msg.msg_type === 1) { return { - type: 'text', + type: OB11MessageDataType.text, data: { - text: msg?.text, + text: msg?.text ?? '', }, }; } else if (msg.msg_type === 3) { return { - type: 'image', + type: OB11MessageDataType.image, data: { + file: '', url: msg?.image_url, }, }; } return undefined; - }).filter(e => e !== undefined), + }).filter((e): e is OB11MessageData => e !== undefined), }; })); } diff --git a/packages/napcat-onebot/action/group/GetGroupIgnoredNotifies.ts b/packages/napcat-onebot/action/group/GetGroupIgnoredNotifies.ts index 2bab18f1..1c719dc7 100644 --- a/packages/napcat-onebot/action/group/GetGroupIgnoredNotifies.ts +++ b/packages/napcat-onebot/action/group/GetGroupIgnoredNotifies.ts @@ -1,20 +1,37 @@ import { GroupNotifyMsgStatus } from 'napcat-core'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; -import { Notify } from '@/napcat-onebot/types'; +import { Static, Type } from '@sinclair/typebox'; -interface RetData { - invited_requests: Notify[]; - InvitedRequest: Notify[]; - join_requests: Notify[]; -} +const PayloadSchema = Type.Object({}, { description: '群忽略通知负载' }); -export class GetGroupIgnoredNotifies extends OneBotAction { +type PayloadType = Static; + +const ReturnSchema = Type.Object({ + invited_requests: Type.Array(Type.Any(), { description: '邀请请求列表' }), + InvitedRequest: Type.Array(Type.Any(), { description: '邀请请求列表' }), + join_requests: Type.Array(Type.Any(), { description: '加入请求列表' }), +}, { description: '群忽略通知结果' }); + +type ReturnType = Static; + +export class GetGroupIgnoredNotifies extends OneBotAction { override actionName = ActionName.GetGroupIgnoredNotifies; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取群忽略通知'; + override actionDescription = '获取被忽略的入群申请和邀请通知'; + override actionTags = ['群组接口']; + override payloadExample = {}; + override returnExample = { + invited_requests: [], + InvitedRequest: [], + join_requests: [] + }; - async _handle (): Promise { + async _handle (): Promise { const SingleScreenNotifies = await this.core.apis.GroupApi.getSingleScreenNotifies(false, 50); - const retData: RetData = { invited_requests: [], InvitedRequest: [], join_requests: [] }; + const retData: ReturnType = { invited_requests: [], InvitedRequest: [], join_requests: [] }; const notifyPromises = SingleScreenNotifies.map(async (SSNotify) => { const invitorUin = SSNotify.user1?.uid ? +await this.core.apis.UserApi.getUinByUidV2(SSNotify.user1.uid) : 0; diff --git a/packages/napcat-onebot/action/group/GetGroupInfo.ts b/packages/napcat-onebot/action/group/GetGroupInfo.ts index 27df912a..b2a33794 100644 --- a/packages/napcat-onebot/action/group/GetGroupInfo.ts +++ b/packages/napcat-onebot/action/group/GetGroupInfo.ts @@ -1,20 +1,32 @@ -import { OB11Group } from '@/napcat-onebot/index'; import { OB11Construct } from '@/napcat-onebot/helper/data'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; +import { OB11GroupSchema } from '../schemas'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), +import { GroupActionsExamples } from '../example/GroupActionsExamples'; + +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), }); -type Payload = Static; +type PayloadType = Static; -class GetGroupInfo extends OneBotAction { +const ReturnSchema = OB11GroupSchema; + +type ReturnType = Static; + +class GetGroupInfo extends OneBotAction { override actionName = ActionName.GetGroupInfo; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取群信息'; + override actionDescription = '获取群聊的基本信息'; + override actionTags = ['群组接口']; + override payloadExample = GroupActionsExamples.GetGroupInfo.payload; + override returnExample = GroupActionsExamples.GetGroupInfo.response; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { const group = (await this.core.apis.GroupApi.getGroups()).find(e => e.groupCode === payload.group_id.toString()); if (!group) { const data = await this.core.apis.GroupApi.fetchGroupDetail(payload.group_id.toString()); diff --git a/packages/napcat-onebot/action/group/GetGroupList.ts b/packages/napcat-onebot/action/group/GetGroupList.ts index e89666a2..09ed639f 100644 --- a/packages/napcat-onebot/action/group/GetGroupList.ts +++ b/packages/napcat-onebot/action/group/GetGroupList.ts @@ -1,20 +1,31 @@ -import { OB11Group } from '@/napcat-onebot/index'; import { OB11Construct } from '@/napcat-onebot/helper/data'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; +import { OB11GroupSchema } from '../schemas'; +import { GroupActionsExamples } from '@/napcat-onebot/action/example/GroupActionsExamples'; -const SchemaData = Type.Object({ - no_cache: Type.Optional(Type.Union([Type.Boolean(), Type.String()])), +const PayloadSchema = Type.Object({ + no_cache: Type.Optional(Type.Union([Type.Boolean(), Type.String()], { description: '是否不使用缓存' })), }); -type Payload = Static; +type PayloadType = Static; -class GetGroupList extends OneBotAction { +const ReturnSchema = Type.Array(OB11GroupSchema, { description: '群列表' }); + +type ReturnType = Static; + +class GetGroupList extends OneBotAction { override actionName = ActionName.GetGroupList; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取群列表'; + override actionDescription = '获取当前帐号的群聊列表'; + override actionTags = ['群组接口']; + override payloadExample = GroupActionsExamples.GetGroupList.payload; + override returnExample = GroupActionsExamples.GetGroupList.response; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { return OB11Construct.groups( await this.core.apis.GroupApi.getGroups( typeof payload.no_cache === 'string' ? payload.no_cache === 'true' : !!payload.no_cache)); diff --git a/packages/napcat-onebot/action/group/GetGroupMemberInfo.ts b/packages/napcat-onebot/action/group/GetGroupMemberInfo.ts index 6fbc017b..4e65f411 100644 --- a/packages/napcat-onebot/action/group/GetGroupMemberInfo.ts +++ b/packages/napcat-onebot/action/group/GetGroupMemberInfo.ts @@ -1,20 +1,32 @@ -import { OB11GroupMember } from '@/napcat-onebot/index'; import { OB11Construct } from '@/napcat-onebot/helper/data'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; +import { OB11GroupMemberSchema } from '../schemas'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - user_id: Type.Union([Type.Number(), Type.String()]), - no_cache: Type.Optional(Type.Union([Type.Boolean(), Type.String()])), +import { GroupActionsExamples } from '../example/GroupActionsExamples'; + +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + user_id: Type.String({ description: 'QQ号' }), + no_cache: Type.Optional(Type.Union([Type.Boolean(), Type.String()], { description: '是否不使用缓存' })), }); -type Payload = Static; +type PayloadType = Static; -class GetGroupMemberInfo extends OneBotAction { +const ReturnSchema = OB11GroupMemberSchema; + +type ReturnType = Static; + +class GetGroupMemberInfo extends OneBotAction { override actionName = ActionName.GetGroupMemberInfo; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取群成员信息'; + override actionDescription = '获取群聊中指定成员的信息'; + override actionTags = ['群组接口']; + override payloadExample = GroupActionsExamples.GetGroupMemberInfo.payload; + override returnExample = GroupActionsExamples.GetGroupMemberInfo.response; private parseBoolean (value: boolean | string): boolean { return typeof value === 'string' ? value === 'true' : value; @@ -26,7 +38,7 @@ class GetGroupMemberInfo extends OneBotAction { return uid; } - private async getGroupMemberInfo (payload: Payload, uid: string, isNocache: boolean) { + private async getGroupMemberInfo (payload: PayloadType, uid: string, isNocache: boolean) { const groupMemberCache = this.core.apis.GroupApi.groupMemberCache.get(payload.group_id.toString()); const groupMember = groupMemberCache?.get(uid); @@ -40,7 +52,7 @@ class GetGroupMemberInfo extends OneBotAction { return info ? { ...groupMember, ...member, ...info } : member; } - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { const isNocache = this.parseBoolean(payload.no_cache ?? true); const uid = await this.getUid(payload.user_id); const member = await this.getGroupMemberInfo(payload, uid, isNocache); diff --git a/packages/napcat-onebot/action/group/GetGroupMemberList.ts b/packages/napcat-onebot/action/group/GetGroupMemberList.ts index 0c978a5c..99ffbbe9 100644 --- a/packages/napcat-onebot/action/group/GetGroupMemberList.ts +++ b/packages/napcat-onebot/action/group/GetGroupMemberList.ts @@ -1,22 +1,32 @@ -import { OB11GroupMember } from '@/napcat-onebot/index'; import { OB11Construct } from '@/napcat-onebot/helper/data'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; import { GroupMember } from 'napcat-core'; +import { GroupActionsExamples } from '../example/GroupActionsExamples'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - no_cache: Type.Optional(Type.Union([Type.Boolean(), Type.String()])), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + no_cache: Type.Optional(Type.Union([Type.Boolean(), Type.String()], { description: '是否不使用缓存' })), }); -type Payload = Static; +type PayloadType = Static; -export class GetGroupMemberList extends OneBotAction { +const ReturnSchema = Type.Array(Type.Any(), { description: '群成员列表' }); + +type ReturnType = Static; + +export class GetGroupMemberList extends OneBotAction { override actionName = ActionName.GetGroupMemberList; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取群成员列表'; + override actionDescription = '获取群聊中的所有成员列表'; + override actionTags = ['群组接口']; + override payloadExample = GroupActionsExamples.GetGroupMemberList.payload; + override returnExample = GroupActionsExamples.GetGroupMemberList.response; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { const groupIdStr = payload.group_id.toString(); const noCache = this.parseBoolean(payload.no_cache ?? false); const groupMembers = await this.getGroupMembers(groupIdStr, noCache); diff --git a/packages/napcat-onebot/action/group/GetGroupNotice.ts b/packages/napcat-onebot/action/group/GetGroupNotice.ts index eceab3c5..8667e69f 100644 --- a/packages/napcat-onebot/action/group/GetGroupNotice.ts +++ b/packages/napcat-onebot/action/group/GetGroupNotice.ts @@ -2,52 +2,48 @@ import { WebApiGroupNoticeFeed } from 'napcat-core'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -interface GroupNotice { - sender_id: number; - publish_time: number; - notice_id: string; - message: { - text: string; - // 保持一段时间兼容性 防止以往版本出现问题 后续版本可考虑移除 - image: Array<{ - height: string; - width: string; - id: string; - }>, - images: Array<{ - height: string; - width: string; - id: string; - }>; - }; - settings?: { - is_show_edit_card: number, - remind_ts: number, - tip_window_type: number, - confirm_required: number; - }; - read_num?: number; -} +import { GroupActionsExamples } from '../example/GroupActionsExamples'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), }); -type Payload = Static; +type PayloadType = Static; -type ApiGroupNotice = GroupNotice & WebApiGroupNoticeFeed; +const ReturnSchema = Type.Array(Type.Object({ + sender_id: Type.Number({ description: '发送者QQ' }), + publish_time: Type.Number({ description: '发布时间' }), + notice_id: Type.String({ description: '公告ID' }), + message: Type.Object({ + text: Type.String({ description: '文本内容' }), + image: Type.Array(Type.Any(), { description: '图片列表' }), + images: Type.Array(Type.Any(), { description: '图片列表' }), + }, { description: '公告内容' }), + settings: Type.Optional(Type.Any({ description: '设置项' })), + read_num: Type.Optional(Type.Number({ description: '阅读数' })), +}), { description: '群公告列表' }); -export class GetGroupNotice extends OneBotAction { +type ReturnType = Static; + +export type ApiGroupNotice = ReturnType[number] & WebApiGroupNoticeFeed; + +export class GetGroupNotice extends OneBotAction { override actionName = ActionName.GoCQHTTP_GetGroupNotice; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取群公告'; + override actionDescription = '获取指定群聊中的公告列表'; + override actionTags = ['群组接口']; + override payloadExample = GroupActionsExamples.GetGroupNotice.payload; + override returnExample = GroupActionsExamples.GetGroupNotice.response; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { const group = payload.group_id.toString(); const ret = await this.core.apis.WebApi.getGroupNotice(group); if (!ret) { throw new Error('获取公告失败'); } - const retNotices: GroupNotice[] = new Array(); + const retNotices: ReturnType = []; for (const key in ret.feeds) { if (!ret.feeds[key]) { continue; @@ -57,7 +53,7 @@ export class GetGroupNotice extends OneBotAction { return { id: pic.id, height: pic.h, width: pic.w }; }) || []; - const retNotice: GroupNotice = { + const retNotice: ReturnType[number] = { notice_id: retApiNotice.fid, sender_id: retApiNotice.u, publish_time: retApiNotice.pubt, diff --git a/packages/napcat-onebot/action/group/GetGroupShutList.ts b/packages/napcat-onebot/action/group/GetGroupShutList.ts index 97f00c0e..c641bb69 100644 --- a/packages/napcat-onebot/action/group/GetGroupShutList.ts +++ b/packages/napcat-onebot/action/group/GetGroupShutList.ts @@ -1,19 +1,35 @@ -import { ShutUpGroupMember } from 'napcat-core'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), }); -type Payload = Static; +type PayloadType = Static; -export class GetGroupShutList extends OneBotAction { +const ReturnSchema = Type.Array(Type.Any(), { description: '禁言成员列表' }); + +type ReturnType = Static; + +export class GetGroupShutList extends OneBotAction { override actionName = ActionName.GetGroupShutList; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取群禁言列表'; + override actionTags = ['群组接口']; + override payloadExample = { + group_id: '123456789' + }; + override returnExample = [ + { + user_id: 123456789, + nickname: '禁言用户', + shut_up_time: 1734567890 + } + ]; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { return await this.core.apis.GroupApi.getGroupShutUpMemberList(payload.group_id.toString()); } } diff --git a/packages/napcat-onebot/action/group/SendGroupAiRecord.ts b/packages/napcat-onebot/action/group/SendGroupAiRecord.ts index 2e9f4499..d1243c37 100644 --- a/packages/napcat-onebot/action/group/SendGroupAiRecord.ts +++ b/packages/napcat-onebot/action/group/SendGroupAiRecord.ts @@ -3,21 +3,35 @@ import { GetPacketStatusDepends } from '@/napcat-onebot/action/packet/GetPacketS import { AIVoiceChatType } from 'napcat-core/packet/entities/aiChat'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - character: Type.String(), - group_id: Type.Union([Type.Number(), Type.String()]), - text: Type.String(), +const PayloadSchema = Type.Object({ + character: Type.String({ description: '角色ID' }), + group_id: Type.String({ description: '群号' }), + text: Type.String({ description: '语音文本内容' }), }); -type Payload = Static; +type PayloadType = Static; -export class SendGroupAiRecord extends GetPacketStatusDepends { +const ReturnSchema = Type.Object({ + message_id: Type.Number({ description: '消息ID' }), +}, { description: '发送结果' }); + +type ReturnType = Static; + +export class SendGroupAiRecord extends GetPacketStatusDepends { override actionName = ActionName.SendGroupAiRecord; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '发送群 AI 语音'; + override actionDescription = '发送 AI 生成的语音到指定群聊'; + override actionTags = ['AI 扩展']; + override payloadExample = { + character: 'ai_char_1', + group_id: '123456', + text: '你好' + }; + override returnExample = {}; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { await this.core.apis.PacketApi.pkt.operation.GetAiVoice(+payload.group_id, payload.character, payload.text, AIVoiceChatType.Sound); return { message_id: 0, // can't get message_id from GetAiVoice diff --git a/packages/napcat-onebot/action/group/SendGroupMsg.ts b/packages/napcat-onebot/action/group/SendGroupMsg.ts index b79d4282..0188af77 100644 --- a/packages/napcat-onebot/action/group/SendGroupMsg.ts +++ b/packages/napcat-onebot/action/group/SendGroupMsg.ts @@ -1,18 +1,24 @@ -import { ContextMode, ReturnDataType, SendMsgBase } from '@/napcat-onebot/action/msg/SendMsg'; +import { ContextMode, ReturnDataType, SendMsgBase, SendMsgPayload } from '@/napcat-onebot/action/msg/SendMsg'; import { ActionName, BaseCheckResult } from '@/napcat-onebot/action/router'; -import { OB11PostSendMsg } from '@/napcat-onebot/types'; + +import { GroupActionsExamples } from '../example/GroupActionsExamples'; // 未检测参数 class SendGroupMsg extends SendMsgBase { override actionName = ActionName.SendGroupMsg; + override actionSummary = '发送群消息'; + override actionDescription = '发送群消息'; + override actionTags = ['群组接口']; + override payloadExample = GroupActionsExamples.SendGroupMsg.payload; + override returnExample = GroupActionsExamples.SendGroupMsg.response; - protected override async check (payload: OB11PostSendMsg): Promise { + protected override async check (payload: SendMsgPayload): Promise { delete payload.user_id; payload.message_type = 'group'; return super.check(payload); } - override async _handle (payload: OB11PostSendMsg): Promise { + override async _handle (payload: SendMsgPayload): Promise { return this.base_handle(payload, ContextMode.Group); } } diff --git a/packages/napcat-onebot/action/group/SetEssenceMsg.ts b/packages/napcat-onebot/action/group/SetEssenceMsg.ts index 85bb4a28..a596184d 100644 --- a/packages/napcat-onebot/action/group/SetEssenceMsg.ts +++ b/packages/napcat-onebot/action/group/SetEssenceMsg.ts @@ -3,17 +3,29 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { MessageUnique } from 'napcat-common/src/message-unique'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - message_id: Type.Union([Type.Number(), Type.String()]), +import { GroupActionsExamples } from '../example/GroupActionsExamples'; + +const PayloadSchema = Type.Object({ + message_id: Type.Union([Type.Number(), Type.String()], { description: '消息ID' }), }); -type Payload = Static; +type PayloadType = Static; -export default class SetEssenceMsg extends OneBotAction { +const ReturnSchema = Type.Any({ description: '操作结果' }); + +type ReturnType = Static; + +export default class SetEssenceMsg extends OneBotAction { override actionName = ActionName.SetEssenceMsg; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '设置精华消息'; + override actionDescription = '将一条消息设置为群精华消息'; + override actionTags = ['群组接口']; + override payloadExample = GroupActionsExamples.SetEssenceMsg.payload; + override returnExample = GroupActionsExamples.SetEssenceMsg.response; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { const msg = MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id); if (!msg) { throw new Error('msg not found'); diff --git a/packages/napcat-onebot/action/group/SetGroupAddRequest.ts b/packages/napcat-onebot/action/group/SetGroupAddRequest.ts index 7b66a46c..2f47f127 100644 --- a/packages/napcat-onebot/action/group/SetGroupAddRequest.ts +++ b/packages/napcat-onebot/action/group/SetGroupAddRequest.ts @@ -3,20 +3,32 @@ import { GroupNotify, NTGroupRequestOperateTypes } from 'napcat-core/types'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - flag: Type.Union([Type.String(), Type.Number()]), - approve: Type.Optional(Type.Union([Type.Boolean(), Type.String()])), - reason: Type.Optional(Type.Union([Type.String({ default: ' ' }), Type.Null()])), - count: Type.Optional(Type.Number({ default: 100 })), +import { GroupActionsExamples } from '../example/GroupActionsExamples'; + +const PayloadSchema = Type.Object({ + flag: Type.String({ description: '请求flag' }), + approve: Type.Optional(Type.Union([Type.Boolean(), Type.String()], { description: '是否同意' })), + reason: Type.Optional(Type.Union([Type.String({ default: ' ' }), Type.Null()], { description: '拒绝理由' })), + count: Type.Optional(Type.Number({ default: 100, description: '搜索通知数量' })), }); -type Payload = Static; +type PayloadType = Static; -export default class SetGroupAddRequest extends OneBotAction { +const ReturnSchema = Type.Null({ description: '操作结果' }); + +type ReturnType = Static; + +export default class SetGroupAddRequest extends OneBotAction { override actionName = ActionName.SetGroupAddRequest; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '处理加群请求'; + override actionDescription = '同意或拒绝加群请求或邀请'; + override actionTags = ['群组接口']; + override payloadExample = GroupActionsExamples.SetGroupAddRequest.payload; + override returnExample = GroupActionsExamples.SetGroupAddRequest.response; - async _handle (payload: Payload): Promise { + async _handle (payload: PayloadType): Promise { const flag = payload.flag.toString(); const approve = payload.approve?.toString() !== 'false'; const reason = payload.reason ?? ' '; diff --git a/packages/napcat-onebot/action/group/SetGroupAdmin.ts b/packages/napcat-onebot/action/group/SetGroupAdmin.ts index 2238ae2b..c50edf03 100644 --- a/packages/napcat-onebot/action/group/SetGroupAdmin.ts +++ b/packages/napcat-onebot/action/group/SetGroupAdmin.ts @@ -3,19 +3,31 @@ import { NTGroupMemberRole } from 'napcat-core/types'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - user_id: Type.Union([Type.Number(), Type.String()]), - enable: Type.Optional(Type.Union([Type.Boolean(), Type.String()])), +import { GroupActionsExamples } from '../example/GroupActionsExamples'; + +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + user_id: Type.String({ description: '用户QQ' }), + enable: Type.Optional(Type.Union([Type.Boolean(), Type.String()], { description: '是否设置为管理员' })), }); -type Payload = Static; +type PayloadType = Static; -export default class SetGroupAdmin extends OneBotAction { +const ReturnSchema = Type.Null({ description: '操作结果' }); + +type ReturnType = Static; + +export default class SetGroupAdmin extends OneBotAction { override actionName = ActionName.SetGroupAdmin; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '设置群管理员'; + override actionDescription = '设置或取消群聊中的管理员'; + override actionTags = ['群组接口']; + override payloadExample = GroupActionsExamples.SetGroupAdmin.payload; + override returnExample = GroupActionsExamples.SetGroupAdmin.response; - async _handle (payload: Payload): Promise { + async _handle (payload: PayloadType): Promise { const enable = typeof payload.enable === 'string' ? payload.enable === 'true' : !!payload.enable; const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString()); if (!uid) throw new Error('get Uid Error'); diff --git a/packages/napcat-onebot/action/group/SetGroupBan.ts b/packages/napcat-onebot/action/group/SetGroupBan.ts index 9a7894d3..1e0d714c 100644 --- a/packages/napcat-onebot/action/group/SetGroupBan.ts +++ b/packages/napcat-onebot/action/group/SetGroupBan.ts @@ -2,18 +2,31 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - user_id: Type.Union([Type.Number(), Type.String()]), - duration: Type.Union([Type.Number(), Type.String()], { default: 0 }), +import { GroupActionsExamples } from '../example/GroupActionsExamples'; + +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + user_id: Type.String({ description: '用户QQ' }), + duration: Type.Union([Type.Number(), Type.String()], { default: 0, description: '禁言时长(秒)' }), }); -type Payload = Static; +type PayloadType = Static; -export default class SetGroupBan extends OneBotAction { +const ReturnSchema = Type.Null({ description: '操作结果' }); + +type ReturnType = Static; + +export default class SetGroupBan extends OneBotAction { override actionName = ActionName.SetGroupBan; - override payloadSchema = SchemaData; - async _handle (payload: Payload): Promise { + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '群组禁言'; + override actionDescription = '禁言群聊中的指定成员'; + override actionTags = ['群组接口']; + override payloadExample = GroupActionsExamples.SetGroupBan.payload; + override returnExample = GroupActionsExamples.SetGroupBan.response; + + async _handle (payload: PayloadType): Promise { const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString()); if (!uid) throw new Error('uid error'); const member_role = (await this.core.apis.GroupApi.getGroupMemberEx(payload.group_id.toString(), uid, true))?.role; diff --git a/packages/napcat-onebot/action/group/SetGroupCard.ts b/packages/napcat-onebot/action/group/SetGroupCard.ts index b9242056..5682ab82 100644 --- a/packages/napcat-onebot/action/group/SetGroupCard.ts +++ b/packages/napcat-onebot/action/group/SetGroupCard.ts @@ -2,19 +2,31 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - user_id: Type.Union([Type.Number(), Type.String()]), - card: Type.Optional(Type.String()), +import { GroupActionsExamples } from '../example/GroupActionsExamples'; + +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + user_id: Type.String({ description: '用户QQ' }), + card: Type.Optional(Type.String({ description: '群名片' })), }); -type Payload = Static; +type PayloadType = Static; -export default class SetGroupCard extends OneBotAction { +const ReturnSchema = Type.Null({ description: '操作结果' }); + +type ReturnType = Static; + +export default class SetGroupCard extends OneBotAction { override actionName = ActionName.SetGroupCard; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '设置群名片'; + override actionDescription = '设置群聊中指定成员的群名片'; + override actionTags = ['群组接口']; + override payloadExample = GroupActionsExamples.SetGroupCard.payload; + override returnExample = GroupActionsExamples.SetGroupCard.response; - async _handle (payload: Payload): Promise { + async _handle (payload: PayloadType): Promise { const member = await this.core.apis.GroupApi.getGroupMember(payload.group_id.toString(), payload.user_id.toString()); if (member) await this.core.apis.GroupApi.setMemberCard(payload.group_id.toString(), member.uid, payload.card || ''); return null; diff --git a/packages/napcat-onebot/action/group/SetGroupKick.ts b/packages/napcat-onebot/action/group/SetGroupKick.ts index 53b33a75..4bd42a6d 100644 --- a/packages/napcat-onebot/action/group/SetGroupKick.ts +++ b/packages/napcat-onebot/action/group/SetGroupKick.ts @@ -2,19 +2,31 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - user_id: Type.Union([Type.Number(), Type.String()]), - reject_add_request: Type.Optional(Type.Union([Type.Boolean(), Type.String()])), +import { GroupActionsExamples } from '../example/GroupActionsExamples'; + +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + user_id: Type.String({ description: '用户QQ' }), + reject_add_request: Type.Optional(Type.Union([Type.Boolean(), Type.String()], { description: '是否拒绝加群请求' })), }); -type Payload = Static; +type PayloadType = Static; -export default class SetGroupKick extends OneBotAction { +const ReturnSchema = Type.Null({ description: '操作结果' }); + +type ReturnType = Static; + +export default class SetGroupKick extends OneBotAction { override actionName = ActionName.SetGroupKick; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '群组踢人'; + override actionDescription = '将指定成员踢出群聊'; + override actionTags = ['群组接口']; + override payloadExample = GroupActionsExamples.SetGroupKick.payload; + override returnExample = GroupActionsExamples.SetGroupKick.response; - async _handle (payload: Payload): Promise { + async _handle (payload: PayloadType): Promise { const rejectReq = payload.reject_add_request?.toString() === 'true'; const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString()); if (!uid) throw new Error('get Uid Error'); diff --git a/packages/napcat-onebot/action/group/SetGroupLeave.ts b/packages/napcat-onebot/action/group/SetGroupLeave.ts index 903b9215..b7f0dc01 100644 --- a/packages/napcat-onebot/action/group/SetGroupLeave.ts +++ b/packages/napcat-onebot/action/group/SetGroupLeave.ts @@ -2,18 +2,31 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - is_dismiss: Type.Optional(Type.Union([Type.Boolean(), Type.String()])), +import { GroupActionsExamples } from '../example/GroupActionsExamples'; + +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + is_dismiss: Type.Optional(Type.Union([Type.Boolean(), Type.String()], { description: '是否解散' })), }); -type Payload = Static; +type PayloadType = Static; -export default class SetGroupLeave extends OneBotAction { +const ReturnSchema = Type.Null({ description: '操作结果' }); + +type ReturnType = Static; + +export default class SetGroupLeave extends OneBotAction { override actionName = ActionName.SetGroupLeave; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '退出群组'; + override actionDescription = '退出或解散指定群聊'; + override actionTags = ['群组接口']; + override payloadExample = GroupActionsExamples.SetGroupLeave.payload; + override returnExample = GroupActionsExamples.SetGroupLeave.response; - async _handle (payload: Payload): Promise { + async _handle (payload: PayloadType): Promise { await this.core.apis.GroupApi.quitGroup(payload.group_id.toString()); + return null; } } diff --git a/packages/napcat-onebot/action/group/SetGroupName.ts b/packages/napcat-onebot/action/group/SetGroupName.ts index dd91bddd..cd9ed2e8 100644 --- a/packages/napcat-onebot/action/group/SetGroupName.ts +++ b/packages/napcat-onebot/action/group/SetGroupName.ts @@ -2,18 +2,30 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - group_name: Type.String(), +import { GroupActionsExamples } from '../example/GroupActionsExamples'; + +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + group_name: Type.String({ description: '群名称' }), }); -type Payload = Static; +type PayloadType = Static; -export default class SetGroupName extends OneBotAction { +const ReturnSchema = Type.Null({ description: '操作结果' }); + +type ReturnType = Static; + +export default class SetGroupName extends OneBotAction { override actionName = ActionName.SetGroupName; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '设置群名称'; + override actionDescription = '修改指定群聊的名称'; + override actionTags = ['群组接口']; + override payloadExample = GroupActionsExamples.SetGroupName.payload; + override returnExample = GroupActionsExamples.SetGroupName.response; - async _handle (payload: Payload): Promise { + async _handle (payload: PayloadType): Promise { const ret = await this.core.apis.GroupApi.setGroupName(payload.group_id.toString(), payload.group_name); if (ret.result !== 0) { throw new Error(`设置群名称失败 ErrCode: ${ret.result} ErrMsg: ${ret.errMsg}`); diff --git a/packages/napcat-onebot/action/group/SetGroupWholeBan.ts b/packages/napcat-onebot/action/group/SetGroupWholeBan.ts index c451e7c4..d60e8ac9 100644 --- a/packages/napcat-onebot/action/group/SetGroupWholeBan.ts +++ b/packages/napcat-onebot/action/group/SetGroupWholeBan.ts @@ -2,18 +2,30 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.Union([Type.Number(), Type.String()]), - enable: Type.Optional(Type.Union([Type.Boolean(), Type.String()])), +import { GroupActionsExamples } from '../example/GroupActionsExamples'; + +const PayloadSchema = Type.Object({ + group_id: Type.String({ description: '群号' }), + enable: Type.Optional(Type.Union([Type.Boolean(), Type.String()], { description: '是否开启全员禁言' })), }); -type Payload = Static; +type PayloadType = Static; -export default class SetGroupWholeBan extends OneBotAction { +const ReturnSchema = Type.Null({ description: '操作结果' }); + +type ReturnType = Static; + +export default class SetGroupWholeBan extends OneBotAction { override actionName = ActionName.SetGroupWholeBan; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '全员禁言'; + override actionDescription = '开启或关闭指定群聊的全员禁言'; + override actionTags = ['群组接口']; + override payloadExample = GroupActionsExamples.SetGroupWholeBan.payload; + override returnExample = GroupActionsExamples.SetGroupWholeBan.response; - async _handle (payload: Payload): Promise { + async _handle (payload: PayloadType): Promise { const enable = payload.enable?.toString() !== 'false'; const res = await this.core.apis.GroupApi.banGroup(payload.group_id.toString(), enable); if (res.result !== 0) { diff --git a/packages/napcat-onebot/action/guild/GetGuildList.ts b/packages/napcat-onebot/action/guild/GetGuildList.ts index ec57f988..c15d7f7e 100644 --- a/packages/napcat-onebot/action/guild/GetGuildList.ts +++ b/packages/napcat-onebot/action/guild/GetGuildList.ts @@ -1,8 +1,18 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; +import { Type } from '@sinclair/typebox'; +import { GuildActionsExamples } from '../example/GuildActionsExamples'; + export class GetGuildList extends OneBotAction { override actionName = ActionName.GetGuildList; + override payloadSchema = Type.Object({}); + override returnSchema = Type.Null(); + override actionSummary = '获取频道列表'; + override actionDescription = '获取当前帐号已加入的频道列表'; + override actionTags = ['频道接口']; + override payloadExample = GuildActionsExamples.GetGuildList.payload; + override returnExample = GuildActionsExamples.GetGuildList.response; async _handle (): Promise { diff --git a/packages/napcat-onebot/action/guild/GetGuildProfile.ts b/packages/napcat-onebot/action/guild/GetGuildProfile.ts index d7286ad4..4985aa9f 100644 --- a/packages/napcat-onebot/action/guild/GetGuildProfile.ts +++ b/packages/napcat-onebot/action/guild/GetGuildProfile.ts @@ -1,8 +1,18 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; +import { Type } from '@sinclair/typebox'; +import { GuildActionsExamples } from '../example/GuildActionsExamples'; + export class GetGuildProfile extends OneBotAction { override actionName = ActionName.GetGuildProfile; + override payloadSchema = Type.Object({}); + override returnSchema = Type.Null(); + override actionSummary = '获取频道个人信息'; + override actionDescription = '获取当前帐号在频道中的个人资料'; + override actionTags = ['频道接口']; + override payloadExample = GuildActionsExamples.GetGuildProfile.payload; + override returnExample = GuildActionsExamples.GetGuildProfile.response; async _handle (): Promise { diff --git a/packages/napcat-onebot/action/index.ts b/packages/napcat-onebot/action/index.ts index 11f8b4c6..a9be0a1d 100644 --- a/packages/napcat-onebot/action/index.ts +++ b/packages/napcat-onebot/action/index.ts @@ -156,7 +156,7 @@ import { ReceiveOnlineFile } from './file/online/ReceiveOnlineFile'; import { RefuseOnlineFile } from './file/online/RefuseOnlineFile'; import { GetFilesetId } from './file/flash/GetFilesetIdByCode'; -export function createActionMap (obContext: NapCatOneBot11Adapter, core: NapCatCore) { +export function getAllHandlers (obContext: NapCatOneBot11Adapter, core: NapCatCore) { const actionHandlers = [ new CleanStreamTempFile(obContext, core), new DownloadFileStream(obContext, core), @@ -324,7 +324,11 @@ export function createActionMap (obContext: NapCatOneBot11Adapter, core: NapCatC new DownloadFileset(obContext, core), new GetFilesetId(obContext, core), ]; + return actionHandlers; +} +export function createActionMap (obContext: NapCatOneBot11Adapter, core: NapCatCore) { + const actionHandlers = getAllHandlers(obContext, core); type HandlerUnion = typeof actionHandlers[number]; type MapType = { [H in HandlerUnion as H['actionName']]: H; diff --git a/packages/napcat-onebot/action/msg/DeleteMsg.ts b/packages/napcat-onebot/action/msg/DeleteMsg.ts index 95c205b2..2def3269 100644 --- a/packages/napcat-onebot/action/msg/DeleteMsg.ts +++ b/packages/napcat-onebot/action/msg/DeleteMsg.ts @@ -3,23 +3,36 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { MessageUnique } from 'napcat-common/src/message-unique'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - message_id: Type.Union([Type.Number(), Type.String()]), +const PayloadSchema = Type.Object({ + message_id: Type.Union([Type.Number(), Type.String()], { description: '消息ID' }), }); -type Payload = Static; +type PayloadType = Static; -class DeleteMsg extends OneBotAction { +const ReturnSchema = Type.Null({ description: '操作结果' }); + +type ReturnType = Static; + +class DeleteMsg extends OneBotAction { override actionName = ActionName.DeleteMsg; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '撤回消息'; + override actionDescription = '撤回已发送的消息'; + override actionTags = ['消息接口']; + override payloadExample = { + message_id: 12345 + }; + override returnExample = null; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { const msg = MessageUnique.getMsgIdAndPeerByShortId(Number(payload.message_id)); if (msg) { this.obContext.recallEventCache.set(msg.MsgId, setTimeout(() => { this.obContext.recallEventCache.delete(msg.MsgId); }, 5000)); await this.core.apis.MsgApi.recallMsg(msg.Peer, msg.MsgId); + return null; } else { throw new Error('Recall failed'); } diff --git a/packages/napcat-onebot/action/msg/ForwardSingleMsg.ts b/packages/napcat-onebot/action/msg/ForwardSingleMsg.ts index a57a4352..d809c417 100644 --- a/packages/napcat-onebot/action/msg/ForwardSingleMsg.ts +++ b/packages/napcat-onebot/action/msg/ForwardSingleMsg.ts @@ -4,16 +4,29 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { MessageUnique } from 'napcat-common/src/message-unique'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - message_id: Type.Union([Type.Number(), Type.String()]), - group_id: Type.Optional(Type.Union([Type.Number(), Type.String()])), - user_id: Type.Optional(Type.Union([Type.Number(), Type.String()])), +const PayloadSchema = Type.Object({ + message_id: Type.Union([Type.Number(), Type.String()], { description: '消息ID' }), + group_id: Type.Optional(Type.String({ description: '目标群号' })), + user_id: Type.Optional(Type.String({ description: '目标用户QQ' })), }); -type Payload = Static; +type PayloadType = Static; -class ForwardSingleMsg extends OneBotAction { - protected async getTargetPeer (payload: Payload): Promise { +const ReturnSchema = Type.Null({ description: '操作结果' }); + +type ReturnType = Static; + +class ForwardSingleMsg extends OneBotAction { + override actionSummary = '转发单条消息'; + override actionDescription = '转发单条消息'; + override actionTags = ['消息接口']; + override payloadExample = { + message_id: 12345, + group_id: '123456' + }; + override returnExample = null; + + protected async getTargetPeer (payload: PayloadType): Promise { if (payload.user_id) { const peerUid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString()); if (!peerUid) { @@ -24,7 +37,7 @@ class ForwardSingleMsg extends OneBotAction { return { chatType: ChatType.KCHATTYPEGROUP, peerUid: payload.group_id!.toString() }; } - async _handle (payload: Payload): Promise { + async _handle (payload: PayloadType): Promise { const msg = MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id); if (!msg) { throw new Error(`无法找到消息${payload.message_id}`); @@ -42,11 +55,13 @@ class ForwardSingleMsg extends OneBotAction { } export class ForwardFriendSingleMsg extends ForwardSingleMsg { - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; override actionName = ActionName.ForwardFriendSingleMsg; } export class ForwardGroupSingleMsg extends ForwardSingleMsg { - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; override actionName = ActionName.ForwardGroupSingleMsg; } diff --git a/packages/napcat-onebot/action/msg/GetMsg.ts b/packages/napcat-onebot/action/msg/GetMsg.ts index a125ae62..313e730f 100644 --- a/packages/napcat-onebot/action/msg/GetMsg.ts +++ b/packages/napcat-onebot/action/msg/GetMsg.ts @@ -1,23 +1,45 @@ -import { OB11Message } from '@/napcat-onebot/index'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { MessageUnique } from 'napcat-common/src/message-unique'; import { Static, Type } from '@sinclair/typebox'; import { NetworkAdapterConfig } from '@/napcat-onebot/config/config'; -export type ReturnDataType = OB11Message; +import { MsgActionsExamples } from './examples'; -const SchemaData = Type.Object({ - message_id: Type.Union([Type.Number(), Type.String()]), +const PayloadSchema = Type.Object({ + message_id: Type.Union([Type.Number(), Type.String()], { description: '消息ID' }), }); -type Payload = Static; +type PayloadType = Static; -class GetMsg extends OneBotAction { +const ReturnSchema = Type.Object({ + time: Type.Number({ description: '发送时间' }), + message_type: Type.String({ description: '消息类型' }), + message_id: Type.Number({ description: '消息ID' }), + real_id: Type.Number({ description: '真实ID' }), + message_seq: Type.Number({ description: '消息序号' }), + sender: Type.Any({ description: '发送者' }), + message: Type.Any({ description: '消息内容' }), + raw_message: Type.String({ description: '原始消息内容' }), + font: Type.Number({ description: '字体' }), + group_id: Type.Optional(Type.Union([Type.Number(), Type.String()], { description: '群号' })), + user_id: Type.Union([Type.Number(), Type.String()], { description: '发送者QQ号' }), + emoji_likes_list: Type.Optional(Type.Array(Type.Any(), { description: '表情回应列表' })), +}, { description: 'OneBot 11 消息' }); + +type ReturnType = Static; + +class GetMsg extends OneBotAction { override actionName = ActionName.GetMsg; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取消息'; + override actionDescription = '根据消息 ID 获取消息详细信息'; + override actionTags = ['消息接口']; + override payloadExample = MsgActionsExamples.GetMsg.payload; + override returnExample = MsgActionsExamples.GetMsg.response; - async _handle (payload: Payload, _adapter: string, config: NetworkAdapterConfig) { + async _handle (payload: PayloadType, _adapter: string, config: NetworkAdapterConfig) { if (!payload.message_id) { throw Error('参数message_id不能为空'); } @@ -27,12 +49,7 @@ class GetMsg extends OneBotAction { throw new Error('消息不存在'); } const peer = { guildId: '', peerUid: msgIdWithPeer?.Peer.peerUid, chatType: msgIdWithPeer.Peer.chatType }; - // const orimsg = this.obContext.recallMsgCache.get(msgIdWithPeer.MsgId); - // if (orimsg) { - // msg = orimsg; - // } else { const msg = (await this.core.apis.MsgApi.getMsgsByMsgId(peer, [msgIdWithPeer?.MsgId || payload.message_id.toString()])).msgList[0]; - // } if (!msg) throw Error('消息不存在'); const retMsg = await this.obContext.apis.MsgApi.parseMessage(msg, config.messagePostFormat); if (!retMsg) throw Error('消息为空'); @@ -44,7 +61,6 @@ class GetMsg extends OneBotAction { likes_cnt: emoji.likesCnt, }); }); - // 烘焙emoji_likes_list 仅此处烘焙 try { retMsg.message_id = MessageUnique.createUniqueMsgId(peer, msg.msgId)!; retMsg.message_seq = retMsg.message_id; diff --git a/packages/napcat-onebot/action/msg/MarkMsgAsRead.ts b/packages/napcat-onebot/action/msg/MarkMsgAsRead.ts index 7698c822..6b565755 100644 --- a/packages/napcat-onebot/action/msg/MarkMsgAsRead.ts +++ b/packages/napcat-onebot/action/msg/MarkMsgAsRead.ts @@ -4,16 +4,28 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { MessageUnique } from 'napcat-common/src/message-unique'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - user_id: Type.Optional(Type.Union([Type.String(), Type.Number()])), - group_id: Type.Optional(Type.Union([Type.String(), Type.Number()])), - message_id: Type.Optional(Type.Union([Type.String(), Type.Number()])), +const PayloadSchema = Type.Object({ + user_id: Type.Optional(Type.Union([Type.String(), Type.Number()], { description: '用户QQ' })), + group_id: Type.Optional(Type.String({ description: '群号' })), + message_id: Type.Optional(Type.String({ description: '消息ID' })), }); -type PlayloadType = Static; +type PayloadType = Static; -class MarkMsgAsRead extends OneBotAction { - async getPeer (payload: PlayloadType): Promise { +const ReturnSchema = Type.Null({ description: '操作结果' }); + +type ReturnType = Static; + +class MarkMsgAsRead extends OneBotAction { + override actionSummary = '标记消息已读'; + override actionDescription = '标记指定渠道的消息为已读'; + override actionTags = ['消息接口']; + override payloadExample = { + message_id: 12345 + }; + override returnExample = null; + + async getPeer (payload: PayloadType): Promise { if (payload.message_id) { const s_peer = MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id)?.Peer; if (s_peer) { @@ -38,7 +50,7 @@ class MarkMsgAsRead extends OneBotAction { return { chatType: ChatType.KCHATTYPEGROUP, peerUid: payload.group_id.toString() }; } - async _handle (payload: PlayloadType): Promise { + async _handle (payload: PayloadType): Promise { const ret = await this.core.apis.MsgApi.setMsgRead(await this.getPeer(payload)); if (ret.result !== 0) { throw new Error('设置已读失败,' + ret.errMsg); @@ -49,21 +61,32 @@ class MarkMsgAsRead extends OneBotAction { // 以下为非标准实现 export class MarkPrivateMsgAsRead extends MarkMsgAsRead { - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; override actionName = ActionName.MarkPrivateMsgAsRead; + override actionSummary = '标记私聊已读'; } export class MarkGroupMsgAsRead extends MarkMsgAsRead { - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; override actionName = ActionName.MarkGroupMsgAsRead; + override actionSummary = '标记群聊已读'; } export class GoCQHTTPMarkMsgAsRead extends MarkMsgAsRead { + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; override actionName = ActionName.GoCQHTTP_MarkMsgAsRead; + override actionSummary = '标记消息已读 (Go-CQHTTP)'; } export class MarkAllMsgAsRead extends OneBotAction { override actionName = ActionName._MarkAllMsgAsRead; + override actionSummary = '标记所有消息已读'; + override actionTags = ['消息接口']; + override payloadExample = {}; + override returnExample = null; async _handle (): Promise { await this.core.apis.MsgApi.markAllMsgAsRead(); diff --git a/packages/napcat-onebot/action/msg/SendMsg.ts b/packages/napcat-onebot/action/msg/SendMsg.ts index d6f0c4ac..2eaef166 100644 --- a/packages/napcat-onebot/action/msg/SendMsg.ts +++ b/packages/napcat-onebot/action/msg/SendMsg.ts @@ -4,7 +4,6 @@ import { OB11MessageMixType, OB11MessageNode, OB11PostContext, - OB11PostSendMsg, } from '@/napcat-onebot/types'; import { ActionName, BaseCheckResult } from '@/napcat-onebot/action/router'; import { decodeCQCode } from '@/napcat-onebot/helper/cqcode'; @@ -15,12 +14,32 @@ import { ForwardMsgBuilder } from '@/napcat-core/helper/forward-msg-builder'; import { stringifyWithBigInt } from 'napcat-common/src/helper'; import { PacketMsg } from 'napcat-core/packet/message/message'; import { rawMsgWithSendMsg } from 'napcat-core/packet/message/converter'; +import { Static, Type } from '@sinclair/typebox'; +import { MsgActionsExamples } from '@/napcat-onebot/action/msg/examples'; +import { OB11MessageMixTypeSchema } from '@/napcat-onebot/types/message'; -export interface ReturnDataType { - message_id: number; - res_id?: string; - forward_id?: string; -} +export const SendMsgPayloadSchema = Type.Object({ + message_type: Type.Optional(Type.Union([Type.Literal('private'), Type.Literal('group')], { description: '消息类型 (private/group)' })), + user_id: Type.Optional(Type.String({ description: '用户QQ' })), + group_id: Type.Optional(Type.String({ description: '群号' })), + message: OB11MessageMixTypeSchema, + auto_escape: Type.Optional(Type.Union([Type.Boolean(), Type.String()], { description: '是否作为纯文本发送' })), + // 以下为扩展字段 + source: Type.Optional(Type.String({ description: '合并转发来源' })), + news: Type.Optional(Type.Array(Type.Object({ text: Type.String() }), { description: '合并转发新闻' })), + summary: Type.Optional(Type.String({ description: '合并转发摘要' })), + prompt: Type.Optional(Type.String({ description: '合并转发提示' })), +}); + +export type SendMsgPayload = Static; + +export const SendMsgReturnSchema = Type.Object({ + message_id: Type.Number({ description: '消息ID' }), + res_id: Type.Optional(Type.String({ description: '转发消息的 res_id' })), + forward_id: Type.Optional(Type.String({ description: '转发消息的 forward_id' })), +}); + +export type ReturnDataType = Static; export enum ContextMode { Normal = 0, @@ -99,17 +118,22 @@ export async function createContext (core: NapCatCore, payload: OB11PostContext throw new Error('请指定正确的 group_id 或 user_id'); } -function getSpecialMsgNum (payload: OB11PostSendMsg, msgType: OB11MessageDataType): number { - if (Array.isArray(payload.message)) { - return payload.message.filter(msg => msg.type === msgType).length; - } - return 0; +function getSpecialMsgNum (messages: OB11MessageData[], msgType: OB11MessageDataType): number { + return messages.filter(msg => msg.type === msgType).length; } -export class SendMsgBase extends OneBotAction { - protected override async check (payload: OB11PostSendMsg): Promise { +function isNode (msg: OB11MessageData): msg is OB11MessageNode { + return msg.type === OB11MessageDataType.node; +} + +export class SendMsgBase extends OneBotAction { + override payloadSchema = SendMsgPayloadSchema; + override returnSchema = SendMsgReturnSchema; + override actionTags = ['消息接口']; + + protected override async check (payload: SendMsgPayload): Promise { const messages = normalize(payload.message); - const nodeElementLength = getSpecialMsgNum(payload, OB11MessageDataType.node); + const nodeElementLength = getSpecialMsgNum(messages, OB11MessageDataType.node); if (nodeElementLength > 0 && nodeElementLength !== messages.length) { return { valid: false, @@ -119,27 +143,32 @@ export class SendMsgBase extends OneBotAction { return { valid: true }; } - async _handle (payload: OB11PostSendMsg): Promise { + async _handle (payload: SendMsgPayload): Promise { return this.base_handle(payload); } - async base_handle (payload: OB11PostSendMsg, contextMode: ContextMode = ContextMode.Normal): Promise { + async base_handle (payload: SendMsgPayload, contextMode: ContextMode = ContextMode.Normal): Promise { if (payload.message_type === 'group') contextMode = ContextMode.Group; if (payload.message_type === 'private') contextMode = ContextMode.Private; - const peer = await createContext(this.core, payload, contextMode); + const peer = await createContext(this.core, { + message_type: payload.message_type, + user_id: payload.user_id?.toString(), + group_id: payload.group_id?.toString(), + }, contextMode); const messages = normalize( payload.message, typeof payload.auto_escape === 'string' ? payload.auto_escape === 'true' : !!payload.auto_escape ); - if (getSpecialMsgNum(payload, OB11MessageDataType.node)) { + const nodeMessages = messages.filter(isNode); + if (nodeMessages.length > 0) { const packetMode = this.core.apis.PacketApi.packetStatus; let returnMsgAndResId: { message: RawMessage | null, res_id?: string; } | null; try { returnMsgAndResId = packetMode - ? await this.handleForwardedNodesPacket(peer, messages as OB11MessageNode[], payload.source, payload.news, payload.summary, payload.prompt) - : await this.handleForwardedNodes(peer, messages as OB11MessageNode[]); + ? await this.handleForwardedNodesPacket(peer, nodeMessages, payload.source, payload.news, payload.summary, payload.prompt) + : await this.handleForwardedNodes(peer, nodeMessages); } catch (e: unknown) { throw Error(packetMode ? `发送伪造合并转发消息失败: ${(e as Error)?.stack}` : `发送合并转发消息失败: ${(e as Error)?.stack}`); } @@ -195,8 +224,9 @@ export class SendMsgBase extends OneBotAction { const OB11Data = normalize(node.type === OB11MessageDataType.node ? node.data.content : node); let sendElements: SendMessageElement[]; - if (getSpecialMsgNum({ message: OB11Data }, OB11MessageDataType.node)) { - const uploadReturnData = await this.uploadForwardedNodesPacket(msgPeer, OB11Data as OB11MessageNode[], node.data.source, node.data.news, node.data.summary, node.data.prompt, { + const subNodeMessages = OB11Data.filter(isNode); + if (subNodeMessages.length > 0) { + const uploadReturnData = await this.uploadForwardedNodesPacket(msgPeer, subNodeMessages, node.data.source, node.data.news, node.data.summary, node.data.prompt, { user_id: (node.data.user_id ?? node.data.uin)?.toString() ?? parentMeta?.user_id ?? this.core.selfInfo.uin, nickname: (node.data.nickname || node.data.name) ?? parentMeta?.nickname ?? 'QQ用户', }, dp + 1); @@ -296,13 +326,13 @@ export class SendMsgBase extends OneBotAction { try { const OB11Data = normalize(messageNode.data.content); // 筛选node消息 - const isNodeMsg = OB11Data.filter(e => e.type === OB11MessageDataType.node).length;// 找到子转发消息 - if (isNodeMsg !== 0) { - if (isNodeMsg !== OB11Data.length) { + const subNodeMessages = OB11Data.filter(isNode); + if (subNodeMessages.length !== 0) { + if (subNodeMessages.length !== OB11Data.length) { this.core.context.logger.logError('子消息中包含非node消息 跳过不合法部分'); continue; } - const nodeMsg = await this.handleForwardedNodes(selfPeer, OB11Data.filter(e => e.type === OB11MessageDataType.node)); + const nodeMsg = await this.handleForwardedNodes(selfPeer, subNodeMessages); if (nodeMsg) { nodeMsgIds.push(nodeMsg.message!.msgId); MessageUnique.createUniqueMsgId(selfPeer, nodeMsg.message!.msgId); @@ -413,4 +443,9 @@ export class SendMsgBase extends OneBotAction { } export default class SendMsg extends SendMsgBase { override actionName = ActionName.SendMsg; + override actionSummary = '发送消息'; + override actionDescription = '发送私聊或群聊消息'; + override actionTags = ['消息接口']; + override payloadExample = MsgActionsExamples.SendMsg.payload; + override returnExample = MsgActionsExamples.SendMsg.response; } diff --git a/packages/napcat-onebot/action/msg/SendPrivateMsg.ts b/packages/napcat-onebot/action/msg/SendPrivateMsg.ts index 6c1f6402..0800985e 100644 --- a/packages/napcat-onebot/action/msg/SendPrivateMsg.ts +++ b/packages/napcat-onebot/action/msg/SendPrivateMsg.ts @@ -1,17 +1,26 @@ -import { ContextMode, ReturnDataType, SendMsgBase } from './SendMsg'; +import { ContextMode, ReturnDataType, SendMsgBase, SendMsgPayload } from './SendMsg'; import { ActionName, BaseCheckResult } from '@/napcat-onebot/action/router'; -import { OB11PostSendMsg } from '@/napcat-onebot/types'; // 未检测参数 class SendPrivateMsg extends SendMsgBase { override actionName = ActionName.SendPrivateMsg; + override actionSummary = '发送私聊消息'; + override actionDescription = '发送私聊消息'; + override actionTags = ['消息接口']; + override payloadExample = { + user_id: '123456789', + message: 'hello' + }; + override returnExample = { + message_id: 123456 + }; - protected override async check (payload: OB11PostSendMsg): Promise { + protected override async check (payload: SendMsgPayload): Promise { payload.message_type = 'private'; return super.check(payload); } - override async _handle (payload: OB11PostSendMsg): Promise { + override async _handle (payload: SendMsgPayload): Promise { return this.base_handle(payload, ContextMode.Private); } } diff --git a/packages/napcat-onebot/action/msg/SetMsgEmojiLike.ts b/packages/napcat-onebot/action/msg/SetMsgEmojiLike.ts index 6278ecd8..745bcff0 100644 --- a/packages/napcat-onebot/action/msg/SetMsgEmojiLike.ts +++ b/packages/napcat-onebot/action/msg/SetMsgEmojiLike.ts @@ -3,19 +3,34 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { MessageUnique } from 'napcat-common/src/message-unique'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - message_id: Type.Union([Type.Number(), Type.String()]), - emoji_id: Type.Union([Type.Number(), Type.String()]), - set: Type.Optional(Type.Union([Type.Boolean(), Type.String()])), +const PayloadSchema = Type.Object({ + message_id: Type.Union([Type.Number(), Type.String()], { description: '消息ID' }), + emoji_id: Type.Union([Type.Number(), Type.String()], { description: '表情ID' }), + set: Type.Optional(Type.Union([Type.Boolean(), Type.String()], { description: '是否设置' })), }); -type Payload = Static; +type PayloadType = Static; -export class SetMsgEmojiLike extends OneBotAction { +const ReturnSchema = Type.Any({ description: '操作结果' }); + +type ReturnType = Static; + +export class SetMsgEmojiLike extends OneBotAction { override actionName = ActionName.SetMsgEmojiLike; - override payloadSchema = SchemaData; + override actionSummary = '设置消息表情点赞'; + override actionTags = ['消息扩展']; + override payloadExample = { + message_id: 12345, + emoji_id: '123', + set: true + }; + override returnExample = { + result: true + }; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; - async _handle (payload: Payload) { + async _handle (payload: PayloadType) { const msg = MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id); if (!msg) { throw new Error('msg not found'); diff --git a/packages/napcat-onebot/action/msg/examples.ts b/packages/napcat-onebot/action/msg/examples.ts new file mode 100644 index 00000000..9aa6b898 --- /dev/null +++ b/packages/napcat-onebot/action/msg/examples.ts @@ -0,0 +1,33 @@ +export const MsgActionsExamples = { + DeleteMsg: { + payload: { message_id: 123456 }, + response: {}, + }, + GetMsg: { + payload: { message_id: 123456 }, + response: { + time: 1710000000, + message_type: 'group', + message_id: 123456, + real_id: 123456, + sender: { user_id: 123456789, nickname: '昵称' }, + message: 'hello', + }, + }, + MarkMsgAsRead: { + payload: { group_id: '123456' }, + response: {}, + }, + SendMsg: { + payload: { message_type: 'group', group_id: '123456', message: 'hello' }, + response: { message_id: 123456 }, + }, + SendPrivateMsg: { + payload: { user_id: '123456789', message: 'hello' }, + response: { message_id: 123456 }, + }, + SetMsgEmojiLike: { + payload: { message_id: 123456, emoji_id: '12345' }, + response: {}, + }, +}; diff --git a/packages/napcat-onebot/action/new/GetDoubtFriendsAddRequest.ts b/packages/napcat-onebot/action/new/GetDoubtFriendsAddRequest.ts index 4f60d49b..444c97c2 100644 --- a/packages/napcat-onebot/action/new/GetDoubtFriendsAddRequest.ts +++ b/packages/napcat-onebot/action/new/GetDoubtFriendsAddRequest.ts @@ -1,18 +1,25 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; +import { NewActionsExamples } from '../example/NewActionsExamples'; -const SchemaData = Type.Object({ - count: Type.Number({ default: 50 }), +export const GetDoubtFriendsAddRequestPayloadSchema = Type.Object({ + count: Type.Number({ default: 50, description: '获取数量' }), }); -type Payload = Static; +export type GetDoubtFriendsAddRequestPayload = Static; -export class GetDoubtFriendsAddRequest extends OneBotAction { +export class GetDoubtFriendsAddRequest extends OneBotAction { override actionName = ActionName.GetDoubtFriendsAddRequest; - override payloadSchema = SchemaData; + override payloadSchema = GetDoubtFriendsAddRequestPayloadSchema; + override returnSchema = Type.Any({ description: '可疑好友申请列表' }); + override actionSummary = '获取可疑好友申请'; + override actionDescription = '获取系统的可疑好友申请列表'; + override actionTags = ['系统接口']; + override payloadExample = NewActionsExamples.GetDoubtFriendsAddRequest.payload; + override returnExample = NewActionsExamples.GetDoubtFriendsAddRequest.response; - async _handle (payload: Payload) { + async _handle (payload: GetDoubtFriendsAddRequestPayload) { return await this.core.apis.FriendApi.getDoubtFriendRequest(payload.count); } } diff --git a/packages/napcat-onebot/action/new/SetDoubtFriendsAddRequest.ts b/packages/napcat-onebot/action/new/SetDoubtFriendsAddRequest.ts index 59f48f72..cb77b40b 100644 --- a/packages/napcat-onebot/action/new/SetDoubtFriendsAddRequest.ts +++ b/packages/napcat-onebot/action/new/SetDoubtFriendsAddRequest.ts @@ -2,20 +2,29 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - flag: Type.String(), +export const SetDoubtFriendsAddRequestPayloadSchema = Type.Object({ + flag: Type.String({ description: '请求 flag' }), // 注意强制String 非isNumeric 不遵守则不符合设计 - approve: Type.Boolean({ default: true }), + approve: Type.Boolean({ default: true, description: '是否同意 (强制为 true)' }), // 该字段没有语义 仅做保留 强制为True }); -type Payload = Static; +export type SetDoubtFriendsAddRequestPayload = Static; -export class SetDoubtFriendsAddRequest extends OneBotAction { +export class SetDoubtFriendsAddRequest extends OneBotAction { override actionName = ActionName.SetDoubtFriendsAddRequest; - override payloadSchema = SchemaData; + override payloadSchema = SetDoubtFriendsAddRequestPayloadSchema; + override returnSchema = Type.Any(); + override actionSummary = '处理可疑好友申请'; + override actionDescription = '同意或拒绝系统的可疑好友申请'; + override actionTags = ['系统接口']; + override payloadExample = { + flag: '12345', + approve: true + }; + override returnExample = null; - async _handle (payload: Payload) { + async _handle (payload: SetDoubtFriendsAddRequestPayload) { return await this.core.apis.FriendApi.handleDoubtFriendRequest(payload.flag); } } diff --git a/packages/napcat-onebot/action/packet/GetPacketStatus.ts b/packages/napcat-onebot/action/packet/GetPacketStatus.ts index ae7fd3ac..e5716aa3 100644 --- a/packages/napcat-onebot/action/packet/GetPacketStatus.ts +++ b/packages/napcat-onebot/action/packet/GetPacketStatus.ts @@ -1,5 +1,6 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName, BaseCheckResult } from '@/napcat-onebot/action/router'; +import { Type } from '@sinclair/typebox'; export abstract class GetPacketStatusDepends extends OneBotAction { protected override async check (payload: PT): Promise { @@ -7,7 +8,7 @@ export abstract class GetPacketStatusDepends extends OneBotAction extends OneBotAction { override actionName = ActionName.GetPacketStatus; + override payloadSchema = Type.Object({}); + override returnSchema = Type.Null(); + override actionSummary = '获取Packet状态'; + override actionDescription = '获取底层Packet服务的运行状态'; + override actionTags = ['系统接口']; + override payloadExample = {}; + override returnExample = null; async _handle () { diff --git a/packages/napcat-onebot/action/packet/GetRkeyEx.ts b/packages/napcat-onebot/action/packet/GetRkeyEx.ts index c73fb4bd..b5079d10 100644 --- a/packages/napcat-onebot/action/packet/GetRkeyEx.ts +++ b/packages/napcat-onebot/action/packet/GetRkeyEx.ts @@ -1,8 +1,31 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { GetPacketStatusDepends } from '@/napcat-onebot/action/packet/GetPacketStatus'; +import { Type, Static } from '@sinclair/typebox'; -export class GetRkeyEx extends GetPacketStatusDepends { +export const GetRkeyExReturnSchema = Type.Array(Type.Object({ + type: Type.String({ description: '类型 (private/group)' }), + rkey: Type.String({ description: 'RKey' }), + created_at: Type.Number({ description: '创建时间' }), + ttl: Type.Number({ description: '有效期' }), +}), { description: 'RKey 列表' }); + +export type GetRkeyExReturn = Static; + +export class GetRkeyEx extends GetPacketStatusDepends { override actionName = ActionName.GetRkeyEx; + override payloadSchema = Type.Object({}); + override returnSchema = GetRkeyExReturnSchema; + override actionSummary = '获取扩展 RKey'; + override actionTags = ['系统扩展']; + override payloadExample = {}; + override returnExample = [ + { + type: 'private', + rkey: 'rkey_123', + created_at: 1734567890, + ttl: 3600 + } + ]; async _handle () { const rkeys = await this.core.apis.PacketApi.pkt.operation.FetchRkey(); @@ -10,8 +33,8 @@ export class GetRkeyEx extends GetPacketStatusDepends { return { type: rkey.type === 10 ? 'private' : 'group', rkey: rkey.rkey, - created_at: rkey.time, - ttl: rkey.ttl, + created_at: Number(rkey.time), + ttl: Number(rkey.ttl), }; }); } diff --git a/packages/napcat-onebot/action/packet/GetRkeyServer.ts b/packages/napcat-onebot/action/packet/GetRkeyServer.ts index 9862d1be..527fcb72 100644 --- a/packages/napcat-onebot/action/packet/GetRkeyServer.ts +++ b/packages/napcat-onebot/action/packet/GetRkeyServer.ts @@ -1,15 +1,31 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { GetPacketStatusDepends } from '@/napcat-onebot/action/packet/GetPacketStatus'; +import { Type, Static } from '@sinclair/typebox'; -export class GetRkeyServer extends GetPacketStatusDepends { +export const GetRkeyServerReturnSchema = Type.Object({ + private_rkey: Type.Optional(Type.String({ description: '私聊 RKey' })), + group_rkey: Type.Optional(Type.String({ description: '群聊 RKey' })), + expired_time: Type.Optional(Type.Number({ description: '过期时间' })), + name: Type.String({ description: '名称' }), +}); + +export type GetRkeyServerReturn = Static; + +export class GetRkeyServer extends GetPacketStatusDepends { override actionName = ActionName.GetRkeyServer; + override actionSummary = '获取 RKey 服务器'; + override actionTags = ['系统扩展']; + override payloadExample = {}; + override returnExample = { + private_rkey: '&rkey=123456789', + group_rkey: '&rkey=123456789', + expired_time: 1694560000, + name: 'NapCat 4', + }; + override payloadSchema = Type.Object({}); + override returnSchema = GetRkeyServerReturnSchema; - private rkeyCache: { - private_rkey?: string; - group_rkey?: string; - expired_time?: number; - name: string; - } | null = null; + private rkeyCache: GetRkeyServerReturn | null = null; private expiryTime: number | null = null; diff --git a/packages/napcat-onebot/action/packet/SendPoke.ts b/packages/napcat-onebot/action/packet/SendPoke.ts index e7094fcf..d0f0c5fb 100644 --- a/packages/napcat-onebot/action/packet/SendPoke.ts +++ b/packages/napcat-onebot/action/packet/SendPoke.ts @@ -2,20 +2,28 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { GetPacketStatusDepends } from '@/napcat-onebot/action/packet/GetPacketStatus'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - group_id: Type.Optional(Type.String()), - user_id: Type.Optional(Type.String()), - target_id: Type.Optional(Type.String()), +import { PacketActionsExamples } from '../example/PacketActionsExamples'; + +export const SendPokePayloadSchema = Type.Object({ + group_id: Type.Optional(Type.String({ description: '群号' })), + user_id: Type.String({ description: '用户QQ' }), + target_id: Type.Optional(Type.String({ description: '目标QQ' })), }); -type Payload = Static; -export class SendPokeBase extends GetPacketStatusDepends { - override payloadSchema = SchemaData; +export type SendPokePayload = Static; +export class SendPokeBase extends GetPacketStatusDepends { + override payloadSchema = SendPokePayloadSchema; + override returnSchema = Type.Null(); + override actionSummary = '发送戳一戳'; + override actionDescription = '在群聊或私聊中发送戳一戳动作'; + override actionTags = ['核心接口']; + override payloadExample = PacketActionsExamples.SendPoke.payload; + override returnExample = PacketActionsExamples.SendPoke.response; - async _handle (payload: Payload) { + async _handle (payload: SendPokePayload) { // 这里的 !! 可以传入空字符串 忽略这些数据有利用接口统一接口 - const target_id = payload.target_id ? payload.target_id : payload.user_id; - const peer_id = payload.group_id ? payload.group_id : payload.user_id; + const target_id = payload.target_id?.toString() || payload.user_id?.toString(); + const peer_id = payload.group_id?.toString() || payload.user_id?.toString(); const is_group = !!payload.group_id; if (!target_id || !peer_id) { diff --git a/packages/napcat-onebot/action/packet/SetGroupTodo.ts b/packages/napcat-onebot/action/packet/SetGroupTodo.ts index 91df36b7..16c83ee0 100644 --- a/packages/napcat-onebot/action/packet/SetGroupTodo.ts +++ b/packages/napcat-onebot/action/packet/SetGroupTodo.ts @@ -4,25 +4,37 @@ import { GetPacketStatusDepends } from '@/napcat-onebot/action/packet/GetPacketS import { Static, Type } from '@sinclair/typebox'; import { ActionName } from '../router'; -const SchemaData = Type.Object({ - group_id: Type.String(), - message_id: Type.String(), - message_seq: Type.Optional(Type.String()), +import { PacketActionsExamples } from '../example/PacketActionsExamples'; + +export const SetGroupTodoPayloadSchema = Type.Object({ + group_id: Type.Union([Type.String(), Type.Number()], { description: '群号' }), + message_id: Type.Optional(Type.String({ description: '消息ID' })), + message_seq: Type.Optional(Type.String({ description: '消息Seq (可选)' })), }); -type Payload = Static; -export class SetGroupTodo extends GetPacketStatusDepends { - override payloadSchema = SchemaData; +export type SetGroupTodoPayload = Static; +export class SetGroupTodo extends GetPacketStatusDepends { override actionName = ActionName.SetGroupTodo; - async _handle (payload: Payload) { + override payloadSchema = SetGroupTodoPayloadSchema; + override returnSchema = Type.Null(); + override actionSummary = '设置群待办'; + override actionDescription = '将指定消息设置为群待办'; + override actionTags = ['核心接口']; + override payloadExample = PacketActionsExamples.SetGroupTodo.payload; + override returnExample = PacketActionsExamples.SetGroupTodo.response; + + async _handle (payload: SetGroupTodoPayload) { if (payload.message_seq) { - return await this.core.apis.PacketApi.pkt.operation.SetGroupTodo(+payload.group_id, payload.message_seq); + return await this.core.apis.PacketApi.pkt.operation.SetGroupTodo(+payload.group_id, payload.message_seq.toString()); + } + if (!payload.message_id) { + throw new Error('缺少参数 message_id 或 message_seq'); } const peer: Peer = { chatType: ChatType.KCHATTYPEGROUP, - peerUid: payload.group_id, + peerUid: payload.group_id.toString(), }; - const { MsgId, Peer } = MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id) ?? { Peer: peer, MsgId: payload.message_id }; + const { MsgId, Peer } = MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id) ?? { Peer: peer, MsgId: payload.message_id.toString() }; const msg = (await this.core.apis.MsgApi.getMsgsByMsgId(Peer, [MsgId])).msgList[0]; if (!msg) throw new Error('消息不存在'); await this.core.apis.PacketApi.pkt.operation.SetGroupTodo(+payload.group_id, msg.msgSeq); diff --git a/packages/napcat-onebot/action/schemas.ts b/packages/napcat-onebot/action/schemas.ts new file mode 100644 index 00000000..1032ecab --- /dev/null +++ b/packages/napcat-onebot/action/schemas.ts @@ -0,0 +1,98 @@ +import { Type } from '@sinclair/typebox'; + +export const OB11UserSchema = Type.Object({ + birthday_year: Type.Optional(Type.Number({ description: '出生年份' })), + birthday_month: Type.Optional(Type.Number({ description: '出生月份' })), + birthday_day: Type.Optional(Type.Number({ description: '出生日期' })), + phone_num: Type.Optional(Type.String({ description: '手机号' })), + email: Type.Optional(Type.String({ description: '邮箱' })), + category_id: Type.Optional(Type.Number({ description: '分组ID' })), + user_id: Type.Number({ description: 'QQ号' }), + nickname: Type.String({ description: '昵称' }), + remark: Type.Optional(Type.String({ description: '备注' })), + sex: Type.Optional(Type.String({ description: '性别' })), + level: Type.Optional(Type.Number({ description: '等级' })), + age: Type.Optional(Type.Number({ description: '年龄' })), + qid: Type.Optional(Type.String({ description: 'QID' })), + login_days: Type.Optional(Type.Number({ description: '登录天数' })), + categoryName: Type.Optional(Type.String({ description: '分组名称' })), + categoryId: Type.Optional(Type.Number({ description: '分组ID' })), +}, { description: 'OneBot 11 用户信息' }); + +export const OB11GroupSchema = Type.Object({ + group_all_shut: Type.Number({ description: '是否全员禁言' }), + group_remark: Type.String({ description: '群备注' }), + group_id: Type.Number({ description: '群号' }), + group_name: Type.String({ description: '群名称' }), + member_count: Type.Optional(Type.Number({ description: '成员人数' })), + max_member_count: Type.Optional(Type.Number({ description: '最大成员人数' })), +}, { description: 'OneBot 11 群信息' }); + +export const OB11GroupMemberSchema = Type.Object({ + group_id: Type.Number({ description: '群号' }), + user_id: Type.Number({ description: 'QQ号' }), + nickname: Type.String({ description: '昵称' }), + card: Type.Optional(Type.String({ description: '名片' })), + sex: Type.Optional(Type.String({ description: '性别' })), + age: Type.Optional(Type.Number({ description: '年龄' })), + join_time: Type.Optional(Type.Number({ description: '入群时间戳' })), + last_sent_time: Type.Optional(Type.Number({ description: '最后发言时间戳' })), + level: Type.Optional(Type.String({ description: '等级' })), + qq_level: Type.Optional(Type.Number({ description: 'QQ等级' })), + role: Type.Optional(Type.String({ description: '角色 (owner/admin/member)' })), + title: Type.Optional(Type.String({ description: '头衔' })), + area: Type.Optional(Type.String({ description: '地区' })), + unfriendly: Type.Optional(Type.Boolean({ description: '是否不良记录' })), + title_expire_time: Type.Optional(Type.Number({ description: '头衔过期时间' })), + card_changeable: Type.Optional(Type.Boolean({ description: '是否允许修改名片' })), + shut_up_timestamp: Type.Optional(Type.Number({ description: '禁言截止时间戳' })), + is_robot: Type.Optional(Type.Boolean({ description: '是否为机器人' })), + qage: Type.Optional(Type.Number({ description: 'Q龄' })), +}, { description: 'OneBot 11 群成员信息' }); + +export const OB11NotifySchema = Type.Object({ + request_id: Type.Number({ description: '请求ID' }), + invitor_uin: Type.Number({ description: '邀请者QQ' }), + invitor_nick: Type.String({ description: '邀请者昵称' }), + group_id: Type.Number({ description: '群号' }), + group_name: Type.String({ description: '群名称' }), + message: Type.String({ description: '附言' }), + checked: Type.Boolean({ description: '是否已处理' }), + actor: Type.Number({ description: '操作者QQ' }), + requester_nick: Type.String({ description: '申请者昵称' }), +}, { description: 'OneBot 11 通知信息' }); + +export const lastestMessageSchema = Type.Object({ + self_id: Type.Number({ description: '发送者QQ号' }), + user_id: Type.Number({ description: '接收者QQ号' }), + time: Type.Number({ description: '时间戳' }), + real_seq: Type.String({ description: '消息序号' }), + message_type: Type.String({ description: '消息类型' }), + sender: Type.Object({ + user_id: Type.Number({ description: '用户QQ号' }), + nickname: Type.String({ description: '用户昵称' }), + card: Type.Optional(Type.String({ description: '用户名片' })), + role: Type.Optional(Type.String({ description: '用户角色' })), + }), + raw_message: Type.String({ description: '原始消息' }), + font: Type.Number({ description: '字体大小' }), + sub_type: Type.String({ description: '子类型' }), + message: Type.Unknown({ description: '消息内容' }), + message_format: Type.String({ description: '消息格式' }), + post_type: Type.String({ description: '发布类型' }), + group_id: Type.Number({ description: '群号' }), + group_name: Type.String({ description: '群名称' }), +}, { description: '最后一条消息' }); + +export const OB11MessageSchema = Type.Intersect([ + lastestMessageSchema, + Type.Object({ + message_id: Type.Number({ description: '消息ID' }), + message_seq: Type.Number({ description: '消息序列号' }), + emoji_likes_list: Type.Array(Type.Object({ + emoji_id: Type.String({ description: '表情符号ID' }), + emoji_type: Type.String({ description: '表情符号类型' }), + likes_cnt: Type.String({ description: '点赞数' }), + })), + }, { description: 'OneBot 11 消息信息' }) +]); \ No newline at end of file diff --git a/packages/napcat-onebot/action/stream/CleanStreamTempFile.ts b/packages/napcat-onebot/action/stream/CleanStreamTempFile.ts index d66f7114..aa02ecec 100644 --- a/packages/napcat-onebot/action/stream/CleanStreamTempFile.ts +++ b/packages/napcat-onebot/action/stream/CleanStreamTempFile.ts @@ -2,9 +2,18 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { join } from 'node:path'; import { readdir, unlink } from 'node:fs/promises'; +import { Type } from '@sinclair/typebox'; export class CleanStreamTempFile extends OneBotAction { override actionName = ActionName.CleanStreamTempFile; + override actionSummary = '清理流式传输临时文件'; + override actionTags = ['流式传输扩展']; + override payloadExample = {}; + override returnExample = { + message: 'success' + }; + override payloadSchema = Type.Object({}); + override returnSchema = Type.Null(); async _handle (_payload: void): Promise { try { diff --git a/packages/napcat-onebot/action/stream/DownloadFileImageStream.ts b/packages/napcat-onebot/action/stream/DownloadFileImageStream.ts index b5e280ee..5885fcb8 100644 --- a/packages/napcat-onebot/action/stream/DownloadFileImageStream.ts +++ b/packages/napcat-onebot/action/stream/DownloadFileImageStream.ts @@ -7,20 +7,29 @@ import fs from 'fs'; import { imageSizeFallBack } from 'napcat-image-size'; import { BaseDownloadStream, DownloadResult } from './BaseDownloadStream'; -const SchemaData = Type.Object({ - file: Type.Optional(Type.String()), - file_id: Type.Optional(Type.String()), - chunk_size: Type.Optional(Type.Number({ default: 64 * 1024 })), // 默认64KB分块 +export const DownloadFileImageStreamPayloadSchema = Type.Object({ + file: Type.Optional(Type.String({ description: '文件路径或 URL' })), + file_id: Type.Optional(Type.String({ description: '文件 ID' })), + chunk_size: Type.Optional(Type.Number({ default: 64 * 1024, description: '分块大小 (字节)' })), // 默认64KB分块 }); -type Payload = Static; +export type DownloadFileImageStreamPayload = Static; -export class DownloadFileImageStream extends BaseDownloadStream { +export class DownloadFileImageStream extends BaseDownloadStream { override actionName = ActionName.DownloadFileImageStream; - override payloadSchema = SchemaData; + override actionSummary = '下载图片文件流'; + override actionTags = ['流式传输扩展']; + override payloadExample = { + file: 'image_file_id' + }; + override returnExample = { + file: 'temp_image_path' + }; + override payloadSchema = DownloadFileImageStreamPayloadSchema; + override returnSchema = Type.Any({ description: '下载结果 (流式)' }); override useStream = true; - async _handle (payload: Payload, _adaptername: string, _config: NetworkAdapterConfig, req: OneBotRequestToolkit): Promise> { + async _handle (payload: DownloadFileImageStreamPayload, _adaptername: string, _config: NetworkAdapterConfig, req: OneBotRequestToolkit): Promise> { try { payload.file ||= payload.file_id || ''; const chunkSize = payload.chunk_size || 64 * 1024; diff --git a/packages/napcat-onebot/action/stream/DownloadFileRecordStream.ts b/packages/napcat-onebot/action/stream/DownloadFileRecordStream.ts index e5482eab..306e3802 100644 --- a/packages/napcat-onebot/action/stream/DownloadFileRecordStream.ts +++ b/packages/napcat-onebot/action/stream/DownloadFileRecordStream.ts @@ -9,21 +9,30 @@ import { BaseDownloadStream, DownloadResult } from './BaseDownloadStream'; const out_format = ['mp3', 'amr', 'wma', 'm4a', 'spx', 'ogg', 'wav', 'flac']; -const SchemaData = Type.Object({ - file: Type.Optional(Type.String()), - file_id: Type.Optional(Type.String()), - chunk_size: Type.Optional(Type.Number({ default: 64 * 1024 })), // 默认64KB分块 - out_format: Type.Optional(Type.String()), +export const DownloadFileRecordStreamPayloadSchema = Type.Object({ + file: Type.Optional(Type.String({ description: '文件路径或 URL' })), + file_id: Type.Optional(Type.String({ description: '文件 ID' })), + chunk_size: Type.Optional(Type.Number({ default: 64 * 1024, description: '分块大小 (字节)' })), // 默认64KB分块 + out_format: Type.Optional(Type.String({ description: '输出格式' })), }); -type Payload = Static; +export type DownloadFileRecordStreamPayload = Static; -export class DownloadFileRecordStream extends BaseDownloadStream { +export class DownloadFileRecordStream extends BaseDownloadStream { override actionName = ActionName.DownloadFileRecordStream; - override payloadSchema = SchemaData; + override actionSummary = '下载语音文件流'; + override actionTags = ['流式传输扩展']; + override payloadExample = { + file: 'record_file_id' + }; + override returnExample = { + file: 'temp_record_path' + }; + override payloadSchema = DownloadFileRecordStreamPayloadSchema; + override returnSchema = Type.Any({ description: '下载结果 (流式)' }); override useStream = true; - async _handle (payload: Payload, _adaptername: string, _config: NetworkAdapterConfig, req: OneBotRequestToolkit): Promise> { + async _handle (payload: DownloadFileRecordStreamPayload, _adaptername: string, _config: NetworkAdapterConfig, req: OneBotRequestToolkit): Promise> { try { payload.file ||= payload.file_id || ''; const chunkSize = payload.chunk_size || 64 * 1024; diff --git a/packages/napcat-onebot/action/stream/DownloadFileStream.ts b/packages/napcat-onebot/action/stream/DownloadFileStream.ts index e6a08551..54d35092 100644 --- a/packages/napcat-onebot/action/stream/DownloadFileStream.ts +++ b/packages/napcat-onebot/action/stream/DownloadFileStream.ts @@ -5,20 +5,33 @@ import { NetworkAdapterConfig } from '@/napcat-onebot/config/config'; import { StreamPacket, StreamStatus } from './StreamBasic'; import fs from 'fs'; import { BaseDownloadStream, DownloadResult } from './BaseDownloadStream'; -const SchemaData = Type.Object({ - file: Type.Optional(Type.String()), - file_id: Type.Optional(Type.String()), - chunk_size: Type.Optional(Type.Number({ default: 64 * 1024 })), // 默认64KB分块 +const DownloadFileStreamPayloadSchema = Type.Object({ + file: Type.Optional(Type.String({ description: '文件路径或 URL' })), + file_id: Type.Optional(Type.String({ description: '文件 ID' })), + chunk_size: Type.Optional(Type.Number({ default: 64 * 1024, description: '分块大小 (字节)' })), // 默认64KB分块 }); -type Payload = Static; +export type DownloadFileStreamPayload = Static; -export class DownloadFileStream extends BaseDownloadStream { +export class DownloadFileStream extends BaseDownloadStream { override actionName = ActionName.DownloadFileStream; - override payloadSchema = SchemaData; + override payloadSchema = DownloadFileStreamPayloadSchema; + override returnSchema = Type.Any({ description: '下载结果 (流式)' }); + override actionSummary = '下载文件流'; + override actionDescription = '以流式方式从网络或本地下载文件'; + override actionTags = ['流式接口']; + override payloadExample = { + file: 'http://example.com/file.png' + }; + override returnExample = { + type: 'stream', + data_type: 'file_info', + file_name: 'file.png', + file_size: 1024 + }; override useStream = true; - async _handle (payload: Payload, _adaptername: string, _config: NetworkAdapterConfig, req: OneBotRequestToolkit): Promise> { + async _handle (payload: DownloadFileStreamPayload, _adaptername: string, _config: NetworkAdapterConfig, req: OneBotRequestToolkit): Promise> { try { payload.file ||= payload.file_id || ''; const chunkSize = payload.chunk_size || 64 * 1024; diff --git a/packages/napcat-onebot/action/stream/TestStreamDownload.ts b/packages/napcat-onebot/action/stream/TestStreamDownload.ts index dc80c126..a3ac7f86 100644 --- a/packages/napcat-onebot/action/stream/TestStreamDownload.ts +++ b/packages/napcat-onebot/action/stream/TestStreamDownload.ts @@ -4,18 +4,27 @@ import { Static, Type } from '@sinclair/typebox'; import { NetworkAdapterConfig } from '@/napcat-onebot/config/config'; import { StreamPacket, StreamStatus } from './StreamBasic'; -const SchemaData = Type.Object({ - error: Type.Optional(Type.Boolean({ default: false })), +export const TestDownloadStreamPayloadSchema = Type.Object({ + error: Type.Optional(Type.Boolean({ default: false, description: '是否触发测试错误' })), }); -type Payload = Static; +export type TestDownloadStreamPayload = Static; -export class TestDownloadStream extends OneBotAction> { +export class TestDownloadStream extends OneBotAction> { override actionName = ActionName.TestDownloadStream; - override payloadSchema = SchemaData; + override actionSummary = '测试下载流'; + override actionTags = ['流式传输扩展']; + override payloadExample = { + url: 'http://example.com/file' + }; + override returnExample = { + success: true + }; + override payloadSchema = TestDownloadStreamPayloadSchema; + override returnSchema = Type.Any({ description: '测试流数据' }); override useStream = true; - async _handle (_payload: Payload, _adaptername: string, _config: NetworkAdapterConfig, req: OneBotRequestToolkit) { + async _handle (_payload: TestDownloadStreamPayload, _adaptername: string, _config: NetworkAdapterConfig, req: OneBotRequestToolkit) { for (let i = 0; i < 10; i++) { await req.send({ type: StreamStatus.Stream, data: `Index-> ${i + 1}`, data_type: 'data_chunk' }); await new Promise(resolve => setTimeout(resolve, 100)); diff --git a/packages/napcat-onebot/action/stream/UploadFileStream.ts b/packages/napcat-onebot/action/stream/UploadFileStream.ts index fa4a0431..42b12f1b 100644 --- a/packages/napcat-onebot/action/stream/UploadFileStream.ts +++ b/packages/napcat-onebot/action/stream/UploadFileStream.ts @@ -16,21 +16,21 @@ const CONFIG = { MEMORY_LIMIT: 100 * 1024 * 1024, // 100MB内存总限制 } as const; -const SchemaData = Type.Object({ - stream_id: Type.String(), - chunk_data: Type.Optional(Type.String()), - chunk_index: Type.Optional(Type.Number()), - total_chunks: Type.Optional(Type.Number()), - file_size: Type.Optional(Type.Number()), - expected_sha256: Type.Optional(Type.String()), - is_complete: Type.Optional(Type.Boolean()), - filename: Type.Optional(Type.String()), - reset: Type.Optional(Type.Boolean()), - verify_only: Type.Optional(Type.Boolean()), - file_retention: Type.Number({ default: 5 * 60 * 1000 }), // 默认5分钟 回收 不设置或0为不回收 +export const UploadFileStreamPayloadSchema = Type.Object({ + stream_id: Type.String({ description: '流 ID' }), + chunk_data: Type.Optional(Type.String({ description: '分块数据 (Base64)' })), + chunk_index: Type.Optional(Type.Number({ description: '分块索引' })), + total_chunks: Type.Optional(Type.Number({ description: '总分块数' })), + file_size: Type.Optional(Type.Number({ description: '文件总大小' })), + expected_sha256: Type.Optional(Type.String({ description: '期望的 SHA256' })), + is_complete: Type.Optional(Type.Boolean({ description: '是否完成' })), + filename: Type.Optional(Type.String({ description: '文件名' })), + reset: Type.Optional(Type.Boolean({ description: '是否重置' })), + verify_only: Type.Optional(Type.Boolean({ description: '是否仅验证' })), + file_retention: Type.Number({ default: 5 * 60 * 1000, description: '文件保留时间 (毫秒)' }), // 默认5分钟 回收 不设置或0为不回收 }); -type Payload = Static; +export type UploadFileStreamPayload = Static; // 简化流状态接口 interface StreamState { @@ -66,15 +66,33 @@ interface StreamResult { sha256?: string; } -export class UploadFileStream extends OneBotAction> { +export class UploadFileStream extends OneBotAction> { override actionName = ActionName.UploadFileStream; - override payloadSchema = SchemaData; + override payloadSchema = UploadFileStreamPayloadSchema; + override returnSchema = Type.Any({ description: '上传结果 (流式)' }); + override actionSummary = '上传文件流'; + override actionDescription = '以流式方式上传文件数据到机器人'; + override actionTags = ['流式接口']; + override payloadExample = { + stream_id: 'uuid-1234-5678', + chunk_data: 'SGVsbG8gV29ybGQ=', + chunk_index: 0, + total_chunks: 1, + file_size: 11 + }; + override returnExample = { + type: 'stream', + stream_id: 'uuid-1234-5678', + status: 'chunk_received', + received_chunks: 1, + total_chunks: 1 + }; override useStream = true; private static streams = new Map(); private static memoryUsage = 0; - async _handle (payload: Payload, _adaptername: string, _config: NetworkAdapterConfig): Promise> { + async _handle (payload: UploadFileStreamPayload, _adaptername: string, _config: NetworkAdapterConfig): Promise> { const { stream_id, reset, verify_only } = payload; if (reset) { @@ -101,7 +119,7 @@ export class UploadFileStream extends OneBotAction { - async _handle (): Promise { +export type CanSendReturnType = Static; + +export class CanSend extends OneBotAction { + override payloadSchema = Type.Object({}); + override returnSchema = CanSendReturnSchema; + override actionTags = ['系统接口']; + + async _handle (): Promise { return { yes: true, }; @@ -15,4 +22,9 @@ export class CanSend extends OneBotAction { export default class CanSendRecord extends CanSend { override actionName = ActionName.CanSendRecord; + override actionSummary = '是否可以发送语音'; + override actionDescription = '检查是否可以发送语音'; + override actionTags = ['系统接口']; + override payloadExample = {}; + override returnExample = { yes: true }; } diff --git a/packages/napcat-onebot/action/system/CleanCache.ts b/packages/napcat-onebot/action/system/CleanCache.ts index cbb4ad51..b352cf87 100644 --- a/packages/napcat-onebot/action/system/CleanCache.ts +++ b/packages/napcat-onebot/action/system/CleanCache.ts @@ -2,9 +2,17 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { unlink, readdir } from 'fs/promises'; import path, { join } from 'path'; +import { Type } from '@sinclair/typebox'; export class CleanCache extends OneBotAction { override actionName = ActionName.CleanCache; + override payloadSchema = Type.Object({}); + override returnSchema = Type.Null(); + override actionSummary = '清理缓存'; + override actionDescription = '清理缓存'; + override actionTags = ['系统接口']; + override payloadExample = {}; + override returnExample = null; async _handle () { try { diff --git a/packages/napcat-onebot/action/system/GetCSRF.ts b/packages/napcat-onebot/action/system/GetCSRF.ts index 6fe2ee83..b01e2a99 100644 --- a/packages/napcat-onebot/action/system/GetCSRF.ts +++ b/packages/napcat-onebot/action/system/GetCSRF.ts @@ -1,8 +1,24 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; +import { Type, Static } from '@sinclair/typebox'; -export class GetCSRF extends OneBotAction { +export const GetCSRFReturnSchema = Type.Object({ + token: Type.Number({ description: 'CSRF Token' }), +}); + +export type GetCSRFReturnType = Static; + +export class GetCSRF extends OneBotAction { override actionName = ActionName.GetCSRF; + override payloadSchema = Type.Object({}); + override returnSchema = GetCSRFReturnSchema; + override actionSummary = '获取 CSRF Token'; + override actionDescription = '获取 CSRF Token'; + override actionTags = ['系统接口']; + override payloadExample = {}; + override returnExample = { + token: 123456789 + }; async _handle () { const sKey = await this.core.apis.UserApi.getSKey(); diff --git a/packages/napcat-onebot/action/system/GetCredentials.ts b/packages/napcat-onebot/action/system/GetCredentials.ts index 1393e124..5b35fbe1 100644 --- a/packages/napcat-onebot/action/system/GetCredentials.ts +++ b/packages/napcat-onebot/action/system/GetCredentials.ts @@ -2,22 +2,35 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -interface Response { - cookies: string, - token: number -} - -const SchemaData = Type.Object({ - domain: Type.String(), +export const GetCredentialsPayloadSchema = Type.Object({ + domain: Type.String({ description: '需要获取 cookies 的域名' }), }); -type Payload = Static; +export type GetCredentialsPayload = Static; -export class GetCredentials extends OneBotAction { +export const GetCredentialsReturnSchema = Type.Object({ + cookies: Type.String({ description: 'Cookies' }), + token: Type.Number({ description: 'CSRF Token' }), +}); + +export type GetCredentialsResponse = Static; + +export class GetCredentials extends OneBotAction { override actionName = ActionName.GetCredentials; - override payloadSchema = SchemaData; + override payloadSchema = GetCredentialsPayloadSchema; + override returnSchema = GetCredentialsReturnSchema; + override actionSummary = '获取登录凭证'; + override actionDescription = '获取登录凭证'; + override actionTags = ['系统接口']; + override payloadExample = { + domain: 'qun.qq.com' + }; + override returnExample = { + cookies: 'uin=o123456789; skey=@abc12345;', + token: 123456789 + }; - async _handle (payload: Payload) { + async _handle (payload: GetCredentialsPayload) { const cookiesObject = await this.core.apis.UserApi.getCookies(payload.domain); // 把获取到的cookiesObject转换成 k=v; 格式字符串拼接在一起 const cookies = Object.entries(cookiesObject).map(([key, value]) => `${key}=${value}`).join('; '); diff --git a/packages/napcat-onebot/action/system/GetLoginInfo.ts b/packages/napcat-onebot/action/system/GetLoginInfo.ts index 8a8b5cb5..f02aca18 100644 --- a/packages/napcat-onebot/action/system/GetLoginInfo.ts +++ b/packages/napcat-onebot/action/system/GetLoginInfo.ts @@ -2,9 +2,19 @@ import { OB11User } from '@/napcat-onebot/index'; import { OB11Construct } from '@/napcat-onebot/helper/data'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; +import { OB11UserSchema } from '../schemas'; +import { Type } from '@sinclair/typebox'; +import { SystemActionsExamples } from '@/napcat-onebot/action/example/SystemActionsExamples'; -class GetLoginInfo extends OneBotAction { +class GetLoginInfo extends OneBotAction { override actionName = ActionName.GetLoginInfo; + override payloadSchema = Type.Object({}); + override returnSchema = OB11UserSchema; + override actionSummary = '获取登录号信息'; + override actionDescription = '获取当前登录帐号的信息'; + override actionTags = ['系统接口']; + override payloadExample = SystemActionsExamples.GetLoginInfo.payload; + override returnExample = SystemActionsExamples.GetLoginInfo.response; async _handle () { return OB11Construct.selfInfo(this.core.selfInfo); diff --git a/packages/napcat-onebot/action/system/GetStatus.ts b/packages/napcat-onebot/action/system/GetStatus.ts index c6c52816..a7091cb2 100644 --- a/packages/napcat-onebot/action/system/GetStatus.ts +++ b/packages/napcat-onebot/action/system/GetStatus.ts @@ -1,15 +1,30 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; +import { Type, Static } from '@sinclair/typebox'; -interface ResponseType { - online: boolean; - good: boolean; - stat: unknown; -} -export default class GetStatus extends OneBotAction { +export const GetStatusReturnSchema = Type.Object({ + online: Type.Boolean({ description: '是否在线' }), + good: Type.Boolean({ description: '状态是否良好' }), + stat: Type.Unknown({ description: '统计信息' }), +}); + +export type GetStatusReturnType = Static; + +export default class GetStatus extends OneBotAction { override actionName = ActionName.GetStatus; + override payloadSchema = Type.Object({}); + override returnSchema = GetStatusReturnSchema; + override actionSummary = '获取运行状态'; + override actionDescription = '获取运行状态'; + override actionTags = ['系统接口']; + override payloadExample = {}; + override returnExample = { + online: true, + good: true, + stat: {} + }; - async _handle (): Promise { + async _handle (): Promise { return { online: !!this.core.selfInfo.online, good: true, diff --git a/packages/napcat-onebot/action/system/GetSystemMsg.ts b/packages/napcat-onebot/action/system/GetSystemMsg.ts index eaf5340e..4d7a622d 100644 --- a/packages/napcat-onebot/action/system/GetSystemMsg.ts +++ b/packages/napcat-onebot/action/system/GetSystemMsg.ts @@ -1,28 +1,42 @@ import { GroupNotifyMsgStatus } from 'napcat-core'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; -import { Notify } from '@/napcat-onebot/types'; import { Static, Type } from '@sinclair/typebox'; +import { OB11NotifySchema } from '../schemas'; -interface RetData { - invited_requests: Notify[]; - InvitedRequest: Notify[]; - join_requests: Notify[]; -} - -const SchemaData = Type.Object({ - count: Type.Union([Type.Number(), Type.String()], { default: 50 }), +export const GetGroupSystemMsgPayloadSchema = Type.Object({ + count: Type.Union([Type.Number(), Type.String()], { default: 50, description: '获取的消息数量' }), }); -type Payload = Static; +export type GetGroupSystemMsgPayload = Static; -export class GetGroupSystemMsg extends OneBotAction { +export const GetGroupSystemMsgReturnSchema = Type.Object({ + invited_requests: Type.Array(OB11NotifySchema, { description: '进群邀请列表' }), + InvitedRequest: Type.Array(OB11NotifySchema, { description: '进群邀请列表 (兼容)' }), + join_requests: Type.Array(OB11NotifySchema, { description: '进群申请列表' }), +}); + +export type GetGroupSystemMsgReturn = Static; + +export class GetGroupSystemMsg extends OneBotAction { override actionName = ActionName.GetGroupSystemMsg; - override payloadSchema = SchemaData; + override payloadSchema = GetGroupSystemMsgPayloadSchema; + override returnSchema = GetGroupSystemMsgReturnSchema; + override actionSummary = '获取群系统消息'; + override actionDescription = '获取群系统消息'; + override actionTags = ['系统接口']; + override payloadExample = { + count: 50 + }; + override returnExample = { + invited_requests: [], + InvitedRequest: [], + join_requests: [] + }; - async _handle (params: Payload): Promise { + async _handle (params: GetGroupSystemMsgPayload): Promise { const SingleScreenNotifies = await this.core.apis.GroupApi.getSingleScreenNotifies(false, +params.count); - const retData: RetData = { invited_requests: [], InvitedRequest: [], join_requests: [] }; + const retData: GetGroupSystemMsgReturn = { invited_requests: [], InvitedRequest: [], join_requests: [] }; const notifyPromises = SingleScreenNotifies.map(async (SSNotify) => { const invitorUin = SSNotify.user1?.uid ? +await this.core.apis.UserApi.getUinByUidV2(SSNotify.user1.uid) : 0; @@ -30,13 +44,13 @@ export class GetGroupSystemMsg extends OneBotAction { const commonData = { request_id: +SSNotify.seq, invitor_uin: invitorUin, - invitor_nick: SSNotify.user1?.nickName, + invitor_nick: SSNotify.user1?.nickName || '', group_id: +SSNotify.group?.groupCode, - message: SSNotify?.postscript, - group_name: SSNotify.group?.groupName, + message: SSNotify?.postscript || '', + group_name: SSNotify.group?.groupName || '', checked: SSNotify.status !== GroupNotifyMsgStatus.KUNHANDLE, actor: actorUin, - requester_nick: SSNotify.user1?.nickName, + requester_nick: SSNotify.user1?.nickName || '', }; if (SSNotify.type === 1) { diff --git a/packages/napcat-onebot/action/system/GetVersionInfo.ts b/packages/napcat-onebot/action/system/GetVersionInfo.ts index 924c86a6..44c92c6d 100644 --- a/packages/napcat-onebot/action/system/GetVersionInfo.ts +++ b/packages/napcat-onebot/action/system/GetVersionInfo.ts @@ -1,15 +1,30 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { napCatVersion } from 'napcat-common/src/version'; -interface ResponseType { - app_name: string; - protocol_version: string; - app_version: string; -} -export default class GetVersionInfo extends OneBotAction { - override actionName = ActionName.GetVersionInfo; +import { Type, Static } from '@sinclair/typebox'; - async _handle (): Promise { +const ReturnSchema = Type.Object({ + app_name: Type.String({ description: '应用名称' }), + protocol_version: Type.String({ description: '协议版本' }), + app_version: Type.String({ description: '应用版本' }), +}, { description: '版本信息' }); + +type ReturnType = Static; + +export default class GetVersionInfo extends OneBotAction { + override actionName = ActionName.GetVersionInfo; + override returnSchema = ReturnSchema; + override actionSummary = '获取版本信息'; + override actionDescription = '获取版本信息'; + override actionTags = ['系统接口']; + override payloadExample = {}; + override returnExample = { + app_name: 'NapCat.Onebot', + protocol_version: 'v11', + app_version: '1.0.0' + }; + + async _handle (): Promise { return { app_name: 'NapCat.Onebot', protocol_version: 'v11', diff --git a/packages/napcat-onebot/action/system/SetRestart.ts b/packages/napcat-onebot/action/system/SetRestart.ts index 05992629..8113d69e 100644 --- a/packages/napcat-onebot/action/system/SetRestart.ts +++ b/packages/napcat-onebot/action/system/SetRestart.ts @@ -1,9 +1,17 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { OneBotAction } from '../OneBotAction'; import { WebUiDataRuntime } from 'napcat-webui-backend/src/helper/Data'; +import { Type } from '@sinclair/typebox'; export class SetRestart extends OneBotAction { override actionName = ActionName.Reboot; + override payloadSchema = Type.Object({}); + override returnSchema = Type.Null(); + override actionSummary = '重启服务'; + override actionDescription = '重启服务'; + override actionTags = ['系统接口']; + override payloadExample = {}; + override returnExample = null; async _handle () { const result = await WebUiDataRuntime.requestRestartProcess(); diff --git a/packages/napcat-onebot/action/test/TestAutoRegister01.ts b/packages/napcat-onebot/action/test/TestAutoRegister01.ts index 3b44f099..e0550558 100644 --- a/packages/napcat-onebot/action/test/TestAutoRegister01.ts +++ b/packages/napcat-onebot/action/test/TestAutoRegister01.ts @@ -1,10 +1,13 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { ActionHandler } from '../auto-register'; +import { Type } from '@sinclair/typebox'; @ActionHandler export default class TestAutoRegister01 extends OneBotAction { override actionName = ActionName.TestAutoRegister01; + override payloadSchema = Type.Object({}); + override returnSchema = Type.String({ description: '测试返回内容' }); async _handle (_payload: void): Promise { return 'AutoRegister Router Test'; diff --git a/packages/napcat-onebot/action/test/TestAutoRegister02.ts b/packages/napcat-onebot/action/test/TestAutoRegister02.ts index 63cbd10f..f80fae6d 100644 --- a/packages/napcat-onebot/action/test/TestAutoRegister02.ts +++ b/packages/napcat-onebot/action/test/TestAutoRegister02.ts @@ -1,10 +1,13 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { ActionHandler } from '../auto-register'; +import { Type } from '@sinclair/typebox'; @ActionHandler export default class TestAutoRegister02 extends OneBotAction { override actionName = ActionName.TestAutoRegister02; + override payloadSchema = Type.Object({}); + override returnSchema = Type.String({ description: '测试返回内容' }); async _handle (_payload: void): Promise { return 'AutoRegister Router Test'; diff --git a/packages/napcat-onebot/action/user/GetCookies.ts b/packages/napcat-onebot/action/user/GetCookies.ts index bddec828..87bd4194 100644 --- a/packages/napcat-onebot/action/user/GetCookies.ts +++ b/packages/napcat-onebot/action/user/GetCookies.ts @@ -1,22 +1,36 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -interface Response { - cookies: string, - bkn: string -} -const SchemaData = Type.Object({ - domain: Type.String(), +export const GetCookiesPayloadSchema = Type.Object({ + domain: Type.String({ description: '需要获取 cookies 的域名' }), }); -type Payload = Static; +export type GetCookiesPayload = Static; -export class GetCookies extends OneBotAction { +export const GetCookiesReturnSchema = Type.Object({ + cookies: Type.String({ description: 'Cookies' }), + bkn: Type.String({ description: 'CSRF Token' }), +}); + +export type GetCookiesResponse = Static; + +export class GetCookies extends OneBotAction { override actionName = ActionName.GetCookies; - override payloadSchema = SchemaData; + override payloadSchema = GetCookiesPayloadSchema; + override returnSchema = GetCookiesReturnSchema; + override actionSummary = '获取 Cookies'; + override actionDescription = '获取指定域名的 Cookies'; + override actionTags = ['用户接口']; + override payloadExample = { + domain: 'qun.qq.com' + }; + override returnExample = { + cookies: 'uin=o123456789; skey=@abc12345;', + bkn: '123456789' + }; - async _handle (payload: Payload) { + async _handle (payload: GetCookiesPayload) { const cookiesObject = await this.core.apis.UserApi.getCookies(payload.domain); // 把获取到的cookiesObject转换成 k=v; 格式字符串拼接在一起 const cookies = Object.entries(cookiesObject).map(([key, value]) => `${key}=${value}`).join('; '); diff --git a/packages/napcat-onebot/action/user/GetFriendList.ts b/packages/napcat-onebot/action/user/GetFriendList.ts index 956689fb..5013d7f3 100644 --- a/packages/napcat-onebot/action/user/GetFriendList.ts +++ b/packages/napcat-onebot/action/user/GetFriendList.ts @@ -1,20 +1,31 @@ -import { OB11User } from '@/napcat-onebot/index'; import { OB11Construct } from '@/napcat-onebot/helper/data'; import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; +import { OB11UserSchema } from '../schemas'; +import { UserActionsExamples } from '@/napcat-onebot/action/example/UserActionsExamples'; -const SchemaData = Type.Object({ - no_cache: Type.Optional(Type.Union([Type.Boolean(), Type.String()])), +const PayloadSchema = Type.Object({ + no_cache: Type.Optional(Type.Union([Type.Boolean(), Type.String()], { description: '是否不使用缓存' })), }); -type Payload = Static; +type PayloadType = Static; -export default class GetFriendList extends OneBotAction { +const ReturnSchema = Type.Array(OB11UserSchema, { description: '好友列表' }); + +type ReturnType = Static; + +export default class GetFriendList extends OneBotAction { override actionName = ActionName.GetFriendList; - override payloadSchema = SchemaData; + override payloadSchema = PayloadSchema; + override returnSchema = ReturnSchema; + override actionSummary = '获取好友列表'; + override actionDescription = '获取当前帐号的好友列表'; + override actionTags = ['用户接口']; + override payloadExample = UserActionsExamples.GetFriendList.payload; + override returnExample = UserActionsExamples.GetFriendList.response; - async _handle (_payload: Payload) { + async _handle (_payload: PayloadType) { const buddyMap = await this.core.apis.FriendApi.getBuddyV2SimpleInfoMap(); const isNocache = typeof _payload.no_cache === 'string' ? _payload.no_cache === 'true' : !!_payload.no_cache; await Promise.all( diff --git a/packages/napcat-onebot/action/user/GetRecentContact.ts b/packages/napcat-onebot/action/user/GetRecentContact.ts index ad8e5926..b02ba7e0 100644 --- a/packages/napcat-onebot/action/user/GetRecentContact.ts +++ b/packages/napcat-onebot/action/user/GetRecentContact.ts @@ -3,20 +3,50 @@ import { ActionName } from '@/napcat-onebot/action/router'; import { NetworkAdapterConfig } from '@/napcat-onebot/config/config'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - count: Type.Union([Type.Number(), Type.String()], { default: 10 }), +export const GetRecentContactPayloadSchema = Type.Object({ + count: Type.Union([Type.Number(), Type.String()], { default: 10, description: '获取的数量' }), }); -type Payload = Static; +export type GetRecentContactPayload = Static; -export default class GetRecentContact extends OneBotAction { +export const GetRecentContactReturnSchema = Type.Array(Type.Object({ + lastestMsg: Type.Any({ description: '最后一条消息' }), + peerUin: Type.String({ description: '对象QQ' }), + remark: Type.String({ description: '备注' }), + msgTime: Type.String({ description: '消息时间' }), + chatType: Type.Number({ description: '聊天类型' }), + msgId: Type.String({ description: '消息ID' }), + sendNickName: Type.String({ description: '发送者昵称' }), + sendMemberName: Type.String({ description: '发送者群名片' }), + peerName: Type.String({ description: '对象名称' }), +}), { description: '最近会话列表' }); + +export type GetRecentContactReturn = Static; + +export default class GetRecentContact extends OneBotAction { override actionName = ActionName.GetRecentContact; - override payloadSchema = SchemaData; + override payloadSchema = GetRecentContactPayloadSchema; + override returnSchema = GetRecentContactReturnSchema; + override actionSummary = '获取最近会话'; + override actionDescription = '获取最近会话'; + override actionTags = ['用户接口']; + override payloadExample = { + count: 10 + }; + override returnExample = [ + { + peerUin: '123456', + peerName: '测试', + msgTime: '1734567890', + msgId: '12345', + lastestMsg: {} + } + ]; - async _handle (payload: Payload, _adapter: string, config: NetworkAdapterConfig) { + async _handle (payload: GetRecentContactPayload, _adapter: string, config: NetworkAdapterConfig): Promise { const ret = await this.core.apis.UserApi.getRecentContactListSnapShot(+payload.count); // 烘焙消息 - return await Promise.all(ret.info.changedList.map(async (t) => { + const results = await Promise.all(ret.info.changedList.map(async (t) => { const FastMsg = await this.core.apis.MsgApi.getMsgsByMsgId({ chatType: t.chatType, peerUid: t.peerUid }, [t.msgId]); if (FastMsg.msgList.length > 0 && FastMsg.msgList[0]) { // 扩展ret.info.changedList @@ -24,25 +54,27 @@ export default class GetRecentContact extends OneBotAction { return { lastestMsg, peerUin: t.peerUin, - remark: t.remark, + remark: String(t.remark ?? ''), msgTime: t.msgTime, chatType: t.chatType, msgId: t.msgId, - sendNickName: t.sendNickName, - sendMemberName: t.sendMemberName, - peerName: t.peerName, + sendNickName: String(t.sendNickName ?? ''), + sendMemberName: String(t.sendMemberName ?? ''), + peerName: String(t.peerName ?? ''), }; } return { + lastestMsg: undefined, peerUin: t.peerUin, - remark: t.remark, + remark: String(t.remark ?? ''), msgTime: t.msgTime, chatType: t.chatType, msgId: t.msgId, - sendNickName: t.sendNickName, - sendMemberName: t.sendMemberName, - peerName: t.peerName, + sendNickName: String(t.sendNickName ?? ''), + sendMemberName: String(t.sendMemberName ?? ''), + peerName: String(t.peerName ?? ''), }; })); + return results; } } diff --git a/packages/napcat-onebot/action/user/SendLike.ts b/packages/napcat-onebot/action/user/SendLike.ts index 6de00884..66b0863c 100644 --- a/packages/napcat-onebot/action/user/SendLike.ts +++ b/packages/napcat-onebot/action/user/SendLike.ts @@ -1,25 +1,35 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; - -const SchemaData = Type.Object({ - times: Type.Union([Type.Number(), Type.String()], { default: 1 }), - user_id: Type.Union([Type.Number(), Type.String()]), +export const SendLikePayloadSchema = Type.Object({ + user_id: Type.String({ description: '对方 QQ 号' }), + times: Type.Union([Type.Number(), Type.String()], { default: 1, description: '点赞次数' }), }); -type Payload = Static; +export type SendLikePayload = Static; -export default class SendLike extends OneBotAction { +export default class SendLike extends OneBotAction { override actionName = ActionName.SendLike; - override payloadSchema = SchemaData; + override payloadSchema = SendLikePayloadSchema; + override returnSchema = Type.Null(); + override actionSummary = '点赞'; + override actionDescription = '给指定用户点赞'; + override actionTags = ['用户接口']; + override payloadExample = { + user_id: '123456', + times: 10 + }; + override returnExample = {}; + override errorExamples = [ + { code: 1400, description: '点赞失败(频率过快或用户不存在)' } + ]; - async _handle (payload: Payload): Promise { + async _handle (payload: SendLikePayload): Promise { const qq = payload.user_id.toString(); const uid: string = await this.core.apis.UserApi.getUidByUinV2(qq) ?? ''; const result = await this.core.apis.UserApi.like(uid, +payload.times); if (result.result !== 0) { throw new Error(`点赞失败 ${result.errMsg}`); } - return null; } } diff --git a/packages/napcat-onebot/action/user/SetFriendAddRequest.ts b/packages/napcat-onebot/action/user/SetFriendAddRequest.ts index d17105bf..e9f01d42 100644 --- a/packages/napcat-onebot/action/user/SetFriendAddRequest.ts +++ b/packages/napcat-onebot/action/user/SetFriendAddRequest.ts @@ -2,19 +2,29 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - flag: Type.Union([Type.String(), Type.Number()]), - approve: Type.Optional(Type.Union([Type.String(), Type.Boolean()])), - remark: Type.Optional(Type.String()), +export const SetFriendAddRequestPayloadSchema = Type.Object({ + flag: Type.String({ description: '加好友请求的 flag (需从上报中获取)' }), + approve: Type.Optional(Type.Union([Type.String(), Type.Boolean()], { description: '是否同意请求' })), + remark: Type.Optional(Type.String({ description: '添加后的好友备注' })), }); -type Payload = Static; +export type SetFriendAddRequestPayload = Static; -export default class SetFriendAddRequest extends OneBotAction { +export default class SetFriendAddRequest extends OneBotAction { override actionName = ActionName.SetFriendAddRequest; - override payloadSchema = SchemaData; + override payloadSchema = SetFriendAddRequestPayloadSchema; + override returnSchema = Type.Null(); + override actionSummary = '处理加好友请求'; + override actionDescription = '同意或拒绝加好友请求'; + override actionTags = ['用户接口']; + override payloadExample = { + flag: 'flag_12345', + approve: true, + remark: '新朋友' + }; + override returnExample = {}; - async _handle (payload: Payload): Promise { + async _handle (payload: SetFriendAddRequestPayload): Promise { const approve = payload.approve?.toString() !== 'false'; const notify = (await this.core.apis.FriendApi.getBuddyReq()).buddyReqs.find(e => e.reqTime === payload.flag.toString()); if (!notify) { @@ -24,6 +34,5 @@ export default class SetFriendAddRequest extends OneBotAction { if (payload.remark) { await this.core.apis.FriendApi.setBuddyRemark(notify.friendUid, payload.remark); } - return null; } } diff --git a/packages/napcat-onebot/action/user/SetFriendRemark.ts b/packages/napcat-onebot/action/user/SetFriendRemark.ts index a4ce09ee..26442305 100644 --- a/packages/napcat-onebot/action/user/SetFriendRemark.ts +++ b/packages/napcat-onebot/action/user/SetFriendRemark.ts @@ -2,24 +2,36 @@ import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import { ActionName } from '@/napcat-onebot/action/router'; import { Static, Type } from '@sinclair/typebox'; -const SchemaData = Type.Object({ - user_id: Type.String(), - remark: Type.String(), + +export const SetFriendRemarkPayloadSchema = Type.Object({ + user_id: Type.String({ description: '对方 QQ 号' }), + remark: Type.String({ description: '备注内容' }), }); -type Payload = Static; +export type SetFriendRemarkPayload = Static; -export default class SetFriendRemark extends OneBotAction { +export default class SetFriendRemark extends OneBotAction { override actionName = ActionName.SetFriendRemark; - override payloadSchema = SchemaData; + override payloadSchema = SetFriendRemarkPayloadSchema; + override returnSchema = Type.Null(); + override actionSummary = '设置好友备注'; + override actionDescription = '设置好友备注'; + override actionTags = ['用户接口']; + override payloadExample = { + user_id: '123456', + remark: '测试备注' + }; + override returnExample = null; + override errorExamples = [ + { code: 1400, description: '备注设置失败(好友不存在或非法输入)' } + ]; - async _handle (payload: Payload): Promise { - const friendUid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id); + async _handle (payload: SetFriendRemarkPayload): Promise { + const friendUid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString()); const is_friend = await this.core.apis.FriendApi.isBuddy(friendUid); if (!is_friend) { throw new Error(`用户 ${payload.user_id} 不是好友`); } await this.core.apis.FriendApi.setBuddyRemark(friendUid, payload.remark); - return null; } } diff --git a/packages/napcat-onebot/api/index.ts b/packages/napcat-onebot/api/index.ts index 115c4410..760416bb 100644 --- a/packages/napcat-onebot/api/index.ts +++ b/packages/napcat-onebot/api/index.ts @@ -3,3 +3,4 @@ export * from './group'; export * from './user'; export * from './msg'; export * from './quick-action'; +export * from './file'; diff --git a/packages/napcat-onebot/config/index.ts b/packages/napcat-onebot/config/index.ts index 1b689a91..d0276120 100644 --- a/packages/napcat-onebot/config/index.ts +++ b/packages/napcat-onebot/config/index.ts @@ -3,6 +3,8 @@ import type { NapCatCore } from 'napcat-core'; import { OneBotConfig } from './config'; import { AnySchema } from 'ajv'; +export * from './config'; + export class OB11ConfigLoader extends ConfigBase { constructor (core: NapCatCore, configPath: string, schema: AnySchema) { super('onebot11', core, configPath, schema); diff --git a/packages/napcat-onebot/event/index.ts b/packages/napcat-onebot/event/index.ts new file mode 100644 index 00000000..cefa45da --- /dev/null +++ b/packages/napcat-onebot/event/index.ts @@ -0,0 +1,5 @@ +export * from './message'; +export * from './meta'; +export * from './notice'; +export * from './request'; +export * from './OneBotEvent'; diff --git a/packages/napcat-onebot/event/message/index.ts b/packages/napcat-onebot/event/message/index.ts new file mode 100644 index 00000000..e60fecce --- /dev/null +++ b/packages/napcat-onebot/event/message/index.ts @@ -0,0 +1 @@ +export * from './OB11BaseMessageEvent'; diff --git a/packages/napcat-onebot/event/meta/index.ts b/packages/napcat-onebot/event/meta/index.ts new file mode 100644 index 00000000..b44b8ed6 --- /dev/null +++ b/packages/napcat-onebot/event/meta/index.ts @@ -0,0 +1,3 @@ +export * from './OB11BaseMetaEvent'; +export * from './OB11HeartbeatEvent'; +export * from './OB11LifeCycleEvent'; diff --git a/packages/napcat-onebot/event/notice/index.ts b/packages/napcat-onebot/event/notice/index.ts new file mode 100644 index 00000000..2868dec7 --- /dev/null +++ b/packages/napcat-onebot/event/notice/index.ts @@ -0,0 +1,23 @@ +export * from './BotOfflineEvent'; +export * from './OB11BaseNoticeEvent'; +export * from './OB11FriendAddNoticeEvent'; +export * from './OB11FriendRecallNoticeEvent'; +export * from './OB11GroupAdminNoticeEvent'; +export * from './OB11GroupBanEvent'; +export * from './OB11GroupCardEvent'; +export * from './OB11GroupDecreaseEvent'; +export * from './OB11GroupEssenceEvent'; +export * from './OB11GroupGrayTipEvent'; +export * from './OB11GroupIncreaseEvent'; +export * from './OB11GroupNameEvent'; +export * from './OB11GroupNoticeEvent'; +export * from './OB11GroupRecallNoticeEvent'; +export * from './OB11GroupTitleEvent'; +export * from './OB11GroupUploadNoticeEvent'; +export * from './OB11InputStatusEvent'; +export * from './OB11MsgEmojiLikeEvent'; +export * from './OB11OnlineFileNoticeEvent'; +export * from './OB11OnlineFileReceiveEvent'; +export * from './OB11OnlineFileSendEvent'; +export * from './OB11PokeEvent'; +export * from './OB11ProfileLikeEvent'; diff --git a/packages/napcat-onebot/event/request/index.ts b/packages/napcat-onebot/event/request/index.ts new file mode 100644 index 00000000..1951f71d --- /dev/null +++ b/packages/napcat-onebot/event/request/index.ts @@ -0,0 +1,3 @@ +export * from './OB11BaseRequestEvent'; +export * from './OB11FriendRequest'; +export * from './OB11GroupRequest'; diff --git a/packages/napcat-onebot/index.ts b/packages/napcat-onebot/index.ts index af377980..2d109ac1 100644 --- a/packages/napcat-onebot/index.ts +++ b/packages/napcat-onebot/index.ts @@ -701,4 +701,7 @@ export class NapCatOneBot11Adapter { } } -export * from './types'; +export * from './types/index'; +export * from './api/index'; +export * from './event/index'; +export * from './config/index'; diff --git a/packages/napcat-onebot/types/message.ts b/packages/napcat-onebot/types/message.ts index bf566b81..5af54664 100644 --- a/packages/napcat-onebot/types/message.ts +++ b/packages/napcat-onebot/types/message.ts @@ -1,56 +1,5 @@ -import { OB11Sender } from './data'; -import { EventType } from '@/napcat-onebot/event/OneBotEvent'; -import { CustomMusicSignPostData, IdMusicSignPostData, PicSubType, RawMessage } from 'napcat-core'; +import { Type, Static } from '@sinclair/typebox'; -// 消息类型枚举 -export enum OB11MessageType { - private = 'private', - group = 'group', -} - -// 消息接口定义 -export interface OB11Message { - real_seq?: string;// 自行扩展 - temp_source?: number; - message_sent_type?: string; - target_id?: number; // 自己发送消息/私聊消息 - self_id?: number; - time: number; - message_id: number; - message_seq: number; // 和message_id一样 - real_id: number; - user_id: number | string; // number - group_id?: number | string; // number - group_name?: string; // string - message_type: 'private' | 'group'; - sub_type?: 'friend' | 'group' | 'normal'; - sender: OB11Sender; - message: OB11MessageData[] | string; - message_format: 'array' | 'string'; - raw_message: string; - font: number; - post_type?: EventType; - raw?: RawMessage; - emoji_likes_list?: Array<{ emoji_id: string; emoji_type: string; likes_cnt: string; }>;// 仅get_msg生效 -} - -// 合并转发消息接口定义 -export interface OB11ForwardMessage extends OB11Message { - content: OB11MessageData[] | string; -} - -// 返回数据接口定义 -export interface OB11Return { - status: string; - retcode: number; - data: DataType; - message: string; - echo?: unknown; // ws调用api才有此字段 - wording?: string; // go-cqhttp字段,错误信息 - stream?: 'stream-action' | 'normal-action'; // 流式返回标记 -} - -// 消息数据类型枚举 export enum OB11MessageDataType { text = 'text', image = 'image', @@ -76,126 +25,422 @@ export enum OB11MessageDataType { onlinefile = 'onlinefile', // 在线文件/文件夹 flashtransfer = 'flashtransfer', // QQ闪传 } +// ==================== 基础消息段类型 ==================== -export interface OB11MessagePoke { - type: OB11MessageDataType.poke; - data: { - type: string; - id: string; - }; -} +// 纯文本消息段 +export const OB11MessageTextSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.text), + data: Type.Object({ + text: Type.String({ description: '纯文本内容' }), + }), +}, { $id: 'OB11MessageText', description: '纯文本消息段' }); -// 商城表情消息接口定义 -export interface OB11MessageMFace { - type: OB11MessageDataType.mface; - data: { - emoji_package_id: number; - emoji_id: string; - key: string; - summary: string; - }; -} +// 表情消息段 +export const OB11MessageFaceSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.face), + data: Type.Object({ + id: Type.String({ description: '表情ID' }), + resultId: Type.Optional(Type.String({ description: '结果ID' })), + chainCount: Type.Optional(Type.Number({ description: '连击数' })), + }), +}, { $id: 'OB11MessageFace', description: 'QQ表情消息段' }); -// 纯文本消息接口定义 -export interface OB11MessageText { - type: OB11MessageDataType.text; - data: { - text: string; // 纯文本 - }; -} +// 商城表情消息段 +export const OB11MessageMFaceSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.mface), + data: Type.Object({ + emoji_package_id: Type.Number({ description: '表情包ID' }), + emoji_id: Type.String({ description: '表情ID' }), + key: Type.String({ description: '表情key' }), + summary: Type.String({ description: '表情摘要' }), + }), +}, { $id: 'OB11MessageMFace', description: '商城表情消息段' }); -// 联系人消息接口定义 -export interface OB11MessageContact { - type: OB11MessageDataType.contact; - data: { - type: 'qq' | 'group'; - id: string; - }; -} +// @消息段 +export const OB11MessageAtSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.at), + data: Type.Object({ + qq: Type.String({ description: 'QQ号或all' }), + name: Type.Optional(Type.String({ description: '显示名称' })), + }), +}, { $id: 'OB11MessageAt', description: '@消息段' }); -// 文件消息基础接口定义 -export interface OB11MessageFileBase { - data: { - path?: string; - thumb?: string; - name?: string; - file: string; - url?: string; - }; -} +// 回复消息段 +export const OB11MessageReplySchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.reply), + data: Type.Object({ + id: Type.Optional(Type.String({ description: '消息ID的短ID映射' })), + seq: Type.Optional(Type.Number({ description: '消息序列号,优先使用' })), + }), +}, { $id: 'OB11MessageReply', description: '回复消息段' }); -// 图片消息接口定义 -export interface OB11MessageImage extends OB11MessageFileBase { - type: OB11MessageDataType.image; - data: OB11MessageFileBase['data'] & { - summary?: string; // 图片摘要 - sub_type?: PicSubType; - }; -} +// ==================== 文件类消息段 ==================== -// 语音消息接口定义 -export interface OB11MessageRecord extends OB11MessageFileBase { - type: OB11MessageDataType.voice; -} +// 文件消息段基础数据 Schema +export const FileBaseDataSchema = Type.Object({ + file: Type.String({ description: '文件路径/URL/file:///' }), + path: Type.Optional(Type.String({ description: '文件路径' })), + url: Type.Optional(Type.String({ description: '文件URL' })), + name: Type.Optional(Type.String({ description: '文件名' })), + thumb: Type.Optional(Type.String({ description: '缩略图' })), +}, { $id: 'FileBaseData', description: '文件消息段基础数据' }); -// 文件消息接口定义 -export interface OB11MessageFile extends OB11MessageFileBase { - type: OB11MessageDataType.file; -} +// 文件消息基础接口 Schema +export const OB11MessageFileBaseSchema = Type.Object({ + data: FileBaseDataSchema, +}, { $id: 'OB11MessageFileBase', description: '文件消息基础接口' }); -// 视频消息接口定义 -export interface OB11MessageVideo extends OB11MessageFileBase { - type: OB11MessageDataType.video; -} +// 图片消息段 +export const OB11MessageImageSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.image), + data: Type.Intersect([ + FileBaseDataSchema, + Type.Object({ + summary: Type.Optional(Type.String({ description: '图片摘要' })), + sub_type: Type.Optional(Type.Number({ description: '图片子类型' })), + }), + ]), +}, { $id: 'OB11MessageImage', description: '图片消息段' }); -// @消息接口定义 -export interface OB11MessageAt { - type: OB11MessageDataType.at; - data: { - qq: string; // `${number}` | 'all' - name?: string; - }; -} +// 语音消息段 +export const OB11MessageRecordSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.voice), + data: FileBaseDataSchema, +}, { $id: 'OB11MessageRecord', description: '语音消息段' }); -// 回复消息接口定义 -export interface OB11MessageReply { - type: OB11MessageDataType.reply; - data: { - id?: string; // msg_id 的短ID映射 - seq?: number; // msg_seq,优先使用 - }; -} +// 视频消息段 +export const OB11MessageVideoSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.video), + data: FileBaseDataSchema, +}, { $id: 'OB11MessageVideo', description: '视频消息段' }); -// 表情消息接口定义 -export interface OB11MessageFace { - type: OB11MessageDataType.face; - data: { - id: string; - resultId?: string; - chainCount?: number; - }; -} +// 文件消息段 +export const OB11MessageFileSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.file), + data: FileBaseDataSchema, +}, { $id: 'OB11MessageFile', description: '文件消息段' }); -// 混合消息类型定义 -export type OB11MessageMixType = OB11MessageData[] | string | OB11MessageData; +// ==================== 音乐消息段 ==================== -// 合并转发消息节点接口定义 -export interface OB11MessageNode { - type: OB11MessageDataType.node; - data: { - id?: string; - user_id?: number | string; // number - uin?: number | string; // number, compatible with go-cqhttp - nickname: string; - name?: string; // compatible with go-cqhttp - content: OB11MessageMixType; - source?: string; - news?: { text: string; }[]; - summary?: string; - prompt?: string; - time?: string; - }; -} +// ID音乐消息段数据 +const IdMusicDataSchema = Type.Object({ + type: Type.Union([ + Type.Literal('qq'), + Type.Literal('163'), + Type.Literal('kugou'), + Type.Literal('migu'), + Type.Literal('kuwo'), + ], { description: '音乐平台类型' }), + id: Type.Union([Type.String(), Type.Number()], { description: '音乐ID' }), +}); + +// 自定义音乐消息段数据 +const CustomMusicDataSchema = Type.Object({ + type: Type.Union([ + Type.Literal('qq'), + Type.Literal('163'), + Type.Literal('kugou'), + Type.Literal('migu'), + Type.Literal('kuwo'), + Type.Literal('custom'), + ], { description: '音乐平台类型' }), + id: Type.Undefined(), + url: Type.String({ description: '点击后跳转URL' }), + audio: Type.Optional(Type.String({ description: '音频URL' })), + title: Type.Optional(Type.String({ description: '音乐标题' })), + image: Type.String({ description: '封面图片URL' }), + content: Type.Optional(Type.String({ description: '音乐简介' })), +}); + +// ID音乐消息段 +export const OB11MessageIdMusicSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.music), + data: IdMusicDataSchema, +}, { $id: 'OB11MessageIdMusic', description: 'ID音乐消息段' }); + +// 自定义音乐消息段 +export const OB11MessageCustomMusicSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.music), + data: CustomMusicDataSchema, +}, { $id: 'OB11MessageCustomMusic', description: '自定义音乐消息段' }); + +// ==================== 特殊消息段 ==================== + +// 戳一戳消息段 +export const OB11MessagePokeSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.poke), + data: Type.Object({ + type: Type.String({ description: '戳一戳类型' }), + id: Type.String({ description: '戳一戳ID' }), + }), +}, { $id: 'OB11MessagePoke', description: '戳一戳消息段' }); + +// 骰子消息段 +export const OB11MessageDiceSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.dice), + data: Type.Object({ + result: Type.Union([Type.Number(), Type.String()], { description: '骰子结果' }), + }), +}, { $id: 'OB11MessageDice', description: '骰子消息段' }); + +// 猜拳消息段 +export const OB11MessageRPSSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.rps), + data: Type.Object({ + result: Type.Union([Type.Number(), Type.String()], { description: '猜拳结果' }), + }), +}, { $id: 'OB11MessageRPS', description: '猜拳消息段' }); + +// 联系人消息段 +export const OB11MessageContactSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.contact), + data: Type.Object({ + type: Type.Union([Type.Literal('qq'), Type.Literal('group')], { description: '联系人类型' }), + id: Type.String({ description: '联系人ID' }), + }), +}, { $id: 'OB11MessageContact', description: '联系人消息段' }); + +// 位置消息段 +export const OB11MessageLocationSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.location), + data: Type.Object({ + lat: Type.Union([Type.String(), Type.Number()], { description: '纬度' }), + lon: Type.Union([Type.String(), Type.Number()], { description: '经度' }), + title: Type.Optional(Type.String({ description: '标题' })), + content: Type.Optional(Type.String({ description: '内容' })), + }), +}, { $id: 'OB11MessageLocation', description: '位置消息段' }); + +// ==================== 富文本消息段 ==================== + +// JSON消息段 +export const OB11MessageJsonSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.json), + data: Type.Object({ + data: Type.Union([Type.String(), Type.Object({})], { description: 'JSON数据' }), + config: Type.Optional(Type.Object({ + token: Type.String({ description: 'token' }), + })), + }), +}, { $id: 'OB11MessageJson', description: 'JSON消息段' }); + +// XML消息段 +export const OB11MessageXmlSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.xml), + data: Type.Object({ + data: Type.String({ description: 'XML数据' }), + }), +}, { $id: 'OB11MessageXml', description: 'XML消息段' }); + +// Markdown消息段 +export const OB11MessageMarkdownSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.markdown), + data: Type.Object({ + content: Type.String({ description: 'Markdown内容' }), + }), +}, { $id: 'OB11MessageMarkdown', description: 'Markdown消息段' }); + +// 小程序消息段 +export const OB11MessageMiniAppSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.miniapp), + data: Type.Object({ + data: Type.String({ description: '小程序数据' }), + }), +}, { $id: 'OB11MessageMiniApp', description: '小程序消息段' }); + +// ==================== 在线文件消息段 ==================== + +// 在线文件消息段 +export const OB11MessageOnlineFileSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.onlinefile), + data: Type.Object({ + msgId: Type.String({ description: '消息ID' }), + elementId: Type.String({ description: '元素ID' }), + fileName: Type.String({ description: '文件名' }), + fileSize: Type.String({ description: '文件大小' }), + isDir: Type.Boolean({ description: '是否为目录' }), + }), +}, { $id: 'OB11MessageOnlineFile', description: '在线文件消息段' }); + +// 闪传消息段 +export const OB11MessageFlashTransferSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.flashtransfer), + data: Type.Object({ + fileSetId: Type.String({ description: '文件集ID' }), + }), +}, { $id: 'OB11MessageFlashTransfer', description: 'QQ闪传消息段' }); + +// ==================== 合并转发消息段(递归类型)==================== + +// 由于 TypeBox 的递归类型限制,我们需要使用 Type.Recursive +// 但为了与原始类型完全兼容,我们使用 Type.Unknown 来表示递归部分 + +// 合并转发消息节点 +export const OB11MessageNodeSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.node), + data: Type.Object({ + id: Type.Optional(Type.String({ description: '转发消息ID' })), + user_id: Type.Optional(Type.Union([Type.Number(), Type.String()], { description: '发送者QQ号' })), + uin: Type.Optional(Type.Union([Type.Number(), Type.String()], { description: '发送者QQ号(兼容go-cqhttp)' })), + nickname: Type.String({ description: '发送者昵称' }), + name: Type.Optional(Type.String({ description: '发送者昵称(兼容go-cqhttp)' })), + // content 使用 Any 以支持循环引用,实际类型是 OB11MessageMixType + content: Type.Any({ description: '消息内容 (OB11MessageMixType)' }), + source: Type.Optional(Type.String({ description: '消息来源' })), + news: Type.Optional(Type.Array(Type.Object({ + text: Type.String({ description: '新闻文本' }), + }))), + summary: Type.Optional(Type.String({ description: '摘要' })), + prompt: Type.Optional(Type.String({ description: '提示' })), + time: Type.Optional(Type.String({ description: '时间' })), + }), +}, { $id: 'OB11MessageNode', description: '合并转发消息节点' }); + +// 合并转发消息段 +export const OB11MessageForwardSchema = Type.Object({ + type: Type.Literal(OB11MessageDataType.forward), + data: Type.Object({ + id: Type.String({ description: '合并转发ID' }), + // content 使用 Any 以支持类型兼容,实际类型是 OB11Message[] + content: Type.Optional(Type.Any({ description: '消息内容 (OB11Message[])' })), + }), +}, { $id: 'OB11MessageForward', description: '合并转发消息段' }); + +// ==================== 消息段联合类型 ==================== + +// 所有消息段的联合类型(与原始 OB11MessageData 完全一致) +export const OB11MessageDataSchema = Type.Union([ + OB11MessageTextSchema, + OB11MessageFaceSchema, + OB11MessageMFaceSchema, + OB11MessageAtSchema, + OB11MessageReplySchema, + OB11MessageImageSchema, + OB11MessageRecordSchema, + OB11MessageVideoSchema, + OB11MessageFileSchema, + OB11MessageIdMusicSchema, + OB11MessageCustomMusicSchema, + OB11MessagePokeSchema, + OB11MessageDiceSchema, + OB11MessageRPSSchema, + OB11MessageContactSchema, + OB11MessageJsonSchema, + OB11MessageMarkdownSchema, + OB11MessageNodeSchema, + OB11MessageForwardSchema, + OB11MessageOnlineFileSchema, + OB11MessageFlashTransferSchema, +], { $id: 'OB11MessageData', description: 'OneBot 11 消息段' }); + +// 消息混合类型(数组、字符串或单个消息段) +export const OB11MessageMixTypeSchema = Type.Union([ + Type.Array(OB11MessageDataSchema), + Type.String(), + OB11MessageDataSchema, +], { $id: 'OB11MessageMixType', description: 'OneBot 11 消息混合类型' }); + +// ==================== 发送消息请求 ==================== + +// 发送消息请求 +export const OB11PostSendMsgSchema = Type.Object({ + message_type: Type.Optional(Type.Union([Type.Literal('private'), Type.Literal('group')], { description: '消息类型' })), + user_id: Type.Optional(Type.String({ description: '用户QQ号' })), + group_id: Type.Optional(Type.String({ description: '群号' })), + message: OB11MessageMixTypeSchema, + messages: Type.Optional(OB11MessageMixTypeSchema), + auto_escape: Type.Optional(Type.Union([Type.Boolean(), Type.String()], { description: '是否作为纯文本发送' })), + source: Type.Optional(Type.String({ description: '消息来源' })), + news: Type.Optional(Type.Array(Type.Object({ + text: Type.String({ description: '文本' }), + }))), + summary: Type.Optional(Type.String({ description: '摘要' })), + prompt: Type.Optional(Type.String({ description: '提示' })), + time: Type.Optional(Type.String({ description: '时间' })), +}, { $id: 'OB11PostSendMsg', description: 'OneBot 11 发送消息请求' }); + +// ==================== 完整消息对象 ==================== + +// 发送者信息 Schema(注意:OB11Sender 类型已在 data.ts 中定义,这里只提供 Schema) +export const OB11SenderSchema = Type.Object({ + user_id: Type.Union([Type.Number(), Type.String()], { description: '发送者QQ号' }), + nickname: Type.String({ description: '发送者昵称' }), + card: Type.Optional(Type.String({ description: '群名片' })), + role: Type.Optional(Type.String({ description: '角色' })), + sex: Type.Optional(Type.String({ description: '性别' })), + age: Type.Optional(Type.Number({ description: '年龄' })), + area: Type.Optional(Type.String({ description: '地区' })), + level: Type.Optional(Type.String({ description: '等级' })), + title: Type.Optional(Type.String({ description: '头衔' })), +}, { $id: 'OB11Sender', description: 'OneBot 11 发送者信息' }); + +// 完整消息对象 +export const OB11MessageSchema = Type.Object({ + real_seq: Type.Optional(Type.String({ description: '真实序列号' })), + temp_source: Type.Optional(Type.Number({ description: '临时会话来源' })), + message_sent_type: Type.Optional(Type.String({ description: '消息发送类型' })), + target_id: Type.Optional(Type.Number({ description: '目标ID' })), + self_id: Type.Optional(Type.Number({ description: '机器人QQ号' })), + time: Type.Number({ description: '消息时间戳' }), + message_id: Type.Number({ description: '消息ID' }), + message_seq: Type.Number({ description: '消息序列号' }), + real_id: Type.Number({ description: '真实ID' }), + user_id: Type.Union([Type.Number(), Type.String()], { description: '发送者QQ号' }), + group_id: Type.Optional(Type.Union([Type.Number(), Type.String()], { description: '群号' })), + group_name: Type.Optional(Type.String({ description: '群名称' })), + message_type: Type.Union([Type.Literal('private'), Type.Literal('group')], { description: '消息类型' }), + sub_type: Type.Optional(Type.Union([ + Type.Literal('friend'), + Type.Literal('group'), + Type.Literal('normal'), + ], { description: '消息子类型' })), + sender: OB11SenderSchema, + message: Type.Union([Type.Array(OB11MessageDataSchema), Type.String()], { description: '消息内容' }), + message_format: Type.Union([Type.Literal('array'), Type.Literal('string')], { description: '消息格式' }), + raw_message: Type.String({ description: '原始消息' }), + font: Type.Number({ description: '字体' }), + post_type: Type.Optional(Type.String({ description: '上报类型' })), + raw: Type.Optional(Type.Unknown({ description: '原始消息对象' })), + emoji_likes_list: Type.Optional(Type.Array(Type.Object({ + emoji_id: Type.String({ description: '表情ID' }), + emoji_type: Type.String({ description: '表情类型' }), + likes_cnt: Type.String({ description: '点赞数' }), + }), { description: '表情点赞列表' })), +}, { $id: 'OB11Message', description: 'OneBot 11 完整消息对象' }); + +// ==================== TypeScript 类型导出 ==================== + +export type OB11MessageText = Static; +export type OB11MessageFace = Static; +export type OB11MessageMFace = Static; +export type OB11MessageAt = Static; +export type OB11MessageReply = Static; +export type OB11MessageFileBase = Static; +export type OB11MessageImage = Static; +export type OB11MessageRecord = Static; +export type OB11MessageVideo = Static; +export type OB11MessageFile = Static; +export type OB11MessageIdMusic = Static; +export type OB11MessageCustomMusic = Static; +export type OB11MessagePoke = Static; +export type OB11MessageDice = Static; +export type OB11MessageRPS = Static; +export type OB11MessageContact = Static; +export type OB11MessageLocation = Static; +export type OB11MessageJson = Static; +export type OB11MessageXml = Static; +export type OB11MessageMarkdown = Static; +export type OB11MessageMiniApp = Static; +export type OB11MessageNode = Static; +export type OB11MessageForward = Static; +export type OB11MessageOnlineFile = Static; +export type OB11MessageFlashTransfer = Static; +export type OB11MessageData = Static; +export type OB11MessageMixType = Static; +export type OB11PostSendMsg = Static; +// 注意:OB11Sender 类型已在 data.ts 中定义,避免重复导出 +// export type OB11Sender = Static; +export type OB11Message = Static; // 合并转发消息节点纯文本接口定义 export type OB11MessageNodePlain = OB11MessageNode & { @@ -205,101 +450,28 @@ export type OB11MessageNodePlain = OB11MessageNode & { }; }; -// 音乐消息接口定义 -export interface OB11MessageIdMusic { - type: OB11MessageDataType.music; - data: IdMusicSignPostData; -} - -// 自定义音乐消息接口定义 -export interface OB11MessageCustomMusic { - type: OB11MessageDataType.music; - data: Omit & { content?: string; }; -} - -// JSON消息接口定义 -export interface OB11MessageJson { - type: OB11MessageDataType.json; - data: { config?: { token: string; }, data: string | object; }; -} - -// 骰子消息接口定义 -export interface OB11MessageDice { - type: OB11MessageDataType.dice; - data: { - result: number /* intended */ | string /* in fact */; - }; -} - -// 猜拳消息接口定义 -export interface OB11MessageRPS { - type: OB11MessageDataType.rps; - data: { - result: number | string; - }; -} - -// Markdown消息接口定义 -export interface OB11MessageMarkdown { - type: OB11MessageDataType.markdown; - data: { - content: string; - }; +// 返回数据接口定义 +export interface OB11Return { + status: string; + retcode: number; + data: DataType; + message: string; + echo?: unknown; // ws调用api才有此字段 + wording?: string; // go-cqhttp字段,错误信息 + stream?: 'stream-action' | 'normal-action'; // 流式返回标记 } // 合并转发消息接口定义 -export interface OB11MessageForward { - type: OB11MessageDataType.forward; - data: { - id: string; - content?: OB11Message[]; - }; +export interface OB11ForwardMessage extends OB11Message { + content: OB11MessageData[] | string; } -export interface OB11MessageOnlineFile { - type: OB11MessageDataType.onlinefile; - data: { - msgId: string; - elementId: string; - fileName: string; - fileSize: string; - isDir: boolean; - } +// 消息类型枚举 +export enum OB11MessageType { + private = 'private', + group = 'group', } -export interface OB11MessageFlashTransfer { - type: OB11MessageDataType.flashtransfer; - data: { - fileSetId: string; - } -} - -// 消息数据类型定义 -export type OB11MessageData = - OB11MessageText | - OB11MessageFace | OB11MessageMFace | - OB11MessageAt | OB11MessageReply | - OB11MessageImage | OB11MessageRecord | OB11MessageFile | OB11MessageVideo | - OB11MessageNode | OB11MessageIdMusic | OB11MessageCustomMusic | OB11MessageJson | - OB11MessageDice | OB11MessageRPS | OB11MessageMarkdown | OB11MessageForward | OB11MessageContact | - OB11MessagePoke | OB11MessageOnlineFile | OB11MessageFlashTransfer; - -// 发送消息接口定义 -export interface OB11PostSendMsg { - message_type?: 'private' | 'group'; - user_id?: string; - group_id?: string; - message: OB11MessageMixType; - messages?: OB11MessageMixType; - auto_escape?: boolean | string; - source?: string; - news?: { text: string; }[]; - summary?: string; - prompt?: string; - time?: string; -} - -// 上下文接口定义 export interface OB11PostContext { message_type?: 'private' | 'group'; user_id?: string; diff --git a/packages/napcat-plugin-builtin/index.ts b/packages/napcat-plugin-builtin/index.ts index 6b1dc263..858d7847 100644 --- a/packages/napcat-plugin-builtin/index.ts +++ b/packages/napcat-plugin-builtin/index.ts @@ -1,7 +1,7 @@ -import type { ActionMap } from 'napcat-onebot/action'; -import { EventType } from 'napcat-onebot/event/OneBotEvent'; -import type { PluginModule } from 'napcat-onebot/network/plugin'; -import type { OB11Message, OB11PostSendMsg } from 'napcat-onebot/types/message'; +import type { ActionMap } from 'napcat-types/dist/napcat-onebot/action/index'; +import { EventType } from 'napcat-types/dist/napcat-onebot/event/index'; +import type { PluginModule } from 'napcat-types/dist/napcat-onebot/network/plugin-manger'; +import type { OB11Message, OB11PostSendMsg } from 'napcat-types/dist/napcat-onebot/types/index'; let actions: ActionMap | undefined = undefined; let startTime: number = Date.now(); diff --git a/packages/napcat-plugin-builtin/package.json b/packages/napcat-plugin-builtin/package.json index 2f4a5bfe..93833dfe 100644 --- a/packages/napcat-plugin-builtin/package.json +++ b/packages/napcat-plugin-builtin/package.json @@ -6,7 +6,7 @@ "description": "NapCat 内置插件", "author": "NapNeko", "dependencies": { - "napcat-onebot": "workspace:*" + "napcat-types": "workspace:*" }, "devDependencies": { "@types/node": "^22.0.1" diff --git a/packages/napcat-plugin/index.ts b/packages/napcat-plugin/index.ts index 2a5b07bc..e3c64029 100644 --- a/packages/napcat-plugin/index.ts +++ b/packages/napcat-plugin/index.ts @@ -1,6 +1,6 @@ -import type { createActionMap } from 'napcat-onebot/action'; -import { EventType } from 'napcat-onebot/event/OneBotEvent'; -import type { PluginModule } from 'napcat-onebot/network/plugin'; +import type { createActionMap } from 'napcat-types/dist/napcat-onebot/action/index.js'; +import { EventType } from 'napcat-types/dist/napcat-onebot/event/index.js'; +import type { PluginModule } from 'napcat-types/dist/napcat-onebot/network/plugin-manger'; /** * 导入 napcat 包时候不使用 @/napcat...,直接使用 napcat... diff --git a/packages/napcat-plugin/package.json b/packages/napcat-plugin/package.json index b48058da..e89cd6b0 100644 --- a/packages/napcat-plugin/package.json +++ b/packages/napcat-plugin/package.json @@ -5,7 +5,7 @@ "main": "index.mjs", "description": "一个高级的 NapCat 插件示例", "dependencies": { - "napcat-onebot": "workspace:*" + "napcat-types": "workspace:*" }, "devDependencies": { "@types/node": "^22.0.1" diff --git a/packages/napcat-schema/index.ts b/packages/napcat-schema/index.ts new file mode 100644 index 00000000..513339bb --- /dev/null +++ b/packages/napcat-schema/index.ts @@ -0,0 +1,219 @@ +import { getAllHandlers } from '@/napcat-onebot/action/index'; +import { AutoRegisterRouter } from '@/napcat-onebot/action/auto-register'; +import { writeFileSync, existsSync } from 'node:fs'; +import { resolve, dirname } from 'node:path'; +import { TSchema } from '@sinclair/typebox'; +import { fileURLToPath } from 'node:url'; +import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; +import { napCatVersion } from 'napcat-common/src/version'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +interface ActionSchemaInfo { + payload?: TSchema; + return?: TSchema; + summary?: string; + description?: string; + tags?: string[]; + payloadExample?: unknown; + returnExample?: unknown; + errorExamples?: Array<{ code: number, description: string; }>; +} + +export const actionSchemas: Record = {}; + +export function initSchemas () { + const handlers = getAllHandlers(null as any, null as any); + handlers.forEach(handler => { + if (handler.actionName && (handler.actionName as string) !== 'unknown') { + const action = handler as OneBotAction; + actionSchemas[handler.actionName] = { + payload: action.payloadSchema, + return: action.returnSchema, + summary: action.actionSummary, + description: action.actionDescription, + tags: action.actionTags, + payloadExample: action.payloadExample, + returnExample: action.returnExample, + errorExamples: action.errorExamples + }; + } + }); + AutoRegisterRouter.forEach((ActionClass) => { + const handler = new ActionClass(null as any, null as any); + if (handler.actionName && (handler.actionName as string) !== 'unknown') { + const action = handler as OneBotAction; + actionSchemas[handler.actionName] = { + payload: action.payloadSchema, + return: action.returnSchema, + summary: action.actionSummary, + description: action.actionDescription, + tags: action.actionTags, + payloadExample: action.payloadExample, + returnExample: action.returnExample, + errorExamples: action.errorExamples + }; + } + }); +} + +export function generateOpenAPI () { + try { + initSchemas(); + } catch (e) { + console.warn('Init schemas partial failure, proceeding with collected data...'); + } + + const openapi: Record = { + openapi: '3.0.1', + info: { + title: 'NapCat OneBot 11 HTTP API', + description: 'NapCatOneBot11 HTTP POST 接口文档', + version: napCatVersion + }, + tags: [ + { name: '消息接口', description: '发送、删除、获取消息相关接口' }, + { name: '群组接口', description: '群组管理、成员管理相关接口' }, + { name: '用户接口', description: '好友管理、个人信息相关接口' }, + { name: '系统接口', description: '状态获取、重启、缓存清理相关接口' }, + { name: '文件接口', description: '文件上传下载、预览相关接口' } + ], + paths: {} as Record, + components: { + schemas: {}, + responses: {}, + securitySchemes: {} + }, + servers: [], + security: [] + }; + + for (const [actionName, schemas] of Object.entries(actionSchemas)) { + if (!schemas.payload && !schemas.summary) continue; + + const path = '/' + actionName; + const cleanPayload = schemas.payload ? JSON.parse(JSON.stringify(schemas.payload)) : { type: 'object', properties: {} }; + const cleanReturn = schemas.return ? JSON.parse(JSON.stringify(schemas.return)) : { type: 'object', properties: {} }; + + // 构造响应示例 + const responseExamples: Record = { + 'Success': { + summary: '成功响应', + value: { + status: 'ok', + retcode: 0, + data: schemas.returnExample || {}, + message: '', + wording: '' + } + } + }; + + if (schemas.errorExamples) { + schemas.errorExamples.forEach(error => { + responseExamples['Error_' + error.code] = { + summary: error.description, + value: { + status: 'failed', + retcode: error.code, + data: null, + message: error.description, + wording: error.description + } + }; + }); + } else { + // 默认提供一个通用错误 + responseExamples['Generic_Error'] = { + summary: '通用错误', + value: { + status: 'failed', + retcode: 1400, + data: null, + message: '请求参数错误或业务逻辑执行失败', + wording: '请求参数错误或业务逻辑执行失败' + } + }; + } + + const paths = openapi['paths'] as Record; + paths[path] = { + post: { + summary: schemas.summary || actionName, + deprecated: false, + description: schemas.description || '', + tags: schemas.tags || [], + parameters: [], + requestBody: { + description: 'API 参数', + content: { + 'application/json': { + schema: cleanPayload, + examples: { + 'Default': { + summary: '默认请求示例', + value: schemas.payloadExample || {} + } + } + } + } + }, + responses: { + '200': { + description: '业务响应', + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + status: { type: 'string', description: '状态 (ok/failed)' }, + retcode: { type: 'number', description: '返回码' }, + data: { ...cleanReturn, description: '数据' }, + message: { type: 'string', description: '消息' }, + wording: { type: 'string', description: '提示' } + }, + required: ['status', 'retcode', 'data'] + }, + examples: responseExamples + } + } + } + }, + security: [] + } + }; + } + + const outputPath = resolve(__dirname, 'openapi.json'); + writeFileSync(outputPath, JSON.stringify(openapi, null, 2)); + console.log('OpenAPI schema (3.0.1 Format) generated at: ' + outputPath); + + generateMissingReport(); +} + +function generateMissingReport () { + const missingReport: string[] = []; + for (const [actionName, schemas] of Object.entries(actionSchemas)) { + const missing: string[] = []; + if (!schemas.summary) missing.push('actionSummary'); + if (!schemas.tags || schemas.tags.length === 0) missing.push('actionTags'); + if (schemas.payloadExample === undefined && schemas.payload) missing.push('payloadExample'); + if (schemas.returnExample === undefined) missing.push('returnExample'); + + if (missing.length > 0) { + missingReport.push('[' + actionName + '] 缺失属性: ' + missing.join(', ')); + } + } + + const reportPath = resolve(__dirname, 'missing_props.log'); + if (missingReport.length > 0) { + writeFileSync(reportPath, missingReport.join('\n')); + console.warn('\n检查到 ' + missingReport.length + ' 个接口存在元数据缺失,报告已保存至: ' + reportPath); + } else { + if (existsSync(reportPath)) writeFileSync(reportPath, ''); + console.log('\n所有接口元数据已完整!'); + } +} + +generateOpenAPI(); diff --git a/packages/napcat-schema/package.json b/packages/napcat-schema/package.json new file mode 100644 index 00000000..3455497b --- /dev/null +++ b/packages/napcat-schema/package.json @@ -0,0 +1,20 @@ +{ + "name": "napcat-schema", + "version": "1.0.0", + "private": true, + "type": "module", + "main": "index.ts", + "scripts": { + "build:openapi": "vite build & node ./dist/schemas.mjs" + }, + "dependencies": { + "@sinclair/typebox": "^0.34.38", + "napcat-onebot": "workspace:*", + "napcat-common": "workspace:*", + "napcat-vite": "workspace:*" + }, + "devDependencies": { + "tsx": "^4.7.1", + "vite": "^6.0.0" + } +} \ No newline at end of file diff --git a/packages/napcat-schema/tsconfig.json b/packages/napcat-schema/tsconfig.json new file mode 100644 index 00000000..2101dac0 --- /dev/null +++ b/packages/napcat-schema/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "include": [ + "*.ts", + "**/*.ts", + ], + "exclude": [ + "node_modules", + "dist" + ] +} \ No newline at end of file diff --git a/packages/napcat-schema/vite.config.ts b/packages/napcat-schema/vite.config.ts new file mode 100644 index 00000000..e77ccdd4 --- /dev/null +++ b/packages/napcat-schema/vite.config.ts @@ -0,0 +1,47 @@ +import { defineConfig } from 'vite'; +import path, { resolve } from 'path'; +import { builtinModules } from 'module'; +import nodeResolve from '@rollup/plugin-node-resolve'; +import napcatVersion from 'napcat-vite/vite-plugin-version'; +// 依赖排除 +const external = [ + 'ws', + 'express', + 'electron' +]; +const nodeModules = [...builtinModules, builtinModules.map((m) => `node:${m}`)].flat(); + +export default defineConfig({ + resolve: { + conditions: ['node', 'default'], + alias: { + '@/napcat-core': resolve(__dirname, '../napcat-core'), + '@/napcat-common': resolve(__dirname, '../napcat-common'), + '@/napcat-onebot': resolve(__dirname, '../napcat-onebot'), + '@/napcat-pty': resolve(__dirname, '../napcat-pty'), + '@/napcat-webui-backend': resolve(__dirname, '../napcat-webui-backend'), + '@/image-size': resolve(__dirname, '../image-size'), + }, + }, + plugins: [ + nodeResolve(), + napcatVersion() + ], + build: { + target: 'esnext', + minify: false, + emptyOutDir: true, + outDir: 'dist', + lib: { + entry: path.resolve(__dirname, './index.ts'), + formats: ['es'], + fileName: () => 'schemas.mjs', + }, + rollupOptions: { + external: [ + ...nodeModules, + ...external + ] + }, + }, +}); diff --git a/packages/napcat-types/README.md b/packages/napcat-types/README.md new file mode 100644 index 00000000..2205c1e4 --- /dev/null +++ b/packages/napcat-types/README.md @@ -0,0 +1,3 @@ +# NapCat-Types + + NapCat 类型定义包,包含 NapCat 及其插件开发所需的所有类型定义。 \ No newline at end of file diff --git a/packages/napcat-types/external-shims.d.ts b/packages/napcat-types/external-shims.d.ts new file mode 100644 index 00000000..6348f911 --- /dev/null +++ b/packages/napcat-types/external-shims.d.ts @@ -0,0 +1,178 @@ +// 外部模块 shim,提供最小的可运行值和类型,避免类型包依赖外部环境 +// node:* 模块移除 mock,使用系统自带类型 + +// (ws/express/winston) now provided by real type deps (@types/ws, @types/express, winston) + +declare module 'ffmpeg-static' { + const _ffmpeg_static_default: any; + export default _ffmpeg_static_default; +} + +declare module 'fluent-ffmpeg' { + const _fluent_ffmpeg_default: any; + export default _fluent_ffmpeg_default; +} + +declare module 'sharp' { + const _sharp_default: any; + export default _sharp_default; +} + +declare module 'uuid' { + export function v4 (...args: any[]): string; +} + +declare module 'axios' { + const _axios_default: any; + export default _axios_default; +} + +declare module 'body-parser' { + const _body_parser_default: any; + export default _body_parser_default; +} + +declare module 'cors' { + const _cors_default: any; + export default _cors_default; +} + +declare module 'file-type' { + export function fileTypeFromFile (path: string): Promise; +} + +declare module 'image-size' { + const _image_size_default: any; + export default _image_size_default; +} + +declare module 'jimp' { + const _jimp_default: any; + export default _jimp_default; +} + +declare module 'qrcode' { + const _qrcode_default: any; + export default _qrcode_default; +} + +declare module 'yaml' { + export const parse: (...args: any[]) => any; + export const stringify: (...args: any[]) => any; +} + +declare module 'async-mutex' { + export class Mutex { + acquire (): Promise<() => void>; + runExclusive (callback: () => T | Promise): Promise; + } + export class Semaphore { + acquire (): Promise<[() => void, number]>; + runExclusive (callback: () => T | Promise): Promise; + release (): void; + } + const _async_mutex_default: { Mutex: typeof Mutex; Semaphore: typeof Semaphore; }; + export default _async_mutex_default; +} + +declare module '@sinclair/typebox' { + export const Type: { + Object: (...args: any[]) => any; + String: (...args: any[]) => any; + Number: (...args: any[]) => any; + Boolean: (...args: any[]) => any; + Array: (...args: any[]) => any; + Union: (...args: any[]) => any; + Literal: (...args: any[]) => any; + Optional: (...args: any[]) => any; + Record: (...args: any[]) => any; + Any: (...args: any[]) => any; + } & any; + + // Make Static<> actually resolve to a structural type so optional properties work. + export type Static = T extends { static: infer S; } ? S : any; + + export interface TSchema { static?: any; } + export interface TObject extends TSchema { } + export interface TOptional extends TSchema { } + export interface TNumber extends TSchema { } + export interface TString extends TSchema { } + export interface TBoolean extends TSchema { } + export interface TArray extends TSchema { } + export interface TUnion extends TSchema { } + export interface TLiteral extends TSchema { } + export interface TAny extends TSchema { } + export interface TNull extends TSchema { } + export interface TUndefined extends TSchema { } + export interface TVoid extends TSchema { } +} + +declare module 'napcat-protobuf' { + export class NapProtoMsg { + constructor (schema: any); + decode (buffer: any): T; + encode (value: any): Uint8Array; + } + export function ProtoField (...args: any[]): any; + export type NapProtoEncodeStructType = any; + export type NapProtoDecodeStructType = any; + export type ScalarProtoFieldType = any; + export type MessageProtoFieldType = any; + export const ScalarType: { + STRING: any; + INT64: any; + INT32: any; + UINT32: any; + UINT64: any; + BYTES: any; + BOOL: any; + [key: string]: any; + }; +} + +declare module 'inversify' { + export class Container { + bind: (...args: any[]) => any; + get: (id: any) => T; + } + export function injectable (...args: any[]): any; + export function inject (...args: any[]): any; + export interface ServiceIdentifier { } + const _inversify_default: any; + export default _inversify_default; +} + +declare module 'ajv' { + export interface AnySchema { [key: string]: any; } + + export interface ErrorObject { + keyword: string; + instancePath: string; + schemaPath: string; + params: any; + message?: string; + } + + export interface ValidateFunction { + (data: any): data is T; + errors: ErrorObject[] | null; + } + + class Ajv { + constructor (...args: any[]); + compile (schema: any): ValidateFunction; + validate (schemaOrRef: any, data: any): boolean; + errorsText (errors?: any, options?: any): string; + errors: ErrorObject[] | null; + } + + export default Ajv; + export { Ajv, ValidateFunction, ErrorObject }; +} + +declare module 'ip' { + export function toBuffer (ip: any, buffer?: Buffer, offset?: number): Buffer; + export function toString (buffer: any, offset?: number, length?: number): string; + const _ip_default: any; + export default _ip_default; +} diff --git a/packages/napcat-types/index.ts b/packages/napcat-types/index.ts new file mode 100644 index 00000000..62fcf6db --- /dev/null +++ b/packages/napcat-types/index.ts @@ -0,0 +1,9 @@ +/// +// 聚合导出核心库的所有内容(包括枚举、类和类型) +export * from '../napcat-core/index'; + +// 聚合导出 OneBot 的所有内容 +export * from '../napcat-onebot/index'; + +// Ensure the shims file exists next to the emitted JS as well. +export type { }; diff --git a/packages/napcat-types/package.json b/packages/napcat-types/package.json new file mode 100644 index 00000000..b450c63f --- /dev/null +++ b/packages/napcat-types/package.json @@ -0,0 +1,30 @@ +{ + "name": "napcat-types", + "version": "0.0.1", + "private": false, + "type": "module", + "types": "./dist/napcat-types/index.d.ts", + "files": [ + "dist/**/*" + ], + "scripts": { + "build": "tsc --project tsconfig.json && tsc-alias --project tsconfig.json --outDir dist && node ./scripts/copy-dist.mjs", + "test": "pnpm -s exec tsc --project tsconfig.json --noEmit", + "publish": "cd dist && npm publish" + }, + "dependencies": { + "@types/node": "^22.10.7", + "@types/express": "^4.17.21", + "@types/ws": "^8.5.12", + "@types/cors": "^2.8.17", + "@types/multer": "^1.4.12", + "@types/winston": "^2.4.4", + "@types/yaml": "^1.9.7", + "@types/ip": "^1.1.3" + }, + "devDependencies": { + "napcat-core": "workspace:*", + "napcat-onebot": "workspace:*", + "tsc-alias": "^1.8.16" + } +} \ No newline at end of file diff --git a/packages/napcat-types/package.public.json b/packages/napcat-types/package.public.json new file mode 100644 index 00000000..6e9a45e7 --- /dev/null +++ b/packages/napcat-types/package.public.json @@ -0,0 +1,25 @@ +{ + "name": "napcat-types", + "version": "0.0.2", + "private": false, + "type": "module", + "types": "./napcat-types/index.d.ts", + "files": [ + "./**/*" + ], + "dependencies": { + "@types/node": "^22.10.7", + "@types/express": "^4.17.21", + "@types/ws": "^8.5.12", + "@types/cors": "^2.8.17", + "@types/multer": "^1.4.12", + "@types/winston": "^2.4.4", + "@types/yaml": "^1.9.7", + "@types/ip": "^1.1.3" + }, + "publishConfig": { + "registry": "https://registry.npmjs.org/", + "access": "public", + "tag": "latest" + } +} \ No newline at end of file diff --git a/packages/napcat-types/scripts/copy-dist.mjs b/packages/napcat-types/scripts/copy-dist.mjs new file mode 100644 index 00000000..4cf85167 --- /dev/null +++ b/packages/napcat-types/scripts/copy-dist.mjs @@ -0,0 +1,13 @@ +// 复制 cp README.md dist/ && cp package.public.json dist/package.json +import { copyFile } from 'node:fs/promises'; +import { join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +const __dirname = fileURLToPath(new URL('../', import.meta.url)); +await copyFile( + join(__dirname, 'package.public.json'), + join(__dirname, 'dist', 'package.json') +); +await copyFile( + join(__dirname, 'README.md'), + join(__dirname, 'dist', 'README.md') +); \ No newline at end of file diff --git a/packages/napcat-types/test-dist.ts b/packages/napcat-types/test-dist.ts new file mode 100644 index 00000000..292ecf09 --- /dev/null +++ b/packages/napcat-types/test-dist.ts @@ -0,0 +1,38 @@ +import { + ChatType, + ElementType, + NapCatCore, + NTQQMsgApi, + NapCatOneBot11Adapter, + OB11Message, + OB11BaseMessageEvent, + OB11BaseMetaEvent, +} from './dist/napcat-types/index'; + +console.log('--- NapCat Comprehensive Type Test ---'); + +// 1. 测试枚举 (Core) +console.log('ChatType.KCHATTYPEGROUP:', ChatType.KCHATTYPEGROUP); // 应输出 2 +console.log('ElementType.TEXT:', ElementType.TEXT); // 应输出 1 + +// 2. 测试类型 (Core) +const coreStub = {} as NapCatCore; +const apiStub = {} as NTQQMsgApi; +console.log('Core types access check: OK'); + +// 3. 测试类和类型 (OneBot) +const obAdapterStub = {} as NapCatOneBot11Adapter; +const obMsgStub = {} as OB11Message; +const baseMessageEventStub = {} as OB11BaseMessageEvent; +const baseMetaEventStub = {} as OB11BaseMetaEvent; +console.log('OneBot types and events access check: OK'); + +// 4. 验证导出完整性 +if (ChatType.KCHATTYPEGROUP === 2 && ElementType.TEXT === 1) { + console.log('\n✅ ALL TESTS PASSED: Types, Enums and Events are correctly exported and accessible.'); +} else { + console.error('\n❌ TESTS FAILED: Enum value mismatch.'); + throw new Error('Test Failed'); +} + + diff --git a/packages/napcat-types/test-export.ts b/packages/napcat-types/test-export.ts new file mode 100644 index 00000000..7176b43c --- /dev/null +++ b/packages/napcat-types/test-export.ts @@ -0,0 +1,20 @@ +import { ChatType, ElementType, NapCatCore, NTQQMsgApi } from './index'; + +console.log('--- NapCat Types Manual Test ---'); + +// 测试枚举值 (napcat-core enums) +console.log('ChatType.KCHATTYPEGROUP:', ChatType.KCHATTYPEGROUP); +console.log('ElementType.TEXT:', ElementType.TEXT); + +// 测试 napcat-core 的类型和类 +const coreStub = {} as NapCatCore; +const apiStub = {} as NTQQMsgApi; + +console.log('NapCatCore type check:', !!coreStub); +console.log('NTQQMsgApi type check:', !!apiStub); + +if (ChatType.KCHATTYPEGROUP === 2 && ElementType.TEXT === 1) { + console.log('Test Passed: core enums and types are correctly exported.'); +} else { + throw new Error('Test Failed: Enum values do not match expected values.'); +} diff --git a/packages/napcat-types/tsconfig.json b/packages/napcat-types/tsconfig.json new file mode 100644 index 00000000..b8ef101d --- /dev/null +++ b/packages/napcat-types/tsconfig.json @@ -0,0 +1,49 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "..", + "baseUrl": ".", + "declaration": true, + "emitDeclarationOnly": true, + "skipLibCheck": true, + "stripInternal": true, + "noEmitOnError": false, + "paths": { + "napcat-core": [ + "../napcat-core/index.ts" + ], + "napcat-onebot": [ + "../napcat-onebot/index.ts" + ], + "@/napcat-core/*": [ + "../napcat-core/*" + ], + "@/napcat-onebot/*": [ + "../napcat-onebot/*" + ], + "@/napcat-common/*": [ + "../napcat-common/*" + ], + "@/napcat-webui-backend/*": [ + "../napcat-webui-backend/*" + ], + "@/*": [ + "../*" + ] + } + }, + "include": [ + "./index.ts", + "../napcat-core/**/*.ts", + "../napcat-onebot/**/*.ts", + "../napcat-common/**/*.ts" + ], + "files": [ + "./external-shims.d.ts" + ], + "exclude": [ + "node_modules", + "dist" + ] +} \ No newline at end of file diff --git a/packages/napcat-webui-backend/src/api/Debug.ts b/packages/napcat-webui-backend/src/api/Debug.ts index 95683c17..a5d1b1d8 100644 --- a/packages/napcat-webui-backend/src/api/Debug.ts +++ b/packages/napcat-webui-backend/src/api/Debug.ts @@ -12,6 +12,7 @@ import { ActionMap } from '@/napcat-onebot/action'; import { NapCatCore } from '@/napcat-core/index'; import { NapCatOneBot11Adapter } from '@/napcat-onebot/index'; import { OB11EmitEventContent, OB11NetworkReloadType } from '@/napcat-onebot/network/index'; +import { OneBotAction } from '@/napcat-onebot/action/OneBotAction'; import json5 from 'json5'; type ActionNameType = typeof ActionName[keyof typeof ActionName]; @@ -19,6 +20,41 @@ type ActionNameType = typeof ActionName[keyof typeof ActionName]; const router: Router = Router(); const DEFAULT_ADAPTER_NAME = 'debug-primary'; +/** + * 获取所有 Action 的 Schema 信息 + */ +router.get('/schemas', async (_req: Request, res: Response) => { + try { + const obContext = WebUiDataRuntime.getOneBotContext(); + if (!obContext) { + return sendError(res, 'OneBot 未初始化'); + } + const schemas: Record = {}; + + // 遍历 ActionName 中定义的所有路由 + for (const key in ActionName) { + const actionName = (ActionName as any)[key]; + if (actionName === ActionName.Unknown) continue; + + const handler = obContext.actions.get(actionName); + if (handler) { + const action = handler as OneBotAction; + schemas[actionName] = { + description: action.actionSummary || action.actionDescription, + payload: action.payloadSchema, + response: action.returnSchema, + payloadExample: action.payloadExample, + tags: action.actionTags, + }; + } + } + + sendSuccess(res, schemas); + } catch (error: unknown) { + sendError(res, (error as Error).message); + } +}); + /** * 统一的调试适配器 * 用于注入到 OneBot NetworkManager,接收所有事件并转发给 WebSocket 客户端 diff --git a/packages/napcat-webui-backend/src/router/File.ts b/packages/napcat-webui-backend/src/router/File.ts index c79830ea..572f2fa4 100644 --- a/packages/napcat-webui-backend/src/router/File.ts +++ b/packages/napcat-webui-backend/src/router/File.ts @@ -1,4 +1,4 @@ -import { Router } from 'express'; +import { Router, RequestHandler } from 'express'; import rateLimit from 'express-rate-limit'; import { ListFilesHandler, @@ -28,7 +28,7 @@ const apiLimiter = rateLimit({ }, }); -router.use(apiLimiter); +router.use(apiLimiter as unknown as RequestHandler); router.get('/list', ListFilesHandler); router.post('/mkdir', CreateDirHandler); diff --git a/packages/napcat-webui-frontend/package.json b/packages/napcat-webui-frontend/package.json index 503f1734..b6a24714 100644 --- a/packages/napcat-webui-frontend/package.json +++ b/packages/napcat-webui-frontend/package.json @@ -55,6 +55,7 @@ "@monaco-editor/loader": "^1.4.0", "@react-aria/visually-hidden": "^3.8.19", "@reduxjs/toolkit": "^2.5.1", + "@sinclair/typebox": "^0.34.41", "@uidotdev/usehooks": "^2.4.1", "@uiw/react-codemirror": "^4.25.4", "@xterm/addon-canvas": "^0.7.0", diff --git a/packages/napcat-webui-frontend/src/components/onebot/api/debug.tsx b/packages/napcat-webui-frontend/src/components/onebot/api/debug.tsx index 36930f9a..19ecbed9 100644 --- a/packages/napcat-webui-frontend/src/components/onebot/api/debug.tsx +++ b/packages/napcat-webui-frontend/src/components/onebot/api/debug.tsx @@ -21,7 +21,8 @@ import PageLoading from '@/components/page_loading'; import { request } from '@/utils/request'; -import { generateDefaultJson, parse } from '@/utils/zod'; +import { BaseResponseSchema, parseTypeBox, generateDefaultFromTypeBox } from '@/utils/typebox'; +import { Type } from '@sinclair/typebox'; import DisplayStruct from './display_struct'; @@ -58,8 +59,16 @@ const OneBotApiDebug = forwardRef((props const [responseHeight, setResponseHeight] = useState(240); const [storedHeight, setStoredHeight] = useLocalStorage('napcat_debug_response_height', 240); - const parsedRequest = parse(data.request); - const parsedResponse = parse(data.response); + const parsedRequest = parseTypeBox(data?.payload); + + // 将返回值的 data 结构包装进 BaseResponseSchema 进行展示 + // 使用解构属性的方式重新构建对象,确保 parseTypeBox 能够识别为 object 类型 + const wrappedResponseSchema = Type.Object({ + ...BaseResponseSchema.properties, + data: data?.response || Type.Any({ description: '数据' }) + }); + + const parsedResponse = parseTypeBox(wrappedResponseSchema); const [backgroundImage] = useLocalStorage(key.backgroundImage, ''); const hasBackground = !!backgroundImage; @@ -75,7 +84,7 @@ const OneBotApiDebug = forwardRef((props // 如果有 adapterName,走后端转发 if (adapterName) { request.post(`/api/Debug/call/${adapterName}`, { - action: path.replace(/^\//, ''), // 去掉开头的 / + action: path, params: parsedRequestBody }, { headers: { @@ -154,7 +163,11 @@ const OneBotApiDebug = forwardRef((props })); useEffect(() => { - setRequestBody(generateDefaultJson(data.request)); + if (data?.payloadExample) { + setRequestBody(JSON.stringify(data.payloadExample, null, 2)); + } else { + setRequestBody(JSON.stringify(generateDefaultFromTypeBox(data?.payload), null, 2)); + } setResponseContent(''); setResponseStatus(null); }, [path]); @@ -307,7 +320,7 @@ const OneBotApiDebug = forwardRef((props )} - diff --git a/packages/napcat-webui-frontend/src/components/onebot/api/nav_list.tsx b/packages/napcat-webui-frontend/src/components/onebot/api/nav_list.tsx deleted file mode 100644 index 7cce84c4..00000000 --- a/packages/napcat-webui-frontend/src/components/onebot/api/nav_list.tsx +++ /dev/null @@ -1,182 +0,0 @@ -import { Input } from '@heroui/input'; -import { useLocalStorage } from '@uidotdev/usehooks'; -import clsx from 'clsx'; -import { AnimatePresence, motion } from 'motion/react'; -import { useMemo, useState } from 'react'; -import { TbChevronRight, TbFolder, TbSearch } from 'react-icons/tb'; - -import key from '@/const/key'; -import oneBotHttpApiGroup from '@/const/ob_api/group'; -import oneBotHttpApiMessage from '@/const/ob_api/message'; -import oneBotHttpApiSystem from '@/const/ob_api/system'; -import oneBotHttpApiUser from '@/const/ob_api/user'; -import type { OneBotHttpApi, OneBotHttpApiPath } from '@/const/ob_api'; - -export interface OneBotApiNavListProps { - data: OneBotHttpApi; - selectedApi: OneBotHttpApiPath; - onSelect: (apiName: OneBotHttpApiPath) => void; - openSideBar: boolean; - onToggle?: (isOpen: boolean) => void; -} - -const OneBotApiNavList: React.FC = (props) => { - const { data, selectedApi, onSelect, openSideBar, onToggle } = props; - const [searchValue, setSearchValue] = useState(''); - const [expandedGroups, setExpandedGroups] = useState([]); - const [backgroundImage] = useLocalStorage(key.backgroundImage, ''); - const hasBackground = !!backgroundImage; - - const groups = useMemo(() => { - const rawGroups = [ - { id: 'user', label: '账号相关', keys: Object.keys(oneBotHttpApiUser) }, - { id: 'message', label: '消息相关', keys: Object.keys(oneBotHttpApiMessage) }, - { id: 'group', label: '群聊相关', keys: Object.keys(oneBotHttpApiGroup) }, - { id: 'system', label: '系统操作', keys: Object.keys(oneBotHttpApiSystem) }, - ]; - - return rawGroups.map(g => { - const apis = g.keys - .filter(k => k in data) - .map(k => ({ path: k as OneBotHttpApiPath, ...data[k as OneBotHttpApiPath] })) - .filter(api => - api.path.toLowerCase().includes(searchValue.toLowerCase()) || - api.description?.toLowerCase().includes(searchValue.toLowerCase()) - ); - return { ...g, apis }; - }).filter(g => g.apis.length > 0); - }, [data, searchValue]); - - const toggleGroup = (id: string) => { - setExpandedGroups(prev => - prev.includes(id) ? prev.filter(i => i !== id) : [...prev, id] - ); - }; - - return ( - <> - {/* Mobile backdrop overlay - below header (z-40) */} - - {openSideBar && ( - onToggle?.(false)} - /> - )} - - - -
-
- } - value={searchValue} - onChange={(e) => setSearchValue(e.target.value)} - onClear={() => setSearchValue('')} - size="sm" - /> -
- -
- {groups.map((group) => { - const isOpen = expandedGroups.includes(group.id) || searchValue.length > 0; - return ( -
- {/* Group Header */} -
toggleGroup(group.id)} - > - - - {group.label} - ({group.apis.length}) -
- - {/* Group Content */} - - {isOpen && ( - - {group.apis.map((api) => { - const isSelected = api.path === selectedApi; - return ( -
onSelect(api.path)} - className={clsx( - 'flex flex-col gap-0.5 px-3 py-2 rounded-lg cursor-pointer transition-all border select-none', - isSelected - ? (hasBackground - ? 'bg-white/10 border-white/20' - : 'bg-primary/10 border-primary/20 shadow-sm') - : 'border-transparent hover:bg-white/10 dark:hover:bg-white/5' - )} - > - - {api.description} - - - {api.path} - -
- ); - })} -
- )} -
-
- ); - })} -
-
-
- - ); -}; - -export default OneBotApiNavList; diff --git a/packages/napcat-webui-frontend/src/const/ob_api/group.ts b/packages/napcat-webui-frontend/src/const/ob_api/group.ts deleted file mode 100644 index 39d69fe0..00000000 --- a/packages/napcat-webui-frontend/src/const/ob_api/group.ts +++ /dev/null @@ -1,744 +0,0 @@ -import { z } from 'zod'; - -import messageNodeSchema from './message/node'; -import { baseResponseSchema, commonResponseDataSchema } from './response'; - -const oneBotHttpApiGroup = { - '/set_group_kick': { - description: '群踢人', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - user_id: z.union([z.string(), z.number()]).describe('QQ 号'), - reject_add_request: z.boolean().describe('拒绝此人的加群请求'), - }), - response: baseResponseSchema, - }, - '/set_group_ban': { - description: '群禁言', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - user_id: z.union([z.string(), z.number()]).describe('QQ 号'), - duration: z.number(), - }), - response: baseResponseSchema, - }, - '/get_group_system_msg': { - description: '获取群系统消息', - request: z.object({}), - response: baseResponseSchema.extend({ - data: z.object({ - InvitedRequest: z - .array( - z - .object({ - request_id: z.string().describe('请求 ID'), - invitor_uin: z.string().describe('邀请人 QQ 号'), - invitor_nick: z.string().describe('邀请人昵称'), - group_id: z.string().describe('群号'), - message: z.string().describe('入群回答'), - group_name: z.string().describe('群名称'), - checked: z.boolean().describe('是否已处理'), - actor: z.string().describe('处理人 QQ 号'), - }) - .describe('邀请入群请求') - ) - .describe('邀请入群请求列表'), - join_requests: z.array( - z.object({ - request_id: z.string().describe('请求 ID'), - requester_uin: z.string().describe('请求人 QQ 号'), - requester_nick: z.string().describe('请求人昵称'), - group_id: z.string().describe('群号'), - message: z.string().describe('入群回答'), - group_name: z.string().describe('群名称'), - checked: z.boolean().describe('是否已处理'), - actor: z.string().describe('处理人 QQ 号'), - }) - ), - }), - }), - }, - '/get_essence_msg_list': { - description: '获取精华消息', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - }), - response: baseResponseSchema.extend({ - data: z - .array( - z - .object({ - msg_seq: z.number().describe('消息序号'), - msg_random: z.number().describe('消息随机数'), - sender_id: z.number().describe('发送人 QQ 号'), - sender_nick: z.string().describe('发送人昵称'), - operator_id: z.number().describe('操作人 QQ 号'), - operator_nick: z.string().describe('操作人昵称'), - message_id: z.string().describe('消息 ID'), - operator_time: z.string().describe('操作时间'), - content: z.array(messageNodeSchema), - }) - .describe('精华消息') - ) - .describe('精华消息列表'), - }), - }, - '/set_group_whole_ban': { - description: '全员禁言', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - enable: z.boolean().describe('是否开启'), - }), - response: baseResponseSchema, - }, - '/set_group_portrait': { - description: '设置群头像', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - file: z.string().describe('图片文件路径,服务器本地路径或远程 URL'), - }), - response: baseResponseSchema.extend({ - data: commonResponseDataSchema, - }), - }, - '/set_group_admin': { - description: '设置群管理', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - user_id: z.union([z.string(), z.number()]).describe('QQ 号'), - enable: z.boolean().describe('是否设置为管理员'), - }), - response: baseResponseSchema, - }, - '/set_essence_msg': { - description: '设置群精华消息', - request: z.object({ - message_id: z.union([z.string(), z.number()]).describe('消息 ID'), - }), - response: baseResponseSchema.extend({ - data: z.object({ - errCode: z.number().describe('错误码'), - errMsg: z.string().describe('错误信息'), - result: z - .object({ - wording: z.string().describe('?'), - digestUin: z.string().describe('?QQ号'), - digestTime: z.number().describe('设置时间?'), - msg: z - .object({ - groupCode: z.string().describe('群号'), - msgSeq: z.number().describe('消息序号'), - msgRandom: z.number().describe('消息随机数'), - msgContent: z.array(messageNodeSchema).describe('消息内容'), - textSize: z.string().describe('文本大小'), - picSize: z.string().describe('图片大小'), - videoSize: z.string().describe('视频大小'), - senderUin: z.string().describe('发送人 QQ 号'), - senderTime: z.number().describe('发送时间'), - addDigestUin: z.string().describe('添加精华消息人 QQ 号'), - addDigestTime: z.number().describe('添加精华消息时间'), - startTime: z.number().describe('开始时间'), - latestMsgSeq: z.number().describe('最新消息序号'), - opType: z.number().describe('操作类型'), - }) - .describe('消息内容'), - errorCode: z.number().describe('错误码'), - }) - .describe('结果'), - }), - }), - }, - '/set_group_card': { - description: '设置群成员名片', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - user_id: z.union([z.string(), z.number()]).describe('QQ 号'), - card: z.string().describe('名片'), - }), - response: baseResponseSchema, - }, - '/delete_essence_msg': { - description: '删除群精华消息', - request: z.object({ - message_id: z.union([z.string(), z.number()]).describe('消息 ID'), - }), - - response: baseResponseSchema.extend({ - data: z.object({ - errCode: z.number().describe('错误码'), - errMsg: z.string().describe('错误信息'), - result: z - .object({ - wording: z.string().describe('?'), - digestUin: z.string().describe('?QQ号'), - digestTime: z.number().describe('设置时间?'), - msg: z.object({ - groupCode: z.string().describe('群号'), - msgSeq: z.number().describe('消息序号'), - msgRandom: z.number().describe('消息随机数'), - msgContent: z.array(messageNodeSchema).describe('消息内容'), - textSize: z.string().describe('文本大小'), - picSize: z.string().describe('图片大小'), - videoSize: z.string().describe('视频大小'), - senderUin: z.string().describe('发送人 QQ 号'), - senderTime: z.number().describe('发送时间'), - addDigestUin: z.string().describe('添加精华消息人 QQ 号'), - addDigestTime: z.number().describe('添加精华消息时间'), - startTime: z.number().describe('开始时间'), - latestMsgSeq: z.number().describe('最新消息序号'), - opType: z.number().describe('操作类型'), - }), - errorCode: z.number().describe('错误码'), - }) - .describe('结果'), - }), - }), - }, - '/set_group_name': { - description: '设置群名称', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - group_name: z.string().describe('群名称'), - }), - response: baseResponseSchema, - }, - '/set_group_leave': { - description: '退出群聊', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - }), - response: baseResponseSchema, - }, - '/_send_group_notice': { - description: '发送群公告', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - content: z.string().describe('公告内容'), - image: z.string().optional().describe('图片地址'), - }), - response: baseResponseSchema, - }, - '/_get_group_notice': { - description: '获取群公告', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - }), - response: baseResponseSchema.extend({ - data: z.array( - z.object({ - notice_id: z.string().describe('公告 ID'), - sender_id: z.number().describe('发送人 QQ 号'), - publish_time: z.number().describe('发布时间'), - message: z.object({ - text: z.string().describe('文本内容'), - image: z - .array( - z - .object({ - id: z.string().describe('图片 ID'), - height: z.string().describe('高度'), - width: z.string().describe('宽度'), - }) - .describe('图片信息') - ) - .describe('图片内容列表'), - }), - }) - ), - }), - }, - '/set_group_special_title': { - description: '设置群成员专属头衔', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - user_id: z.union([z.string(), z.number()]).describe('QQ 号'), - special_title: z.string().describe('专属头衔内容'), - }), - response: baseResponseSchema, - }, - '/upload_group_file': { - description: '上传群文件', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - file: z.string().describe('文件路径'), - name: z.string().describe('文件名'), - folder_id: z.string().describe('文件夹 ID'), - }), - response: baseResponseSchema.extend({ - data: commonResponseDataSchema, - }), - }, - '/set_group_add_request': { - description: '处理加群请求', - request: z.object({ - flag: z.string().describe('请求ID'), - approve: z.boolean().describe('是否同意'), - reason: z.string().optional().describe('拒绝理由'), - }), - response: baseResponseSchema, - }, - '/get_group_info': { - description: '获取群信息', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - }), - response: baseResponseSchema.extend({ - data: z.object({}), - }), - }, - '/get_group_info_ex': { - description: '获取群信息扩展', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - }), - response: baseResponseSchema.extend({ - data: z - .object({ - groupCode: z.string().describe('群号'), - resultCode: z.number().describe('结果码'), - extInfo: z - .object({ - groupInfoExtSeq: z.number().describe('群信息序列号'), - reserve: z.number().describe('?'), - luckyWordId: z.string().describe('幸运字符ID'), - lightCharNum: z.number().describe('?'), - luckyWord: z.string().describe('幸运字符'), - starId: z.number().describe('?'), - essentialMsgSwitch: z.number().describe('精华消息开关'), - todoSeq: z.number().describe('?'), - blacklistExpireTime: z.number().describe('黑名单过期时间'), - isLimitGroupRtc: z.number().describe('是否限制群视频通话'), - companyId: z.number().describe('公司ID'), - hasGroupCustomPortrait: z.number().describe('是否有群自定义头像'), - bindGuildId: z.string().describe('绑定频道ID?'), - groupOwnerId: z - .object({ - memberUin: z.string().describe('群主QQ号'), - memberUid: z.string().describe('群主ID'), - memberQid: z.string().describe('群主QID'), - }) - .describe('群主信息'), - essentialMsgPrivilege: z.number().describe('精华消息权限'), - msgEventSeq: z.string().describe('消息事件序列号'), - inviteRobotSwitch: z.number().describe('邀请机器人开关'), - gangUpId: z.string().describe('?'), - qqMusicMedalSwitch: z.number().describe('QQ音乐勋章开关'), - showPlayTogetherSwitch: z.number().describe('显示一起玩开关'), - groupFlagPro1: z.string()?.describe('群标识1'), - groupBindGuildIds: z - .object({ - guildIds: z.array(z.string()), - }) - .describe('绑定频道ID列表?'), - viewedMsgDisappearTime: z.string().describe('消息消失时间'), - groupExtFlameData: z.object({ - switchState: z.number().describe('开关状态'), - state: z.number().describe('状态'), - dayNums: z.array(z.number()).describe('天数列表'), - version: z.number().describe('版本号'), - updateTime: z.string().describe('更新时间'), - isDisplayDayNum: z.boolean().describe('是否显示天数'), - }), - groupBindGuildSwitch: z.number().describe('绑定频道开关'), - groupAioBindGuildId: z.string().describe('AIO绑定频道ID'), - groupExcludeGuildIds: z - .object({ - guildIds: z.array(z.string()).describe('排除频道ID'), - }) - .describe('排除频道ID列表?'), - fullGroupExpansionSwitch: z.number().describe('全员群扩容开关'), - fullGroupExpansionSeq: z.string().describe('全员群扩容序列号'), - inviteRobotMemberSwitch: z - .number() - .describe('邀请机器人成员开关'), - inviteRobotMemberExamine: z - .number() - .describe('邀请机器人成员审核'), - groupSquareSwitch: z.number().describe('群广场开关'), - }) - .describe('扩展信息'), - }) - .describe('结果'), - }), - }, - '/create_group_file_folder': { - description: '创建群文件夹', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - folder_name: z.string().describe('文件夹名称'), - }), - response: baseResponseSchema.extend({ - data: z - .object({ - result: z - .object({ - retCode: z.number().describe('结果码'), - retMsg: z.string().describe('结果信息'), - clientWording: z.string().describe('客户端提示'), - }) - .describe('结果'), - groupItem: z - .object({ - peerId: z.string().describe('?'), - type: z.string().describe('类型'), - folderInfo: z - .object({ - folderId: z.string().describe('文件夹 ID'), - parentFolderId: z.string().describe('父文件夹 ID'), - folderName: z.string().describe('文件夹名称'), - createTime: z.number().describe('创建时间'), - modifyTime: z.number().describe('修改时间'), - createUin: z.string().describe('创建人 QQ 号'), - creatorName: z.string().describe('创建人昵称'), - totalFileCount: z.string().describe('文件总数'), - modifyUin: z.string().describe('修改人 QQ 号'), - modifyName: z.string().describe('修改人昵称'), - usedSpace: z.string().describe('已使用空间'), - }) - .describe('文件夹信息'), - }) - .describe('群文件夹信息'), - }) - .describe('数据'), - }), - }, - '/delete_group_file': { - description: '删除群文件', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - file_id: z.string().describe('文件 ID'), - }), - response: baseResponseSchema.extend({ - data: z - .object({ - result: z.number().describe('结果码'), - errMsg: z.string().describe('错误信息'), - transGroupFileResult: z - .object({ - result: z - .object({ - retCode: z.number().describe('结果码'), - retMsg: z.string().describe('结果信息'), - clientWording: z.string().describe('客户端提示'), - }) - .describe('结果'), - successFileIdList: z - .array(z.string()) - .describe('成功文件 ID 列表'), - failFileIdList: z.array(z.string()).describe('失败文件 ID 列表'), - }) - .describe('删除群文件结果'), - }) - .describe('结果'), - }), - }, - '/delete_group_folder': { - description: '删除群文件夹', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - folder_id: z.string().describe('文件夹 ID'), - }), - response: baseResponseSchema.extend({ - data: z.object({ - retCode: z.number().describe('结果码'), - retMsg: z.string().describe('结果信息'), - clientWording: z.string().describe('客户端提示'), - }), - }), - }, - '/get_group_file_system_info': { - description: '获取群文件系统信息', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - }), - response: baseResponseSchema.extend({ - data: z.object({ - file_count: z.number().describe('文件总数'), - limit_count: z.number().describe('文件总数限制'), - used_space: z.number().describe('已使用空间'), - total_space: z.number().describe('总空间'), - }), - }), - }, - '/get_group_root_files': { - description: '获取群根目录文件列表', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - }), - response: baseResponseSchema.extend({ - data: z.array( - z.object({ - files: z - .array( - z - .object({ - group_id: z.number().describe('群号'), - file_id: z.string().describe('文件 ID'), - file_name: z.string().describe('文件名'), - busid: z.number().describe('?'), - size: z.number().describe('文件大小'), - upload_time: z.number().describe('上传时间'), - dead_time: z.number().describe('过期时间'), - modify_time: z.number().describe('修改时间'), - download_times: z.number().describe('下载次数'), - uploader: z.number().describe('上传人 QQ 号'), - uploader_name: z.string().describe('上传人昵称'), - }) - .describe('文件信息') - ) - .describe('文件列表'), - folders: z - .array( - z - .object({ - group_id: z.number().describe('群号'), - folder_id: z.string().describe('文件夹 ID'), - folder: z.string().describe('文件夹?'), - folder_name: z.string().describe('文件夹名称'), - create_time: z.string().describe('创建时间'), - creator: z.string().describe('创建人 QQ 号'), - creator_name: z.string().describe('创建人昵称'), - total_file_count: z.string().describe('文件总数'), - }) - .describe('文件夹信息') - ) - .describe('文件夹列表'), - }) - ), - }), - }, - '/get_group_files_by_folder': { - description: '获取群子目录文件列表', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - folder_id: z.string().describe('文件夹 ID'), - file_count: z.number().describe('文件数量'), - }), - response: baseResponseSchema.extend({ - data: z.object({ - files: z - .array( - z - .object({ - group_id: z.number().describe('群号'), - file_id: z.string().describe('文件 ID'), - file_name: z.string().describe('文件名'), - busid: z.number().describe('?'), - size: z.number().describe('文件大小'), - upload_time: z.number().describe('上传时间'), - dead_time: z.number().describe('过期时间'), - modify_time: z.number().describe('修改时间'), - download_times: z.number().describe('下载次数'), - uploader: z.number().describe('上传人 QQ 号'), - uploader_name: z.string().describe('上传人昵称'), - }) - .describe('文件信息') - ) - .describe('文件列表'), - folders: z - .array( - z - .object({ - group_id: z.number().describe('群号'), - folder_id: z.string().describe('文件夹 ID'), - folder: z.string().describe('文件夹?'), - folder_name: z.string().describe('文件夹名称'), - create_time: z.string().describe('创建时间'), - creator: z.string().describe('创建人 QQ 号'), - creator_name: z.string().describe('创建人昵称'), - total_file_count: z.string().describe('文件总数'), - }) - .describe('文件夹信息') - ) - .describe('文件夹列表'), - }), - }), - }, - '/get_group_file_url': { - description: '获取群文件下载链接', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - file_id: z.string().describe('文件 ID'), - }), - response: baseResponseSchema.extend({ - data: z.object({ - url: z.string().describe('下载链接'), - }), - }), - }, - '/get_group_list': { - description: '获取群列表', - request: z.object({ - next_token: z.string().optional().describe('下一页标识'), - }), - response: baseResponseSchema.extend({ - data: z.array(z.object({})), - }), - }, - '/get_group_member_info': { - description: '获取群成员信息', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - user_id: z.union([z.string(), z.number()]).describe('QQ 号'), - no_cache: z.boolean().describe('是否不使用缓存'), - }), - response: baseResponseSchema.extend({ - data: z.object({}), - }), - }, - '/get_group_member_list': { - description: '获取群成员列表', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - no_cache: z.boolean().describe('是否不使用缓存'), - }), - response: baseResponseSchema.extend({ - data: z.array(z.object({})), - }), - }, - '/get_group_honor_info': { - description: '获取群荣誉', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - }), - response: baseResponseSchema.extend({ - data: z - .object({ - group_id: z.number().describe('群号'), - current_talkative: z - .object({ - user_id: z.number().describe('QQ 号'), - avatar: z.string().describe('头像 URL'), - nickname: z.string().describe('昵称'), - day_count: z.number().describe('天数'), - description: z.string().describe('描述'), - }) - .describe('当前龙王'), - talkative_list: z - .array( - z.object({ - user_id: z.number().describe('QQ 号'), - avatar: z.string().describe('头像 URL'), - nickname: z.string().describe('昵称'), - day_count: z.number().describe('天数'), - description: z.string().describe('描述'), - }) - ) - .describe('龙王榜'), - performer_list: z - .array( - z.object({ - user_id: z.number().describe('QQ 号'), - avatar: z.string().describe('头像 URL'), - nickname: z.string().describe('昵称'), - description: z.string().describe('描述'), - }) - ) - .describe('?'), - legend_list: z.array(z.string()).describe('?'), - emotion_list: z.array(z.string()).describe('?'), - strong_newbie_list: z.array(z.string()).describe('?'), - }) - .describe('群荣誉信息'), - }), - }, - '/get_group_at_all_remain': { - description: '获取群 @全体成员 剩余次数', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - }), - response: baseResponseSchema.extend({ - data: z.object({ - can_at_all: z.boolean().describe('是否可以 @全体成员'), - remain_at_all_count_for_group: z.number().describe('剩余次数(group?)'), - remain_at_all_count_for_uin: z.number().describe('剩余次数(qq?)'), - }), - }), - }, - '/get_group_ignored_notifies': { - description: '获取群过滤系统消息', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - }), - response: baseResponseSchema.extend({ - data: z.object({ - join_requests: z - .array( - z.object({ - request_id: z.string().describe('请求 ID'), - requester_uin: z.string().describe('请求人 QQ 号'), - requester_nick: z.string().describe('请求人昵称'), - group_id: z.string().describe('群号'), - group_name: z.string().describe('群名称'), - checked: z.boolean().describe('是否已处理'), - actor: z.string().describe('处理人 QQ 号'), - }) - ) - .describe('入群请求列表'), - }), - }), - }, - '/set_group_sign': { - description: '设置群打卡', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - }), - response: baseResponseSchema, - }, - '/send_group_sign': { - description: '发送群打卡', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - }), - response: baseResponseSchema, - }, - '/get_ai_characters': { - description: '获取AI语音人物', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - chat_type: z.union([z.string(), z.number()]).describe('聊天类型'), - }), - response: baseResponseSchema.extend({ - data: z.array( - z.object({ - type: z.string().describe('类型'), - characters: z.array( - z - .object({ - character_id: z.string().describe('人物 ID'), - character_name: z.string().describe('人物名称'), - preview_url: z.string().describe('预览音频地址'), - }) - .describe('人物信息') - ), - }) - ), - }), - }, - '/send_group_ai_record': { - description: '发送群AI语音', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - character: z.string().describe('人物ID'), - text: z.string().describe('文本内容'), - }), - response: baseResponseSchema.extend({ - data: z.object({ - message_id: z.string().describe('消息 ID'), - }), - }), - }, - '/get_ai_record': { - description: '获取AI语音', - request: z.object({ - group_id: z.string().describe('群号'), - character: z.string().describe('人物ID'), - text: z.string().describe('文本内容'), - }), - response: baseResponseSchema.extend({ - data: z.string(), - }), - }, -} as const; - -export default oneBotHttpApiGroup; diff --git a/packages/napcat-webui-frontend/src/const/ob_api/index.ts b/packages/napcat-webui-frontend/src/const/ob_api/index.ts index ab075756..8cf0c2b9 100644 --- a/packages/napcat-webui-frontend/src/const/ob_api/index.ts +++ b/packages/napcat-webui-frontend/src/const/ob_api/index.ts @@ -1,34 +1,40 @@ -import { ZodSchema } from 'zod'; +import { TSchema } from '@sinclair/typebox'; -import oneBotHttpApiGroup from './group'; -import oneBotHttpApiMessage from './message'; -import oneBotHttpApiSystem from './system'; -import oneBotHttpApiUser from './user'; +export interface OneBotHttpApiContent { + description?: string; + payload: TSchema; + response: TSchema; + payloadExample?: any; + tags?: string[]; +} -type AllKey = - | keyof typeof oneBotHttpApiUser - | keyof typeof oneBotHttpApiMessage - | keyof typeof oneBotHttpApiGroup - | keyof typeof oneBotHttpApiSystem; +export type OneBotHttpApi = Record; -export type OneBotHttpApi = Record< - AllKey, - { - description?: string - request: ZodSchema - response: ZodSchema +let oneBotHttpApi: OneBotHttpApi = {}; + +export async function fetchOneBotHttpApi (): Promise { + try { + const response = await fetch('/api/Debug/schemas', { + headers: { + 'Authorization': `Bearer ${localStorage.getItem('token')}` + } + }); + const data = await response.json(); + if (data.code === 0) { + oneBotHttpApi = data.data; + return oneBotHttpApi; + } + } catch (error) { + console.error('Failed to fetch OneBot HTTP API schemas:', error); } ->; + return {}; +} -const oneBotHttpApi: OneBotHttpApi = { - ...oneBotHttpApiUser, - ...oneBotHttpApiMessage, - ...oneBotHttpApiGroup, - ...oneBotHttpApiSystem, -} as const; +export function getOneBotHttpApi () { + return oneBotHttpApi; +} -export type OneBotHttpApiPath = keyof OneBotHttpApi; - -export type OneBotHttpApiContent = OneBotHttpApi[OneBotHttpApiPath]; +export type OneBotHttpApiPath = string; export default oneBotHttpApi; + diff --git a/packages/napcat-webui-frontend/src/const/ob_api/message/group.ts b/packages/napcat-webui-frontend/src/const/ob_api/message/group.ts deleted file mode 100644 index f5546e63..00000000 --- a/packages/napcat-webui-frontend/src/const/ob_api/message/group.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { z } from 'zod'; -import type { ZodSchema } from 'zod'; - -import { baseResponseSchema, commonResponseDataSchema } from '../response'; -import messageNodeSchema, { nodeMessage } from './node'; - -const oneBotHttpApiMessageGroup: Record< - string, - { - description?: string - request: ZodSchema - response: ZodSchema - } -> = { - '/send_group_msg': { - description: '发送群消息', - request: z - .object({ - group_id: z - .union([z.string(), z.number()]) - .describe('群号') - .describe('群号'), - message: z.array(messageNodeSchema).describe('消息内容'), - }) - .refine( - (data) => { - const hasReply = data.message.some((item) => item.type === 'reply'); - - if (hasReply) { - return data.message[0].type === 'reply'; - } - - return true; - }, - { - message: - '如果 message 包含 reply 类型的消息,那么只能包含一个,而且排在最前面', - } - ), - response: baseResponseSchema.extend({ - data: commonResponseDataSchema, - }), - }, - '/send_group_forward_msg': { - description: '发送群合并转发消息', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - messages: z.array(nodeMessage).describe('消息内容'), - news: z - .array( - z.object({ - text: z.string(), - }) - ) - .describe('?'), - prompt: z.string().describe('外显'), - summary: z.string().describe('底下文本'), - source: z.string().describe('内容'), - }), - response: baseResponseSchema.extend({ - data: commonResponseDataSchema, - }), - }, - '/forward_group_single_msg': { - description: '消息转发到群', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - message_id: z.union([z.string(), z.number()]).describe('消息 ID'), - }), - response: baseResponseSchema.extend({ - data: commonResponseDataSchema, - }), - }, - '/group_poke': { - description: '发送戳一戳', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - user_id: z.union([z.string(), z.number()]).describe('对方QQ号'), - }), - response: baseResponseSchema, - }, -}; - -export default oneBotHttpApiMessageGroup; diff --git a/packages/napcat-webui-frontend/src/const/ob_api/message/index.ts b/packages/napcat-webui-frontend/src/const/ob_api/message/index.ts deleted file mode 100644 index 9e624ea8..00000000 --- a/packages/napcat-webui-frontend/src/const/ob_api/message/index.ts +++ /dev/null @@ -1,290 +0,0 @@ -import { z } from 'zod'; - -import { baseResponseSchema, commonResponseDataSchema } from '../response'; -import oneBotHttpApiMessageGroup from './group'; -import messageNodeSchema from './node'; -import oneBotHttpApiMessagePrivate from './private'; - -const fileSchema = z - .object({ - file: z.string().describe('路径或链接'), - url: z.string().describe('路径或链接'), - file_size: z.string().describe('文件大小'), - file_name: z.string().describe('文件名'), - base64: z.string().describe('文件base64编码'), - }) - .describe('文件'); -const messageSchema = z - .object({ - self_id: z.number().describe('自己QQ号'), - user_id: z.number().describe('发送人QQ号'), - time: z.number().describe('发送时间'), - message_id: z.number().describe('消息ID'), - message_seq: z.number().describe('消息序号'), - real_id: z.number().describe('?ID'), - message_type: z.string().describe('消息类型'), - sender: z - .object({ - user_id: z.number().describe('发送人QQ号'), - nickname: z.string().describe('昵称'), - sex: z.enum(['male', 'female', 'unknown']).describe('性别'), - age: z.number().describe('年龄'), - card: z.string().describe('名片'), - role: z.enum(['owner', 'admin', 'member']).describe('角色'), - }) - .describe('发送人信息'), - raw_message: z.string().describe('原始消息'), - font: z.number().describe('字体'), - sub_type: z.string().describe('子类型'), - message: z.array(messageNodeSchema).describe('消息内容'), - message_format: z.string().describe('消息格式'), - post_type: z.string().describe('?'), - message_sent_type: z.string().describe('消息发送类型'), - group_id: z.number().describe('群号'), - }) - .describe('消息'); - -const oneBotHttpApiMessage = { - ...oneBotHttpApiMessagePrivate, - ...oneBotHttpApiMessageGroup, - '/mark_msg_as_read': { - description: '标记消息已读', - request: z - .object({ - group_id: z - .union([z.string(), z.number()]) - .optional() - .describe('群号,与 user_id 二选一'), - user_id: z - .union([z.string(), z.number()]) - .optional() - .describe('用户QQ号,与 group_id 二选一'), - }) - .refine( - (data) => - (data.group_id && !data.user_id) || (!data.group_id && data.user_id), - { - message: 'group_id 和 user_id 必须二选一,且不能同时存在或同时为空', - path: ['group_id', 'user_id'], - } - ), - response: baseResponseSchema, - }, - '/mark_group_msg_as_read': { - description: '标记群消息已读', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - }), - response: baseResponseSchema, - }, - '/mark_private_msg_as_read': { - description: '标记私聊消息已读', - request: z.object({ - user_id: z.union([z.string(), z.number()]).describe('用户QQ号'), - }), - response: baseResponseSchema, - }, - '/_mark_all_as_read': { - description: '标记所有消息已读', - request: z.object({}), - response: baseResponseSchema, - }, - '/delete_msg': { - description: '撤回消息', - request: z.object({ - message_id: z.union([z.string(), z.number()]).describe('消息ID'), - }), - response: baseResponseSchema, - }, - '/get_msg': { - description: '获取消息', - request: z.object({ - message_id: z.union([z.string(), z.number()]).describe('消息ID'), - }), - response: baseResponseSchema.extend({ - data: z.object({}), - }), - }, - '/get_image': { - description: '获取图片', - request: z.object({ - file_id: z.string().describe('文件ID'), - }), - response: baseResponseSchema.extend({ - data: fileSchema, - }), - }, - '/get_record': { - description: '获取语音', - request: z.object({ - file_id: z.string().describe('文件ID'), - out_format: z - .enum(['mp3', 'amr', 'wma', 'm4a', 'spx', 'ogg', 'wav', 'flac']) - .describe('输出格式'), - }), - response: baseResponseSchema.extend({ - data: fileSchema, - }), - }, - '/get_file': { - description: '获取文件', - request: z.object({ - file_id: z.string().describe('文件ID'), - }), - response: baseResponseSchema.extend({ - data: fileSchema, - }), - }, - '/get_group_msg_history': { - description: '获取群消息历史', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群号'), - message_seq: z.union([z.string(), z.number()]).describe('消息序号'), - count: z.number().int().positive().describe('获取数量'), - reverse_order: z.boolean().describe('是否倒序'), - }), - response: baseResponseSchema.extend({ - data: z.object({ - messages: z.array(messageSchema).describe('消息列表'), - }), - }), - }, - '/set_msg_emoji_like': { - description: '贴表情', - request: z.object({ - message_id: z.union([z.string(), z.number()]).describe('消息ID'), - emoji_id: z.number().describe('表情ID'), - set: z.boolean().describe('?'), - }), - response: baseResponseSchema.extend({ - data: commonResponseDataSchema, - }), - }, - '/get_friend_msg_history': { - description: '获取好友消息历史', - request: z.object({ - user_id: z.union([z.string(), z.number()]).describe('用户QQ号'), - message_seq: z.union([z.string(), z.number()]).describe('消息序号'), - count: z.number().int().positive().describe('获取数量'), - reverse_order: z.boolean().describe('是否倒序'), - }), - response: baseResponseSchema.extend({ - data: z.object({ - messages: z.array(messageSchema), - }), - }), - }, - '/get_recent_contact': { - description: '最近消息列表', - request: z.object({ - count: z.number().int().positive().describe('获取数量'), - }), - response: baseResponseSchema.extend({ - data: z.array( - z.object({ - lastestMsg: messageSchema, - peerUin: z.string().describe('对方QQ号'), - remark: z.string().describe('备注'), - msgTime: z.string().describe('消息时间'), - chatType: z.number().describe('聊天类型'), - msgId: z.string().describe('消息ID'), - sendNickName: z.string().describe('发送人昵称'), - sendMemberName: z.string().describe('发送人?昵称'), - peerName: z.string().describe('对方昵称'), - }) - ), - }), - }, - '/fetch_emoji_like': { - description: '获取贴表情详情', - request: z.object({ - message_id: z.union([z.string(), z.number()]).describe('消息ID'), - emojiId: z.string().describe('表情ID'), - emojiType: z.string().describe('表情类型'), - count: z.number().int().positive().optional().describe('获取数量'), - cookie: z.string().describe('cookie,首次为空,后续为上次返回'), - }), - response: baseResponseSchema.extend({ - data: z.object({ - result: z.number().describe('结果'), - errMsg: z.string().describe('错误信息'), - emojiLikesList: z - .array( - z - .object({ - tinyId: z.string().describe('点击者QQ号'), - nickName: z.string().describe('昵称?'), - headUrl: z.string().describe('头像?'), - }) - .describe('表情点击列表') - ) - .describe('表情点击列表'), - cookie: z.string().describe('cookie'), - isLastPage: z.boolean().describe('是否最后一页'), - isFirstPage: z.boolean().describe('是否第一页'), - }), - }), - }, - '/get_emoji_likes': { - description: '获取贴表情详情列表', - request: z.object({ - message_id: z.union([z.string(), z.number()]).describe('消息ID'), - emojiId: z.string().describe('表情ID'), - emojiType: z.string().describe('表情类型'), - }), - response: baseResponseSchema.extend({ - data: z.object({ - result: z.number().describe('结果'), - errMsg: z.string().describe('错误信息'), - emojiLikesList: z - .array( - z - .object({ - tinyId: z.string().describe('点击者QQ号'), - nickName: z.string().describe('昵称?'), - headUrl: z.string().describe('头像?'), - }) - .describe('表情点击列表') - ) - .describe('表情点击列表'), - }), - }), - }, - '/get_forward_msg': { - description: '获取合并转发消息', - request: z.object({ - message_id: z.union([z.string(), z.number()]).describe('消息ID'), - }), - response: baseResponseSchema.extend({ - data: z.object({}), - }), - }, - '/send_forward_msg': { - description: '发送合并转发消息', - request: z.object({ - group_id: z.union([z.string(), z.number()]).optional().describe('群号'), - user_id: z - .union([z.string(), z.number()]) - .optional() - .describe('用户QQ号'), - messages: z.array(messageNodeSchema).describe('消息内容'), - news: z - .array( - z.object({ - text: z.string(), - }) - ) - .describe('?'), - prompt: z.string().describe('外显'), - summary: z.string().describe('底下文字'), - source: z.string().describe('内容'), - }), - response: baseResponseSchema.extend({ - data: commonResponseDataSchema.extend({ - data: z.object({}), - }), - }), - }, -} as const; - -export default oneBotHttpApiMessage; diff --git a/packages/napcat-webui-frontend/src/const/ob_api/message/node.ts b/packages/napcat-webui-frontend/src/const/ob_api/message/node.ts deleted file mode 100644 index c1b93c90..00000000 --- a/packages/napcat-webui-frontend/src/const/ob_api/message/node.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { z } from 'zod'; - -const messageNode = z.union([ - z - .object({ - type: z.literal('text'), - data: z.object({ - text: z.string(), - }), - }) - .describe('文本消息'), - z - .object({ - type: z.literal('at'), - data: z.object({ - qq: z.string(), - }), - }) - .describe('@某人'), - z - .object({ - type: z.literal('image'), - data: z.object({ - file: z.string(), - }), - }) - .describe('图片消息'), - z - .object({ - type: z.literal('face'), - data: z.object({ - id: z.number(), - }), - }) - .describe('表情消息'), - z - .object({ - type: z.literal('json'), - data: z.object({ - data: z.string(), - }), - }) - .describe('json 卡片消息'), - z - .object({ - type: z.literal('record'), - data: z.object({ - file: z.string(), - }), - }) - .describe('语音消息'), - z - .object({ - type: z.literal('video'), - data: z.object({ - file: z.string(), - }), - }) - .describe('视频消息'), - z - .object({ - type: z.literal('reply'), - data: z.object({ - id: z.number().optional(), - seq: z.number().optional(), - }), - }) - .describe('回复消息'), - z - .object({ - type: z.literal('music'), - data: z.union([ - z.object({ - type: z.enum(['qq', '163']), - id: z.string(), - }), - z.object({ - type: z.literal('custom'), - url: z.string(), - audio: z.string(), - title: z.string(), - image: z.string(), - }), - ]), - }) - .describe('音乐消息'), - z - .object({ - type: z.literal('dice'), - }) - .describe('掷骰子'), - z - .object({ - type: z.literal('rps'), - }) - .describe('猜拳'), - z - .object({ - type: z.literal('file'), - data: z.object({ - file: z.string().describe('文件路径,服务器本地或者网络文件均可'), - }), - }) - .describe('发送消息'), -]); - -export const nodeMessage = z - .object({ - type: z.literal('node'), - data: z.object({ - user_id: z.string(), - nickname: z.string(), - content: z.array(messageNode), - }), - }) - .describe('消息节点'); - -const messageNodeSchema = z.union([messageNode, nodeMessage]); - -export default messageNodeSchema; diff --git a/packages/napcat-webui-frontend/src/const/ob_api/message/private.ts b/packages/napcat-webui-frontend/src/const/ob_api/message/private.ts deleted file mode 100644 index 87ff7e11..00000000 --- a/packages/napcat-webui-frontend/src/const/ob_api/message/private.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { z } from 'zod'; -import type { ZodSchema } from 'zod'; - -import { baseResponseSchema, commonResponseDataSchema } from '../response'; -import messageNodeSchema, { nodeMessage } from './node'; - -const oneBotHttpApiMessagePrivate: Record< - string, - { - description?: string - request: ZodSchema - response: ZodSchema - } -> = { - '/send_private_msg': { - description: '发送私聊消息', - request: z - .object({ - user_id: z.union([z.string(), z.number()]).describe('对方QQ号'), - message: z.array(messageNodeSchema).describe('消息内容'), - }) - .refine( - (data) => { - const hasReply = data.message.some((item) => item.type === 'reply'); - - if (hasReply) { - return data.message[0].type === 'reply'; - } - - return true; - }, - { - message: - '如果 message 包含 reply 类型的消息,那么只能包含一个,而且排在最前面', - } - ), - response: baseResponseSchema.extend({ - data: commonResponseDataSchema, - }), - }, - '/send_private_forward_msg': { - description: '发送私聊合并转发消息', - request: z.object({ - user_id: z.union([z.string(), z.number()]).describe('对方QQ号'), - messages: z.array(nodeMessage).describe('消息内容'), - news: z - .array( - z.object({ - text: z.string(), - }) - ) - .describe('?'), - prompt: z.string().describe('外显'), - summary: z.string().describe('底下文本'), - source: z.string().describe('内容'), - }), - response: baseResponseSchema.extend({ - data: commonResponseDataSchema, - }), - }, - '/forward_friend_single_msg': { - description: '消息转发到私聊', - request: z.object({ - user_id: z.union([z.string(), z.number()]).describe('对方QQ号'), - message_id: z.union([z.string(), z.number()]).describe('消息ID'), - }), - response: baseResponseSchema.extend({ - data: commonResponseDataSchema, - }), - }, - '/group_poke': { - description: '发送私聊戳一戳', - request: z.object({ - user_id: z.union([z.string(), z.number()]).describe('对方QQ号'), - }), - response: baseResponseSchema, - }, -}; - -export default oneBotHttpApiMessagePrivate; diff --git a/packages/napcat-webui-frontend/src/const/ob_api/online_status.ts b/packages/napcat-webui-frontend/src/const/ob_api/online_status.ts deleted file mode 100644 index e1caaa7b..00000000 --- a/packages/napcat-webui-frontend/src/const/ob_api/online_status.ts +++ /dev/null @@ -1,335 +0,0 @@ -import { z } from 'zod'; - -// 定义 set_online_status 的 data 格式 -const onlineStatusDataSchema = z.union([ - // 在线 - z - .object({ - status: z.literal(10), - ext_status: z.literal(0), - battery_status: z.literal(0), - }) - .describe('在线'), - // Q我吧 - z - .object({ - status: z.literal(60), - ext_status: z.literal(0), - battery_status: z.literal(0), - }) - .describe('Q我吧'), - // 离开 - z - .object({ - status: z.literal(30), - ext_status: z.literal(0), - battery_status: z.literal(0), - }) - .describe('离开'), - // 忙碌 - z - .object({ - status: z.literal(50), - ext_status: z.literal(0), - battery_status: z.literal(0), - }) - .describe('忙碌'), - // 请勿打扰 - z - .object({ - status: z.literal(70), - ext_status: z.literal(0), - battery_status: z.literal(0), - }) - .describe('请勿打扰'), - // 隐身 - z - .object({ - status: z.literal(40), - ext_status: z.literal(0), - battery_status: z.literal(0), - }) - .describe('隐身'), - // 听歌中 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1028), - battery_status: z.literal(0), - }) - .describe('听歌中'), - // 春日限定 - z - .object({ - status: z.literal(10), - ext_status: z.literal(2037), - battery_status: z.literal(0), - }) - .describe('春日限定'), - // 一起元梦 - z - .object({ - status: z.literal(10), - ext_status: z.literal(2025), - battery_status: z.literal(0), - }) - .describe('一起元梦'), - // 求星搭子 - z - .object({ - status: z.literal(10), - ext_status: z.literal(2026), - battery_status: z.literal(0), - }) - .describe('求星搭子'), - // 被掏空 - z - .object({ - status: z.literal(10), - ext_status: z.literal(2014), - battery_status: z.literal(0), - }) - .describe('被掏空'), - // 今日天气 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1030), - battery_status: z.literal(0), - }) - .describe('今日天气'), - // 我crash了 - z - .object({ - status: z.literal(10), - ext_status: z.literal(2019), - battery_status: z.literal(0), - }) - .describe('我crash了'), - // 爱你 - z - .object({ - status: z.literal(10), - ext_status: z.literal(2006), - battery_status: z.literal(0), - }) - .describe('爱你'), - // 恋爱中 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1051), - battery_status: z.literal(0), - }) - .describe('恋爱中'), - // 好运锦鲤 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1071), - battery_status: z.literal(0), - }) - .describe('好运锦鲤'), - // 水逆退散 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1201), - battery_status: z.literal(0), - }) - .describe('水逆退散'), - // 嗨到飞起 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1056), - battery_status: z.literal(0), - }) - .describe('嗨到飞起'), - // 元气满满 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1058), - battery_status: z.literal(0), - }) - .describe('元气满满'), - // 宝宝认证 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1070), - battery_status: z.literal(0), - }) - .describe('宝宝认证'), - // 一言难尽 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1063), - battery_status: z.literal(0), - }) - .describe('一言难尽'), - // 难得糊涂 - z - .object({ - status: z.literal(10), - ext_status: z.literal(2001), - battery_status: z.literal(0), - }) - .describe('难得糊涂'), - // emo中 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1401), - battery_status: z.literal(0), - }) - .describe('emo中'), - // 我太难了 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1062), - battery_status: z.literal(0), - }) - .describe('我太难了'), - // 我想开了 - z - .object({ - status: z.literal(10), - ext_status: z.literal(2013), - battery_status: z.literal(0), - }) - .describe('我想开了'), - // 我没事 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1052), - battery_status: z.literal(0), - }) - .describe('我没事'), - // 想静静 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1061), - battery_status: z.literal(0), - }) - .describe('想静静'), - // 悠哉哉 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1059), - battery_status: z.literal(0), - }) - .describe('悠哉哉'), - // 去旅行 - z - .object({ - status: z.literal(10), - ext_status: z.literal(2015), - battery_status: z.literal(0), - }) - .describe('去旅行'), - // 信号弱 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1011), - battery_status: z.literal(0), - }) - .describe('信号弱'), - // 出去浪 - z - .object({ - status: z.literal(10), - ext_status: z.literal(2003), - battery_status: z.literal(0), - }) - .describe('出去浪'), - // 肝作业 - z - .object({ - status: z.literal(10), - ext_status: z.literal(2012), - battery_status: z.literal(0), - }) - .describe('肝作业'), - // 学习中 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1018), - battery_status: z.literal(0), - }) - .describe('学习中'), - // 搬砖中 - z - .object({ - status: z.literal(10), - ext_status: z.literal(2023), - battery_status: z.literal(0), - }) - .describe('搬砖中'), - // 摸鱼中 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1300), - battery_status: z.literal(0), - }) - .describe('摸鱼中'), - // 无聊中 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1060), - battery_status: z.literal(0), - }) - .describe('无聊中'), - // timi中 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1027), - battery_status: z.literal(0), - }) - .describe('timi中'), - // 睡觉中 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1016), - battery_status: z.literal(0), - }) - .describe('睡觉中'), - // 熬夜中 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1032), - battery_status: z.literal(0), - }) - .describe('熬夜中'), - // 追剧中 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1021), - battery_status: z.literal(0), - }) - .describe('追剧中'), - // 我的电量 - z - .object({ - status: z.literal(10), - ext_status: z.literal(1000), - battery_status: z.literal(0), - }) - .describe('我的电量'), -]); - -export default onlineStatusDataSchema; diff --git a/packages/napcat-webui-frontend/src/const/ob_api/response.ts b/packages/napcat-webui-frontend/src/const/ob_api/response.ts deleted file mode 100644 index 7162b99a..00000000 --- a/packages/napcat-webui-frontend/src/const/ob_api/response.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { z } from 'zod'; - -// 通用响应格式 -export const baseResponseSchema = z.object({ - status: z.enum(['ok', 'error']).describe('请求状态'), // 状态 - retcode: z.number().describe('响应🐎'), // 返回码 - data: z.null(), - message: z.string().describe('提示信息'), // 提示信息 - wording: z.string().describe('提示信息(人性化)'), // 人性化提示 - echo: z.string().describe('回显'), // 请求回显内容 -}); - -export const commonResponseDataSchema = z.object({ - result: z.number(), - errMsg: z.string(), -}); diff --git a/packages/napcat-webui-frontend/src/const/ob_api/system.ts b/packages/napcat-webui-frontend/src/const/ob_api/system.ts deleted file mode 100644 index 36a53e34..00000000 --- a/packages/napcat-webui-frontend/src/const/ob_api/system.ts +++ /dev/null @@ -1,366 +0,0 @@ -import { z } from 'zod'; - -import { baseResponseSchema, commonResponseDataSchema } from './response'; - -const oneBotHttpApiSystem = { - '/get_online_clients': { - description: '获取当前账号在线客户端列表', - request: z.object({ - no_cache: z.boolean().optional().describe('是否不使用缓存'), - }), - response: baseResponseSchema.extend({ - data: z.object({ - clients: z.object({}), - }), - }), - }, - '/get_robot_uin_range': { - description: '获取机器人账号范围', - request: z.object({}), - response: baseResponseSchema.extend({ - data: z.array( - z.object({ - minUin: z.string(), - maxUin: z.string(), - }) - ), - }), - }, - '/ocr_image': { - description: 'OCR图片识别', - request: z.object({ - image: z.string(), - }), - response: baseResponseSchema.extend({ - data: z.array( - z.object({ - text: z.string(), - pt1: z.object({ - x: z.string(), - y: z.string(), - }), - pt2: z.object({ - x: z.string(), - y: z.string(), - }), - pt3: z.object({ - x: z.string(), - y: z.string(), - }), - pt4: z.object({ - x: z.string(), - y: z.string(), - }), - charBox: z.array( - z.object({ - charText: z.string(), - charBox: z.object({ - pt1: z.object({ - x: z.string(), - y: z.string(), - }), - pt2: z.object({ - x: z.string(), - y: z.string(), - }), - pt3: z.object({ - x: z.string(), - y: z.string(), - }), - pt4: z.object({ - x: z.string(), - y: z.string(), - }), - }), - }) - ), - score: z.string(), - }) - ), - }), - }, - - '/.ocr_image': { - description: '.OCR图片识别', - request: z.object({ - image: z.string(), - }), - response: baseResponseSchema.extend({ - data: z.array( - z.object({ - text: z.string(), - pt1: z.object({ - x: z.string(), - y: z.string(), - }), - pt2: z.object({ - x: z.string(), - y: z.string(), - }), - pt3: z.object({ - x: z.string(), - y: z.string(), - }), - pt4: z.object({ - x: z.string(), - y: z.string(), - }), - charBox: z.array( - z.object({ - charText: z.string(), - charBox: z.object({ - pt1: z.object({ - x: z.string(), - y: z.string(), - }), - pt2: z.object({ - x: z.string(), - y: z.string(), - }), - pt3: z.object({ - x: z.string(), - y: z.string(), - }), - pt4: z.object({ - x: z.string(), - y: z.string(), - }), - }), - }) - ), - score: z.string(), - }) - ), - }), - }, - '/translate_en2zh': { - description: '英文翻译为中文', - request: z.object({ - words: z.array(z.string()), - }), - response: baseResponseSchema.extend({ - data: z.array(z.string()), - }), - }, - '/get_login_info': { - description: '获取登录号信息', - request: z.object({}), - response: baseResponseSchema.extend({ - data: z.object({ - user_id: z.number(), - nickname: z.string(), - }), - }), - }, - '/set_input_status': { - description: '设置输入状态', - request: z.object({ - eventType: z.union([z.literal(0), z.literal(1)]), - user_id: z.union([z.number(), z.string()]), - }), - response: baseResponseSchema.extend({ - data: commonResponseDataSchema, - }), - }, - '/download_file': { - description: '下载文件到缓存目录', - request: z - .object({ - base64: z.string().optional(), - url: z.string().optional(), - thread_count: z.number(), - headers: z.union([z.string(), z.array(z.string())]), - name: z.string().optional(), - }) - .refine( - (data) => (data.base64 && !data.url) || (!data.base64 && data.url), - { - message: 'base64 和 url 必须二选一,且不能同时存在或同时为空', - path: ['base64', 'url'], - } - ), - response: baseResponseSchema.extend({ - data: z.object({ - file: z.string(), - }), - }), - }, - '/get_cookies': { - description: '获取cookies', - request: z.object({ - domain: z.string(), - }), - response: baseResponseSchema.extend({ - data: z.object({ - cookies: z.string(), - bkn: z.string(), - }), - }), - }, - '/.handle_quick_operation': { - description: '.对事件执行快速操作', - request: z.object({ - context: z.object({}), - operation: z.object({}), - }), - response: baseResponseSchema, - }, - '/get_csrf_token': { - description: '获取CSRF Token', - request: z.object({}), - response: baseResponseSchema.extend({ - data: z.object({ - token: z.number(), - }), - }), - }, - '/_del_group_notice': { - description: '_删除群公告', - request: z.object({ - group_id: z.union([z.number(), z.string()]), - notice_id: z.number(), - }), - response: baseResponseSchema, - }, - '/get_credentials': { - description: '获取 QQ 相关接口凭证', - request: z.object({ - domain: z.string(), - }), - response: baseResponseSchema.extend({ - data: z.object({ - cookies: z.string(), - token: z.number(), - }), - }), - }, - '/_get_model_show': { - description: '_获取在线机型', - request: z.object({ - model: z.string(), - }), - response: baseResponseSchema.extend({ - data: z.array( - z.object({ - variants: z.object({ - model_show: z.string(), - need_pay: z.boolean(), - }), - }) - ), - }), - }, - '/_set_model_show': { - description: '_设置在线机型', - request: z.object({ - model: z.string(), - model_show: z.string(), - }), - response: baseResponseSchema, - }, - '/can_send_image': { - description: '检查是否可以发送图片', - request: z.object({}), - response: baseResponseSchema.extend({ - yes: z.boolean(), - }), - }, - '/nc_get_packet_status': { - description: '获取packet状态', - request: z.object({}), - response: baseResponseSchema, - }, - '/can_send_record': { - description: '检查是否可以发送语音', - request: z.object({}), - response: baseResponseSchema.extend({ - yes: z.boolean(), - }), - }, - '/get_status': { - description: '获取状态', - request: z.object({}), - response: baseResponseSchema.extend({ - data: z.object({ - online: z.boolean(), - good: z.boolean(), - stat: z.object({}), - }), - }), - }, - '/nc_get_rkey': { - description: '获取rkey', - request: z.object({}), - response: baseResponseSchema.extend({ - data: z.array( - z.object({ - rkey: z.string(), - ttl: z.string(), - time: z.number(), - type: z.number(), - }) - ), - }), - }, - '/get_version_info': { - description: '获取版本信息', - request: z.object({}), - response: baseResponseSchema.extend({ - data: z.object({ - app_name: z.string(), - protocol_version: z.string(), - app_version: z.string(), - }), - }), - }, - '/get_group_shut_list': { - description: '获取群禁言列表', - request: z.object({ - group_id: z.union([z.number(), z.string()]), - }), - response: baseResponseSchema.extend({ - data: z.object({ - uid: z.string(), - qid: z.string(), - uin: z.string(), - nick: z.string(), - remark: z.string(), - cardType: z.number(), - cardName: z.string(), - role: z.number(), - avatarPath: z.string(), - shutUpTime: z.number(), - isDelete: z.boolean(), - isSpecialConcerned: z.boolean(), - isSpecialShield: z.boolean(), - isRobot: z.boolean(), - groupHonor: z.record(z.number()), - memberRealLevel: z.number(), - memberLevel: z.number(), - globalGroupLevel: z.number(), - globalGroupPoint: z.number(), - memberTitleId: z.number(), - memberSpecialTitle: z.string(), - specialTitleExpireTime: z.string(), - userShowFlag: z.number(), - userShowFlagNew: z.number(), - richFlag: z.number(), - mssVipType: z.number(), - bigClubLevel: z.number(), - bigClubFlag: z.number(), - autoRemark: z.string(), - creditLevel: z.number(), - joinTime: z.number(), - lastSpeakTime: z.number(), - memberFlag: z.number(), - memberFlagExt: z.number(), - memberMobileFlag: z.number(), - memberFlagExt2: z.number(), - isSpecialShielded: z.boolean(), - cardNameId: z.number(), - }), - }), - }, -} as const; - -export default oneBotHttpApiSystem; diff --git a/packages/napcat-webui-frontend/src/const/ob_api/user.ts b/packages/napcat-webui-frontend/src/const/ob_api/user.ts deleted file mode 100644 index ba66bcc8..00000000 --- a/packages/napcat-webui-frontend/src/const/ob_api/user.ts +++ /dev/null @@ -1,278 +0,0 @@ -import { z } from 'zod'; - -import onlineStatusDataSchema from './online_status'; -import { baseResponseSchema, commonResponseDataSchema } from './response'; - -const oneBotHttpApiUser = { - '/set_qq_profile': { - description: '设置账号信息', - request: z.object({ - nickname: z.string().describe('昵称'), - personal_note: z.string().describe('个性签名'), - sex: z.string().optional().describe('性别'), - }), - response: baseResponseSchema.extend({ - data: commonResponseDataSchema, - }), - }, - '/send_ark_share': { - description: '获取推荐好友/群聊卡片', - request: z - .object({ - group_id: z - .union([z.string(), z.number()]) - .optional() - .describe('群聊ID,与 user_id 二选一'), - user_id: z - .union([z.string(), z.number()]) - .optional() - .describe('用户ID,与 group_id 二选一'), - phone_number: z.string().optional().describe('对方手机号码'), - }) - .refine( - (data) => - (data.group_id && !data.user_id) || (!data.group_id && data.user_id), - { - message: 'group_id 和 user_id 必须二选一,且不能同时存在或同时为空', - path: ['group_id', 'user_id'], // 错误路径 - } - ), - response: baseResponseSchema.extend({ - data: z.object({ - errCode: z.number(), - errMsg: z.string(), - arkJson: z.string(), - }), - }), - }, - '/send_group_ark_share': { - description: '获取推荐群聊卡片', - request: z.object({ - group_id: z.union([z.string(), z.number()]).describe('群聊ID'), - }), - response: baseResponseSchema.extend({ - data: z.string(), - }), - }, - '/set_online_status': { - description: '设置在线状态', - request: z.object({ - data: onlineStatusDataSchema, - }), - response: baseResponseSchema, - }, - '/get_friends_with_category': { - description: '获取好友分组列表', - request: z.object({}), - response: baseResponseSchema.extend({ - data: z.array( - z.object({ - categoryId: z.number(), - categorySortId: z.number(), - categoryName: z.string(), - categoryMbCount: z.number(), - onlineCount: z.number(), - buddyList: z.array( - z.object({ - qid: z.string(), - longNick: z.string(), - birthday_year: z.number(), - birthday_month: z.number(), - birthday_day: z.number(), - age: z.number(), - sex: z.string(), - eMail: z.string(), - phoneNum: z.string(), - categoryId: z.number(), - richTime: z.number(), - richBuffer: z.object({}), - uid: z.string(), - uin: z.string(), - nick: z.string(), - remark: z.string(), - user_id: z.number(), - nickname: z.string(), - level: z.number(), - }) - ), - }) - ), - }), - }, - '/set_qq_avatar': { - description: '设置头像', - request: z.object({ - file: z.string().describe('图片文件路径(服务器本地或者远程均可)'), - }), - response: baseResponseSchema, - }, - '/send_like': { - description: '点赞', - request: z.object({ - user_id: z.union([z.string(), z.number()]).describe('对方QQ号'), - times: z.number().describe('点赞次数'), - }), - response: baseResponseSchema, - }, - '/create_collection': { - description: '创建收藏', - request: z.object({ - rawData: z.string().describe('收藏内容'), - brief: z.string().describe('收藏简介'), - }), - response: baseResponseSchema.extend({ - data: commonResponseDataSchema, - }), - }, - '/set_friend_add_request': { - description: '处理好友请求', - request: z.object({ - flag: z.string().describe('请求ID'), - approve: z.boolean().describe('是否同意'), - remark: z.string().describe('好友备注'), - }), - response: baseResponseSchema, - }, - '/set_self_longnick': { - description: '设置个性签名', - request: z.object({ - longNick: z.string().describe('签名内容'), - }), - response: baseResponseSchema.extend({ - data: commonResponseDataSchema, - }), - }, - '/get_stranger_info': { - description: '获取账号信息', - request: z.object({ - user_id: z.union([z.string(), z.number()]).describe('对方QQ号'), - }), - response: baseResponseSchema.extend({ - data: z.object({ - user_id: z.number(), - uid: z.string(), - uin: z.string(), - nickname: z.string(), - age: z.number(), - qid: z.string(), - qqLevel: z.number(), - sex: z.string(), - long_nick: z.string(), - reg_time: z.number(), - is_vip: z.boolean(), - is_years_vip: z.boolean(), - vip_level: z.number(), - remark: z.string(), - status: z.number(), - login_days: z.number(), - }), - }), - }, - '/get_friend_list': { - description: '获取好友列表', - request: z.object({ - no_cache: z.boolean().describe('是否不使用缓存'), - }), - response: baseResponseSchema.extend({ - data: z.array( - z.object({ - qid: z.string(), - longNick: z.string(), - birthday_year: z.number(), - birthday_month: z.number(), - birthday_day: z.number(), - age: z.number(), - sex: z.string(), - eMail: z.string(), - phoneNum: z.string(), - categoryId: z.number(), - richTime: z.number(), - richBuffer: z.object({}), - uid: z.string(), - uin: z.string(), - nick: z.string(), - remark: z.string(), - user_id: z.number(), - nickname: z.string(), - level: z.number(), - }) - ), - }), - }, - '/get_profile_like': { - description: '获取点赞列表', - request: z.object({}), - response: baseResponseSchema.extend({ - data: z.object({ - total_count: z.number(), - new_count: z.number(), - new_nearby_count: z.number(), - last_visit_time: z.number(), - userInfos: z.array( - z.object({ - uid: z.string(), - src: z.number(), - latestTime: z.number(), - count: z.number(), - giftCount: z.number(), - customId: z.number(), - lastCharged: z.number(), - bAvailableCnt: z.number(), - bTodayVotedCnt: z.number(), - nick: z.string(), - gender: z.number(), - age: z.number(), - isFriend: z.boolean(), - isvip: z.boolean(), - isSvip: z.boolean(), - uin: z.number(), - }) - ), - }), - }), - }, - '/fetch_custom_face': { - description: '获取收藏表情', - request: z.object({ - count: z.number().optional().describe('获取数量'), - }), - response: baseResponseSchema.extend({ - data: z.array(z.string()), - }), - }, - '/upload_private_file': { - description: '上传私聊文件', - request: z.object({ - user_id: z.union([z.string(), z.number()]), - file: z.string(), - name: z.string(), - }), - response: baseResponseSchema, - }, - '/delete_friend': { - description: '删除好友', - request: z.object({ - user_id: z.union([z.string(), z.number()]).describe('自己QQ号?'), - friend_id: z.union([z.string(), z.number()]).describe('好友QQ号'), - temp_block: z.boolean().describe('是否加入黑名单'), - temp_both_del: z.boolean().describe('是否双向删除'), - }), - response: baseResponseSchema.extend({ - data: commonResponseDataSchema, - }), - }, - '/nc_get_user_status': { - description: '获取用户在线状态', - request: z.object({ - user_id: z.union([z.string(), z.number()]).describe('对方QQ号'), - }), - response: baseResponseSchema.extend({ - data: z.object({ - status: z.number(), - ext_status: z.number(), - }), - }), - }, -} as const; - -export default oneBotHttpApiUser; diff --git a/packages/napcat-webui-frontend/src/pages/dashboard/debug/http/index.tsx b/packages/napcat-webui-frontend/src/pages/dashboard/debug/http/index.tsx index 0637ed08..589deeaa 100644 --- a/packages/napcat-webui-frontend/src/pages/dashboard/debug/http/index.tsx +++ b/packages/napcat-webui-frontend/src/pages/dashboard/debug/http/index.tsx @@ -6,19 +6,20 @@ import { IoClose } from 'react-icons/io5'; import { TbSearch } from 'react-icons/tb'; import key from '@/const/key'; -import oneBotHttpApi from '@/const/ob_api'; -import type { OneBotHttpApiPath } from '@/const/ob_api'; +import { fetchOneBotHttpApi, OneBotHttpApiPath } from '@/const/ob_api'; +import type { OneBotHttpApi } from '@/const/ob_api'; import OneBotApiDebug from '@/components/onebot/api/debug'; import CommandPalette from '@/components/command_palette'; import type { CommandPaletteCommand, CommandPaletteExecuteMode } from '@/components/command_palette'; -import { generateDefaultJson } from '@/utils/zod'; +import { generateDefaultFromTypeBox } from '@/utils/typebox'; import type { OneBotApiDebugRef } from '@/components/onebot/api/debug'; export default function HttpDebug () { const [activeApi, setActiveApi] = useState(null); const [openApis, setOpenApis] = useState([]); + const [oneBotHttpApi, setOneBotHttpApi] = useState({}); const [backgroundImage] = useLocalStorage(key.backgroundImage, ''); const hasBackground = !!backgroundImage; @@ -40,30 +41,34 @@ export default function HttpDebug () { return () => window.removeEventListener('keydown', handler); }, []); - // Initialize Debug Adapter + // Initialize Debug Adapter and fetch schemas useEffect(() => { let currentAdapterName = ''; - const initAdapter = async () => { + const init = async () => { try { - const response = await fetch('/api/Debug/create', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${localStorage.getItem('token')}` - } - }); - const data = await response.json(); - if (data.code === 0) { - currentAdapterName = data.data.adapterName; - setAdapterName(currentAdapterName); - } + const [apiData] = await Promise.all([ + fetchOneBotHttpApi(), + fetch('/api/Debug/create', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${localStorage.getItem('token')}` + } + }).then(res => res.json()).then(data => { + if (data.code === 0) { + currentAdapterName = data.data.adapterName; + setAdapterName(currentAdapterName); + } + }) + ]); + setOneBotHttpApi(apiData); } catch (error) { - console.error('Failed to create debug adapter:', error); + console.error('Failed to initialize debug:', error); } }; - initAdapter(); + init(); return () => { // 不再主动关闭 adapter,由后端自动管理活跃状态 @@ -92,21 +97,24 @@ export default function HttpDebug () { return Object.keys(oneBotHttpApi).map((p) => { const path = p as OneBotHttpApiPath; const item = oneBotHttpApi[path]; + const displayPath = '/' + path; // 简单分组:按描述里已有分类不可靠,这里只用 path 前缀推断 - const group = path.startsWith('/get_') ? 'GET' : (path.startsWith('/set_') ? 'SET' : 'API'); + const group = path.startsWith('get_') ? 'GET' : (path.startsWith('set_') ? 'SET' : 'API'); return { id: path, - title: item?.description || path, - subtitle: item?.request ? '回车发送 · Shift+Enter 仅打开' : undefined, + title: item?.description || displayPath, + subtitle: item?.payload ? '回车发送 · Shift+Enter 仅打开' : undefined, group, }; }); - }, []); + }, [oneBotHttpApi]); const executeCommand = (commandId: string, mode: CommandPaletteExecuteMode) => { const api = commandId as OneBotHttpApiPath; const item = oneBotHttpApi[api]; - const body = item?.request ? generateDefaultJson(item.request) : '{}'; + const body = item?.payloadExample + ? JSON.stringify(item.payloadExample, null, 2) + : (item?.payload ? JSON.stringify(generateDefaultFromTypeBox(item.payload), null, 2) : '{}'); handleSelectApi(api); // 确保请求参数可见 diff --git a/packages/napcat-webui-frontend/src/utils/typebox.ts b/packages/napcat-webui-frontend/src/utils/typebox.ts new file mode 100644 index 00000000..92f1f048 --- /dev/null +++ b/packages/napcat-webui-frontend/src/utils/typebox.ts @@ -0,0 +1,123 @@ +import { TSchema, Type } from '@sinclair/typebox'; + +export type ParsedSchema = { + name?: string; + type: string | string[]; + optional: boolean; + value?: any; + enum?: any[]; + children?: ParsedSchema[]; + description?: string; +}; + +// 定义基础响应结构 (TypeBox 格式) +export const BaseResponseSchema = Type.Object({ + status: Type.Union([Type.Literal('ok'), Type.Literal('failed')], { description: '状态 (ok/failed)' }), + retcode: Type.Number({ description: '返回码' }), + data: Type.Any({ description: '数据' }), + message: Type.String({ description: '消息' }), + wording: Type.String({ description: '提示' }), + echo: Type.Optional(Type.String({ description: '回显' })), +}); + +export function parseTypeBox (schema: TSchema | undefined, name?: string, isRoot = true): ParsedSchema | ParsedSchema[] { + if (!schema) { + return isRoot ? [] : { name, type: 'unknown', optional: false }; + } + + // 如果是根节点解析,且我们需要将其包装在 BaseResponse 中(通常用于 response) + // 但这里我们根据传入的 schema 决定 + + const description = schema.description; + const optional = false; // TypeBox schema doesn't store optionality in the same way Zod does, usually handled by parent object + + // Handle specific types + const type = schema.type; + + if (schema.const !== undefined) { + return { name, type: 'value', value: schema.const, optional, description }; + } + + if (schema.enum) { + return { name, type: 'enum', enum: schema.enum, optional, description }; + } + + if (schema.anyOf || schema.oneOf) { + const options = (schema.anyOf || schema.oneOf) as TSchema[]; + const children = options.map(opt => parseTypeBox(opt, undefined, false) as ParsedSchema); + return { name, type: 'union', children, optional, description }; + } + + if (schema.allOf) { + const parts = schema.allOf as TSchema[]; + // 如果全是对象,尝试合并属性 + const allProperties: Record = {}; + const allRequired: string[] = []; + let canMerge = true; + parts.forEach(part => { + if (part.type === 'object' && part.properties) { + Object.assign(allProperties, part.properties); + if (part.required) allRequired.push(...part.required); + } else { + canMerge = false; + } + }); + + if (canMerge) { + return parseTypeBox({ ...schema, type: 'object', properties: allProperties, required: allRequired }, name, isRoot); + } + // 无法简单合并,当作联合展示 + const children = parts.map(part => parseTypeBox(part, undefined, false) as ParsedSchema); + return { name, type: 'intersection', children, optional, description }; + } + + if (type === 'object') { + const properties = schema.properties || {}; + const required = schema.required || []; + const children = Object.keys(properties).map(key => { + const child = parseTypeBox(properties[key], key, false) as ParsedSchema; + child.optional = !required.includes(key); + return child; + }); + if (isRoot) return children; + return { name, type: 'object', children, optional, description }; + } + + if (type === 'array') { + const items = schema.items as TSchema; + const child = parseTypeBox(items, undefined, false) as ParsedSchema; + return { name, type: 'array', children: [child], optional, description }; + } + + if (type === 'string') return { name, type: 'string', optional, description }; + if (type === 'number' || type === 'integer') return { name, type: 'number', optional, description }; + if (type === 'boolean') return { name, type: 'boolean', optional, description }; + if (type === 'null') return { name, type: 'null', optional, description }; + + return { name, type: type || 'unknown', optional, description }; +} + +export function generateDefaultFromTypeBox (schema: TSchema | undefined): any { + if (!schema) return {}; + if (schema.const !== undefined) return schema.const; + if (schema.default !== undefined) return schema.default; + if (schema.enum) return schema.enum[0]; + if (schema.anyOf || schema.oneOf) return generateDefaultFromTypeBox((schema.anyOf || schema.oneOf)[0]); + + const type = schema.type; + if (type === 'object') { + const obj: any = {}; + const props = schema.properties || {}; + for (const key in props) { + // Only generate defaults for required properties or if we want a full example + obj[key] = generateDefaultFromTypeBox(props[key]); + } + return obj; + } + if (type === 'array') return []; + if (type === 'string') return ''; + if (type === 'number' || type === 'integer') return 0; + if (type === 'boolean') return false; + if (type === 'null') return null; + return null; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8b0ffbe4..bcf80996 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,7 +20,7 @@ importers: version: 16.0.3(rollup@4.53.2) '@vitejs/plugin-react-swc': specifier: ^4.2.2 - version: 4.2.2(@swc/helpers@0.5.17)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)) + version: 4.2.2(@swc/helpers@0.5.17)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/ui': specifier: ^4.0.9 version: 4.0.9(vitest@4.0.9) @@ -35,13 +35,13 @@ importers: version: 5.9.3 vite: specifier: ^6.4.1 - version: 6.4.1(@types/node@22.19.1)(jiti@1.21.7) + version: 6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2) vite-plugin-cp: specifier: ^6.0.3 version: 6.0.3 vitest: specifier: ^4.0.9 - version: 4.0.9(@types/debug@4.1.12)(@types/node@22.19.1)(@vitest/ui@4.0.9)(jiti@1.21.7) + version: 4.0.9(@types/debug@4.1.12)(@types/node@22.19.1)(@vitest/ui@4.0.9)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2) packages/napcat-common: dependencies: @@ -212,9 +212,9 @@ importers: packages/napcat-plugin: dependencies: - napcat-onebot: + napcat-types: specifier: workspace:* - version: link:../napcat-onebot + version: link:../napcat-types devDependencies: '@types/node': specifier: ^22.0.1 @@ -222,9 +222,9 @@ importers: packages/napcat-plugin-builtin: dependencies: - napcat-onebot: + napcat-types: specifier: workspace:* - version: link:../napcat-onebot + version: link:../napcat-types devDependencies: '@types/node': specifier: ^22.0.1 @@ -256,6 +256,28 @@ importers: specifier: ^22.0.1 version: 22.19.1 + packages/napcat-schema: + dependencies: + '@sinclair/typebox': + specifier: ^0.34.38 + version: 0.34.41 + napcat-common: + specifier: workspace:* + version: link:../napcat-common + napcat-onebot: + specifier: workspace:* + version: link:../napcat-onebot + napcat-vite: + specifier: workspace:* + version: link:../napcat-vite + devDependencies: + tsx: + specifier: ^4.7.1 + version: 4.21.0 + vite: + specifier: ^6.0.0 + version: 6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2) + packages/napcat-shell: dependencies: napcat-common: @@ -289,7 +311,44 @@ importers: devDependencies: vitest: specifier: ^4.0.9 - version: 4.0.9(@types/debug@4.1.12)(@types/node@22.19.1)(@vitest/ui@4.0.9)(jiti@1.21.7) + version: 4.0.9(@types/debug@4.1.12)(@types/node@22.19.1)(@vitest/ui@4.0.9)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2) + + packages/napcat-types: + dependencies: + '@types/cors': + specifier: ^2.8.17 + version: 2.8.19 + '@types/express': + specifier: ^4.17.21 + version: 4.17.25 + '@types/ip': + specifier: ^1.1.3 + version: 1.1.3 + '@types/multer': + specifier: ^1.4.12 + version: 1.4.13 + '@types/node': + specifier: ^22.10.7 + version: 22.19.1 + '@types/winston': + specifier: ^2.4.4 + version: 2.4.4 + '@types/ws': + specifier: ^8.5.12 + version: 8.18.1 + '@types/yaml': + specifier: ^1.9.7 + version: 1.9.7 + devDependencies: + napcat-core: + specifier: workspace:* + version: link:../napcat-core + napcat-onebot: + specifier: workspace:* + version: link:../napcat-onebot + tsc-alias: + specifier: ^1.8.16 + version: 1.8.16 packages/napcat-universal: dependencies: @@ -393,97 +452,97 @@ importers: version: 3.2.2(react@19.2.0) '@heroui/accordion': specifier: ^2.2.8 - version: 2.2.24(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.2.24(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/avatar': specifier: 2.2.7 - version: 2.2.7(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.2.7(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/breadcrumbs': specifier: 2.2.7 - version: 2.2.7(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.2.7(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/button': specifier: 2.2.10 - version: 2.2.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.2.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/card': specifier: 2.2.10 - version: 2.2.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.2.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/checkbox': specifier: 2.3.9 - version: 2.3.9(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.3.9(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/chip': specifier: 2.2.7 - version: 2.2.7(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.2.7(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/code': specifier: 2.2.7 - version: 2.2.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.2.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/divider': specifier: ^2.2.21 - version: 2.2.21(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.2.21(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/dropdown': specifier: 2.3.10 - version: 2.3.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.3.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/form': specifier: 2.1.9 - version: 2.1.9(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.1.9(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/image': specifier: 2.2.6 - version: 2.2.6(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.2.6(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/input': specifier: 2.4.10 - version: 2.4.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(@types/react@19.2.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.4.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(@types/react@19.2.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/kbd': specifier: 2.2.7 - version: 2.2.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.2.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/link': specifier: 2.2.8 - version: 2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/listbox': specifier: 2.3.10 - version: 2.3.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.3.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/modal': specifier: 2.2.8 - version: 2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/navbar': specifier: 2.2.9 - version: 2.2.9(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.2.9(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/pagination': specifier: ^2.2.9 - version: 2.2.24(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.2.24(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/popover': specifier: 2.3.10 - version: 2.3.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.3.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/select': specifier: 2.4.10 - version: 2.4.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.4.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/skeleton': specifier: ^2.2.6 - version: 2.2.17(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.2.17(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/slider': specifier: 2.4.8 - version: 2.4.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.4.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/snippet': specifier: 2.2.11 - version: 2.2.11(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.2.11(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/spinner': specifier: 2.2.7 - version: 2.2.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.2.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/switch': specifier: 2.2.9 - version: 2.2.9(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.2.9(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/system': specifier: 2.4.7 - version: 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/table': specifier: ^2.2.9 - version: 2.2.27(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.2.27(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/tabs': specifier: 2.2.8 - version: 2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/theme': specifier: 2.4.6 - version: 2.4.6(tailwindcss@3.4.18) + version: 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@heroui/tooltip': specifier: 2.2.8 - version: 2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@monaco-editor/loader': specifier: ^1.4.0 version: 1.6.1 @@ -493,6 +552,9 @@ importers: '@reduxjs/toolkit': specifier: ^2.5.1 version: 2.10.1(react-redux@9.2.0(@types/react@19.2.4)(react@19.2.0)(redux@5.0.1))(react@19.2.0) + '@sinclair/typebox': + specifier: ^0.34.41 + version: 0.34.41 '@uidotdev/usehooks': specifier: ^2.4.1 version: 2.4.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -588,10 +650,10 @@ importers: version: 4.0.1 tailwind-variants: specifier: ^0.3.0 - version: 0.3.1(tailwindcss@3.4.18) + version: 0.3.1(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) tailwindcss: specifier: ^3.4.17 - version: 3.4.18 + version: 3.4.18(tsx@4.21.0)(yaml@2.8.2) zod: specifier: ^3.24.1 version: 3.25.76 @@ -628,7 +690,7 @@ importers: version: 1.8.8 '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.7.0(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)) + version: 4.7.0(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2)) autoprefixer: specifier: ^10.4.20 version: 10.4.22(postcss@8.5.6) @@ -670,19 +732,19 @@ importers: version: 5.9.3 vite: specifier: ^6.0.5 - version: 6.4.1(@types/node@22.19.1)(jiti@1.21.7) + version: 6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2) vite-plugin-compression: specifier: ^0.5.1 - version: 0.5.1(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)) + version: 0.5.1(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2)) vite-plugin-image-optimizer: specifier: ^2.0.3 - version: 2.0.3(sharp@0.34.5)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)) + version: 2.0.3(sharp@0.34.5)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2)) vite-plugin-static-copy: specifier: ^2.2.0 - version: 2.3.2(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)) + version: 2.3.2(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2)) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)) + version: 5.1.4(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2)) packages: @@ -860,156 +922,312 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.27.2': + resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.25.12': resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.27.2': + resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.25.12': resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.27.2': + resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.25.12': resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.27.2': + resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.25.12': resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.27.2': + resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.25.12': resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.27.2': + resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.25.12': resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.27.2': + resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.12': resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.27.2': + resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.25.12': resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.27.2': + resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.25.12': resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.27.2': + resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.25.12': resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.27.2': + resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.25.12': resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.27.2': + resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.25.12': resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.27.2': + resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.25.12': resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.27.2': + resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.25.12': resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.27.2': + resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.25.12': resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.27.2': + resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.25.12': resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.27.2': + resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.25.12': resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.27.2': + resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.12': resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.27.2': + resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.25.12': resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.27.2': + resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.12': resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.27.2': + resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openharmony-arm64@0.25.12': resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + '@esbuild/openharmony-arm64@0.27.2': + resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/sunos-x64@0.25.12': resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.27.2': + resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.25.12': resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.27.2': + resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.25.12': resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.27.2': + resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.25.12': resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} engines: {node: '>=18'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.27.2': + resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.9.0': resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1648,105 +1866,89 @@ 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==} @@ -2497,67 +2699,56 @@ 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==} @@ -2632,28 +2823,24 @@ 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==} @@ -2784,9 +2971,15 @@ packages: '@types/event-source-polyfill@1.0.5': resolution: {integrity: sha512-iaiDuDI2aIFft7XkcwMzDWLqo7LVDixd2sR6B4wxJut9xcp/Ev9bO4EFg4rm6S9QxATLBj5OPxdeocgmhjwKaw==} + '@types/express-serve-static-core@4.19.8': + resolution: {integrity: sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==} + '@types/express-serve-static-core@5.1.0': resolution: {integrity: sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==} + '@types/express@4.17.25': + resolution: {integrity: sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==} + '@types/express@5.0.5': resolution: {integrity: sha512-LuIQOcb6UmnF7C1PCFmEU1u2hmiHL43fgFQX67sN3H4Z+0Yk0Neo++mFsBjhOAuLzvlQeqAAkeDOZrJs9rzumQ==} @@ -2802,6 +2995,9 @@ packages: '@types/http-errors@2.0.5': resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} + '@types/ip@1.1.3': + resolution: {integrity: sha512-64waoJgkXFTYnCYDUWgSATJ/dXEBanVkaP5d4Sbk7P6U7cTTMhxVyROTckc6JKdwCrgnAjZMn0k3177aQxtDEA==} + '@types/js-cookie@3.0.6': resolution: {integrity: sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==} @@ -2885,9 +3081,17 @@ packages: '@types/use-sync-external-store@0.0.6': resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} + '@types/winston@2.4.4': + resolution: {integrity: sha512-BVGCztsypW8EYwJ+Hq+QNYiT/MUyCif0ouBH+flrY66O5W+KIXAMML6E/0fJpm7VjIzgangahl5S03bJJQGrZw==} + deprecated: This is a stub types definition. winston provides its own type definitions, so you do not need this installed. + '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + '@types/yaml@1.9.7': + resolution: {integrity: sha512-8WMXRDD1D+wCohjfslHDgICd2JtMATZU8CkhH8LVJqcJs6dyYj5TGptzP8wApbmEullGBSsCEzzap73DQ1HJaA==} + deprecated: This is a stub types definition. yaml provides its own type definitions, so you do not need this installed. + '@typescript-eslint/eslint-plugin@8.46.4': resolution: {integrity: sha512-R48VhmTJqplNyDxCyqqVkFSZIx1qX6PzwqgcXn1olLrzxcSBDlOsbtcnQuQhNtnNiJ4Xe5gREI1foajYaYU2Vg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3018,49 +3222,41 @@ 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==} @@ -3251,6 +3447,10 @@ packages: resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} engines: {node: '>= 0.4'} + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + array.prototype.findlast@1.2.5: resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} engines: {node: '>= 0.4'} @@ -3587,6 +3787,10 @@ packages: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} + commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + comment-parser@1.4.1: resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} engines: {node: '>= 12.0.0'} @@ -3779,6 +3983,10 @@ packages: didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} @@ -3878,6 +4086,11 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.27.2: + resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -4395,6 +4608,10 @@ packages: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} @@ -5213,6 +5430,10 @@ packages: resolution: {integrity: sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==} engines: {node: '>= 10.16.0'} + mylas@2.1.14: + resolution: {integrity: sha512-BzQguy9W9NJgoVn2mRWzbFrFWWztGCcng2QI9+41frfk+Athwgx3qhqhvStz7ExeUUu7Kzw427sNzHpEZNINog==} + engines: {node: '>=16.0.0'} + mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} @@ -5427,6 +5648,10 @@ packages: path-to-regexp@8.3.0: resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -5456,6 +5681,10 @@ packages: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} + plimit-lit@1.6.1: + resolution: {integrity: sha512-B7+VDyb8Tl6oMJT9oSO2CW8XC/T4UcJGrwOVoNGwOQsQYhlpfajmrMj5xeejqaASq3V/EqThyOeATEOMuSEXiA==} + engines: {node: '>=12'} + possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} @@ -5585,6 +5814,10 @@ packages: resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} engines: {node: '>=0.6'} + queue-lit@1.5.2: + resolution: {integrity: sha512-tLc36IOPeMAubu8BkW8YDBV+WyIgKlYU7zUNs0J5Vk9skSZ4JfGlPOqplP0aHdfv7HL0B2Pg6nwiq60Qc6M2Hw==} + engines: {node: '>=12'} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -5990,6 +6223,10 @@ packages: resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} engines: {node: '>=18'} + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + smart-buffer@4.2.0: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} @@ -6307,6 +6544,11 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + tsc-alias@1.8.16: + resolution: {integrity: sha512-QjCyu55NFyRSBAl6+MTFwplpFcnm2Pq01rR/uxfqJoLMm6X3O14KEGtaSDZpJYaE1bJBGDjD0eSuiIWPe2T58g==} + engines: {node: '>=16.20.2'} + hasBin: true + tsconfck@3.1.6: resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} engines: {node: ^18 || >=20} @@ -6326,6 +6568,11 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsx@4.21.0: + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} + engines: {node: '>=18.0.0'} + hasBin: true + tsyringe@4.10.0: resolution: {integrity: sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==} engines: {node: '>= 6.0.0'} @@ -6712,6 +6959,11 @@ packages: yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + yaml@2.8.2: + resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} + engines: {node: '>= 14.6'} + hasBin: true + yargs-parser@20.2.9: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} @@ -6982,81 +7234,159 @@ snapshots: '@esbuild/aix-ppc64@0.25.12': optional: true + '@esbuild/aix-ppc64@0.27.2': + optional: true + '@esbuild/android-arm64@0.25.12': optional: true + '@esbuild/android-arm64@0.27.2': + optional: true + '@esbuild/android-arm@0.25.12': optional: true + '@esbuild/android-arm@0.27.2': + optional: true + '@esbuild/android-x64@0.25.12': optional: true + '@esbuild/android-x64@0.27.2': + optional: true + '@esbuild/darwin-arm64@0.25.12': optional: true + '@esbuild/darwin-arm64@0.27.2': + optional: true + '@esbuild/darwin-x64@0.25.12': optional: true + '@esbuild/darwin-x64@0.27.2': + optional: true + '@esbuild/freebsd-arm64@0.25.12': optional: true + '@esbuild/freebsd-arm64@0.27.2': + optional: true + '@esbuild/freebsd-x64@0.25.12': optional: true + '@esbuild/freebsd-x64@0.27.2': + optional: true + '@esbuild/linux-arm64@0.25.12': optional: true + '@esbuild/linux-arm64@0.27.2': + optional: true + '@esbuild/linux-arm@0.25.12': optional: true + '@esbuild/linux-arm@0.27.2': + optional: true + '@esbuild/linux-ia32@0.25.12': optional: true + '@esbuild/linux-ia32@0.27.2': + optional: true + '@esbuild/linux-loong64@0.25.12': optional: true + '@esbuild/linux-loong64@0.27.2': + optional: true + '@esbuild/linux-mips64el@0.25.12': optional: true + '@esbuild/linux-mips64el@0.27.2': + optional: true + '@esbuild/linux-ppc64@0.25.12': optional: true + '@esbuild/linux-ppc64@0.27.2': + optional: true + '@esbuild/linux-riscv64@0.25.12': optional: true + '@esbuild/linux-riscv64@0.27.2': + optional: true + '@esbuild/linux-s390x@0.25.12': optional: true + '@esbuild/linux-s390x@0.27.2': + optional: true + '@esbuild/linux-x64@0.25.12': optional: true + '@esbuild/linux-x64@0.27.2': + optional: true + '@esbuild/netbsd-arm64@0.25.12': optional: true + '@esbuild/netbsd-arm64@0.27.2': + optional: true + '@esbuild/netbsd-x64@0.25.12': optional: true + '@esbuild/netbsd-x64@0.27.2': + optional: true + '@esbuild/openbsd-arm64@0.25.12': optional: true + '@esbuild/openbsd-arm64@0.27.2': + optional: true + '@esbuild/openbsd-x64@0.25.12': optional: true + '@esbuild/openbsd-x64@0.27.2': + optional: true + '@esbuild/openharmony-arm64@0.25.12': optional: true + '@esbuild/openharmony-arm64@0.27.2': + optional: true + '@esbuild/sunos-x64@0.25.12': optional: true + '@esbuild/sunos-x64@0.27.2': + optional: true + '@esbuild/win32-arm64@0.25.12': optional: true + '@esbuild/win32-arm64@0.27.2': + optional: true + '@esbuild/win32-ia32@0.25.12': optional: true + '@esbuild/win32-ia32@0.27.2': + optional: true + '@esbuild/win32-x64@0.25.12': optional: true + '@esbuild/win32-x64@0.27.2': + optional: true + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1(jiti@1.21.7))': dependencies: eslint: 9.39.1(jiti@1.21.7) @@ -7131,17 +7461,17 @@ snapshots: '@gar/promisify@1.1.3': {} - '@heroui/accordion@2.2.24(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/accordion@2.2.24(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@heroui/aria-utils': 2.2.24(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/divider': 2.2.20(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/aria-utils': 2.2.24(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/divider': 2.2.20(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/dom-animation': 2.1.10(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0)) - '@heroui/framer-utils': 2.1.23(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/framer-utils': 2.1.23(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/react-utils': 2.1.14(react@19.2.0) '@heroui/shared-icons': 2.1.10(react@19.2.0) '@heroui/shared-utils': 2.1.12 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@heroui/use-aria-accordion': 2.2.18(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@react-aria/focus': 3.21.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@react-aria/interactions': 3.25.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -7152,9 +7482,9 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/aria-utils@2.2.24(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/aria-utils@2.2.24(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@heroui/system': 2.4.23(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/system': 2.4.23(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@react-aria/utils': 3.31.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@react-stately/collections': 3.12.8(react@19.2.0) '@react-types/overlays': 3.9.2(react@19.2.0) @@ -7165,11 +7495,11 @@ snapshots: - '@heroui/theme' - framer-motion - '@heroui/aria-utils@2.2.8(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/aria-utils@2.2.8(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/react-rsc-utils': 2.1.2(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@react-aria/utils': 3.26.0(react@19.2.0) '@react-stately/collections': 3.12.0(react@19.2.0) '@react-stately/overlays': 3.6.12(react@19.2.0) @@ -7181,12 +7511,12 @@ snapshots: - '@heroui/theme' - framer-motion - '@heroui/avatar@2.2.7(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/avatar@2.2.7(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@heroui/use-image': 2.1.3(react@19.2.0) '@react-aria/focus': 3.19.0(react@19.2.0) '@react-aria/interactions': 3.22.5(react@19.2.0) @@ -7194,13 +7524,13 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/breadcrumbs@2.2.7(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/breadcrumbs@2.2.7(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-icons': 2.1.2(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@react-aria/breadcrumbs': 3.5.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@react-aria/focus': 3.19.0(react@19.2.0) '@react-aria/utils': 3.26.0(react@19.2.0) @@ -7209,14 +7539,14 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/button@2.2.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/button@2.2.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/react-utils': 2.1.4(react@19.2.0) - '@heroui/ripple': 2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/ripple': 2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/spinner': 2.2.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/spinner': 2.2.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@heroui/use-aria-button': 2.2.5(react@19.2.0) '@react-aria/button': 3.11.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@react-aria/focus': 3.19.0(react@19.2.0) @@ -7228,13 +7558,13 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/card@2.2.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/card@2.2.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/react-utils': 2.1.4(react@19.2.0) - '@heroui/ripple': 2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/ripple': 2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@heroui/use-aria-button': 2.2.5(react@19.2.0) '@react-aria/button': 3.11.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@react-aria/focus': 3.19.0(react@19.2.0) @@ -7245,13 +7575,13 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/checkbox@2.3.27(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/checkbox@2.3.27(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@heroui/form': 2.1.27(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/form': 2.1.27(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/react-utils': 2.1.14(react@19.2.0) '@heroui/shared-utils': 2.1.12 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@heroui/use-callback-ref': 2.1.8(react@19.2.0) '@heroui/use-safe-layout-effect': 2.1.8(react@19.2.0) '@react-aria/checkbox': 3.16.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -7264,13 +7594,13 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/checkbox@2.3.9(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/checkbox@2.3.9(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@heroui/form': 2.1.9(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/form': 2.1.9(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@heroui/use-callback-ref': 2.1.2(react@19.2.0) '@heroui/use-safe-layout-effect': 2.1.2(react@19.2.0) '@react-aria/checkbox': 3.15.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -7285,13 +7615,13 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/chip@2.2.7(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/chip@2.2.7(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-icons': 2.1.2(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@react-aria/focus': 3.19.0(react@19.2.0) '@react-aria/interactions': 3.22.5(react@19.2.0) '@react-aria/utils': 3.26.0(react@19.2.0) @@ -7299,39 +7629,39 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/code@2.2.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/code@2.2.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system-rsc': 2.3.6(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system-rsc': 2.3.6(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/divider@2.2.20(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/divider@2.2.20(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/react-rsc-utils': 2.1.9(react@19.2.0) - '@heroui/system-rsc': 2.3.20(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system-rsc': 2.3.20(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@react-types/shared': 3.32.1(react@19.2.0) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/divider@2.2.21(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/divider@2.2.21(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/react-rsc-utils': 2.1.9(react@19.2.0) - '@heroui/system-rsc': 2.3.21(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system-rsc': 2.3.21(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@react-types/shared': 3.32.1(react@19.2.0) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/divider@2.2.6(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/divider@2.2.6(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/react-rsc-utils': 2.1.2(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system-rsc': 2.3.6(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system-rsc': 2.3.6(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@react-types/shared': 3.26.0(react@19.2.0) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) @@ -7344,15 +7674,15 @@ snapshots: dependencies: framer-motion: 12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/dropdown@2.3.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/dropdown@2.3.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@heroui/aria-utils': 2.2.8(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/menu': 2.2.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/popover': 2.3.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/aria-utils': 2.2.8(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/menu': 2.2.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/popover': 2.3.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@react-aria/focus': 3.19.0(react@19.2.0) '@react-aria/menu': 3.16.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@react-aria/utils': 3.26.0(react@19.2.0) @@ -7362,23 +7692,23 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/form@2.1.27(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/form@2.1.27(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/shared-utils': 2.1.12 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@react-stately/form': 3.2.2(react@19.2.0) '@react-types/form': 3.7.16(react@19.2.0) '@react-types/shared': 3.32.1(react@19.2.0) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/form@2.1.9(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/form@2.1.9(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@react-aria/utils': 3.26.0(react@19.2.0) '@react-stately/form': 3.1.0(react@19.2.0) '@react-types/form': 3.7.8(react@19.2.0) @@ -7386,9 +7716,9 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/framer-utils@2.1.23(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/framer-utils@2.1.23(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@heroui/system': 2.4.23(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/system': 2.4.23(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/use-measure': 2.1.8(react@19.2.0) framer-motion: 12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: 19.2.0 @@ -7396,10 +7726,10 @@ snapshots: transitivePeerDependencies: - '@heroui/theme' - '@heroui/framer-utils@2.1.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/framer-utils@2.1.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/use-measure': 2.1.2(react@19.2.0) framer-motion: 12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: 19.2.0 @@ -7407,24 +7737,24 @@ snapshots: transitivePeerDependencies: - '@heroui/theme' - '@heroui/image@2.2.6(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/image@2.2.6(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@heroui/use-image': 2.1.3(react@19.2.0) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/input@2.4.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(@types/react@19.2.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/input@2.4.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(@types/react@19.2.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@heroui/form': 2.1.9(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/form': 2.1.9(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-icons': 2.1.2(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@heroui/use-safe-layout-effect': 2.1.2(react@19.2.0) '@react-aria/focus': 3.19.0(react@19.2.0) '@react-aria/interactions': 3.22.5(react@19.2.0) @@ -7439,23 +7769,23 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@heroui/kbd@2.2.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/kbd@2.2.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system-rsc': 2.3.6(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system-rsc': 2.3.6(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@react-aria/utils': 3.26.0(react@19.2.0) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/link@2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/link@2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-icons': 2.1.2(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@heroui/use-aria-link': 2.2.6(react@19.2.0) '@react-aria/focus': 3.19.0(react@19.2.0) '@react-aria/link': 3.7.7(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -7464,14 +7794,14 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/listbox@2.3.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/listbox@2.3.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@heroui/aria-utils': 2.2.8(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/divider': 2.2.6(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/aria-utils': 2.2.8(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/divider': 2.2.6(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@heroui/use-is-mobile': 2.2.3(react@19.2.0) '@react-aria/focus': 3.19.0(react@19.2.0) '@react-aria/interactions': 3.22.5(react@19.2.0) @@ -7486,14 +7816,14 @@ snapshots: transitivePeerDependencies: - framer-motion - '@heroui/menu@2.2.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/menu@2.2.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@heroui/aria-utils': 2.2.8(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/divider': 2.2.6(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/aria-utils': 2.2.8(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/divider': 2.2.6(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@heroui/use-is-mobile': 2.2.3(react@19.2.0) '@react-aria/focus': 3.19.0(react@19.2.0) '@react-aria/interactions': 3.22.5(react@19.2.0) @@ -7508,15 +7838,15 @@ snapshots: transitivePeerDependencies: - framer-motion - '@heroui/modal@2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/modal@2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/dom-animation': 2.1.2(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0)) - '@heroui/framer-utils': 2.1.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/framer-utils': 2.1.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-icons': 2.1.2(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@heroui/use-aria-button': 2.2.5(react@19.2.0) '@heroui/use-aria-modal-overlay': 2.2.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/use-disclosure': 2.2.3(react@19.2.0) @@ -7532,14 +7862,14 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/navbar@2.2.9(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/navbar@2.2.9(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/dom-animation': 2.1.2(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0)) - '@heroui/framer-utils': 2.1.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/framer-utils': 2.1.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@heroui/use-scroll-position': 2.1.2(react@19.2.0) '@react-aria/button': 3.11.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@react-aria/focus': 3.19.0(react@19.2.0) @@ -7552,13 +7882,13 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/pagination@2.2.24(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/pagination@2.2.24(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/react-utils': 2.1.14(react@19.2.0) '@heroui/shared-icons': 2.1.10(react@19.2.0) '@heroui/shared-utils': 2.1.12 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@heroui/use-intersection-observer': 2.2.14(react@19.2.0) '@heroui/use-pagination': 2.2.18(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@react-aria/focus': 3.21.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -7569,16 +7899,16 @@ snapshots: react-dom: 19.2.0(react@19.2.0) scroll-into-view-if-needed: 3.0.10 - '@heroui/popover@2.3.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/popover@2.3.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@heroui/aria-utils': 2.2.8(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/button': 2.2.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/aria-utils': 2.2.8(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/button': 2.2.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/dom-animation': 2.1.2(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0)) - '@heroui/framer-utils': 2.1.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/framer-utils': 2.1.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@heroui/use-aria-button': 2.2.5(react@19.2.0) '@heroui/use-safe-layout-effect': 2.1.2(react@19.2.0) '@react-aria/dialog': 3.5.20(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -7613,40 +7943,40 @@ snapshots: '@heroui/shared-utils': 2.1.3 react: 19.2.0 - '@heroui/ripple@2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/ripple@2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/dom-animation': 2.1.2(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0)) '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) framer-motion: 12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/scroll-shadow@2.3.6(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/scroll-shadow@2.3.6(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@heroui/use-data-scroll-overflow': 2.2.3(react@19.2.0) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/select@2.4.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/select@2.4.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@heroui/aria-utils': 2.2.8(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/form': 2.1.9(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/listbox': 2.3.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/popover': 2.3.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/aria-utils': 2.2.8(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/form': 2.1.9(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/listbox': 2.3.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/popover': 2.3.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/react-utils': 2.1.4(react@19.2.0) - '@heroui/scroll-shadow': 2.3.6(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/scroll-shadow': 2.3.6(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/shared-icons': 2.1.2(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/spinner': 2.2.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/spinner': 2.2.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@heroui/use-aria-button': 2.2.5(react@19.2.0) '@heroui/use-aria-multiselect': 2.4.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/use-safe-layout-effect': 2.1.2(react@19.2.0) @@ -7673,21 +8003,21 @@ snapshots: '@heroui/shared-utils@2.1.3': {} - '@heroui/skeleton@2.2.17(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/skeleton@2.2.17(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/shared-utils': 2.1.12 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/slider@2.4.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/slider@2.4.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) - '@heroui/tooltip': 2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) + '@heroui/tooltip': 2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@react-aria/focus': 3.19.0(react@19.2.0) '@react-aria/i18n': 3.12.4(react@19.2.0) '@react-aria/interactions': 3.22.5(react@19.2.0) @@ -7700,15 +8030,15 @@ snapshots: transitivePeerDependencies: - framer-motion - '@heroui/snippet@2.2.11(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/snippet@2.2.11(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@heroui/button': 2.2.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/button': 2.2.10(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-icons': 2.1.2(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) - '@heroui/tooltip': 2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) + '@heroui/tooltip': 2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/use-clipboard': 2.1.3(react@19.2.0) '@react-aria/focus': 3.19.0(react@19.2.0) '@react-aria/utils': 3.26.0(react@19.2.0) @@ -7716,30 +8046,30 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/spacer@2.2.21(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/spacer@2.2.21(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/react-utils': 2.1.14(react@19.2.0) '@heroui/shared-utils': 2.1.12 - '@heroui/system-rsc': 2.3.20(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system-rsc': 2.3.20(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/spinner@2.2.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/spinner@2.2.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system-rsc': 2.3.6(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system-rsc': 2.3.6(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/switch@2.2.9(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/switch@2.2.9(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@heroui/use-safe-layout-effect': 2.1.2(react@19.2.0) '@react-aria/focus': 3.19.0(react@19.2.0) '@react-aria/interactions': 3.22.5(react@19.2.0) @@ -7751,30 +8081,30 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/system-rsc@2.3.20(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react@19.2.0)': + '@heroui/system-rsc@2.3.20(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react@19.2.0)': dependencies: - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@react-types/shared': 3.32.1(react@19.2.0) clsx: 1.2.1 react: 19.2.0 - '@heroui/system-rsc@2.3.21(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react@19.2.0)': + '@heroui/system-rsc@2.3.21(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react@19.2.0)': dependencies: - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@react-types/shared': 3.32.1(react@19.2.0) react: 19.2.0 - '@heroui/system-rsc@2.3.6(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react@19.2.0)': + '@heroui/system-rsc@2.3.6(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react@19.2.0)': dependencies: - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@react-types/shared': 3.26.0(react@19.2.0) clsx: 1.2.1 react: 19.2.0 - '@heroui/system@2.4.23(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/system@2.4.23(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/react-utils': 2.1.14(react@19.2.0) - '@heroui/system-rsc': 2.3.20(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react@19.2.0) + '@heroui/system-rsc': 2.3.20(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react@19.2.0) '@react-aria/i18n': 3.12.13(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@react-aria/overlays': 3.30.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@react-aria/utils': 3.31.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -7784,10 +8114,10 @@ snapshots: transitivePeerDependencies: - '@heroui/theme' - '@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@heroui/react-utils': 2.1.4(react@19.2.0) - '@heroui/system-rsc': 2.3.6(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react@19.2.0) + '@heroui/system-rsc': 2.3.6(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react@19.2.0) '@internationalized/date': 3.6.0 '@react-aria/i18n': 3.12.4(react@19.2.0) '@react-aria/overlays': 3.24.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -7800,15 +8130,15 @@ snapshots: transitivePeerDependencies: - '@heroui/theme' - '@heroui/table@2.2.27(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/table@2.2.27(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@heroui/checkbox': 2.3.27(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/checkbox': 2.3.27(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/react-utils': 2.1.14(react@19.2.0) '@heroui/shared-icons': 2.1.10(react@19.2.0) '@heroui/shared-utils': 2.1.12 - '@heroui/spacer': 2.2.21(@heroui/theme@2.4.6(tailwindcss@3.4.18))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/spacer': 2.2.21(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@react-aria/focus': 3.21.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@react-aria/interactions': 3.25.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@react-aria/table': 3.17.8(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -7821,14 +8151,14 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@heroui/tabs@2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/tabs@2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@heroui/aria-utils': 2.2.8(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/framer-utils': 2.1.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/aria-utils': 2.2.8(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/framer-utils': 2.1.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@heroui/use-is-mounted': 2.1.2(react@19.2.0) '@heroui/use-update-effect': 2.1.2(react@19.2.0) '@react-aria/focus': 3.19.0(react@19.2.0) @@ -7843,7 +8173,7 @@ snapshots: react-dom: 19.2.0(react@19.2.0) scroll-into-view-if-needed: 3.0.10 - '@heroui/theme@2.4.6(tailwindcss@3.4.18)': + '@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@heroui/shared-utils': 2.1.3 clsx: 1.2.1 @@ -7852,18 +8182,18 @@ snapshots: deepmerge: 4.3.1 flat: 5.0.2 tailwind-merge: 2.6.0 - tailwind-variants: 0.1.20(tailwindcss@3.4.18) - tailwindcss: 3.4.18 + tailwind-variants: 0.1.20(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) + tailwindcss: 3.4.18(tsx@4.21.0)(yaml@2.8.2) - '@heroui/tooltip@2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@heroui/tooltip@2.2.8(@heroui/system@2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@heroui/aria-utils': 2.2.8(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/aria-utils': 2.2.8(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/dom-animation': 2.1.2(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0)) - '@heroui/framer-utils': 2.1.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/framer-utils': 2.1.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@heroui/react-utils': 2.1.4(react@19.2.0) '@heroui/shared-utils': 2.1.3 - '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@heroui/theme': 2.4.6(tailwindcss@3.4.18) + '@heroui/system': 2.4.7(@heroui/theme@2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)))(framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@heroui/theme': 2.4.6(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)) '@heroui/use-safe-layout-effect': 2.1.2(react@19.2.0) '@react-aria/interactions': 3.22.5(react@19.2.0) '@react-aria/overlays': 3.24.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -9500,6 +9830,13 @@ snapshots: '@types/event-source-polyfill@1.0.5': {} + '@types/express-serve-static-core@4.19.8': + dependencies: + '@types/node': 22.19.1 + '@types/qs': 6.14.0 + '@types/range-parser': 1.2.7 + '@types/send': 1.2.1 + '@types/express-serve-static-core@5.1.0': dependencies: '@types/node': 22.19.1 @@ -9507,6 +9844,13 @@ snapshots: '@types/range-parser': 1.2.7 '@types/send': 1.2.1 + '@types/express@4.17.25': + dependencies: + '@types/body-parser': 1.19.6 + '@types/express-serve-static-core': 4.19.8 + '@types/qs': 6.14.0 + '@types/serve-static': 1.15.10 + '@types/express@5.0.5': dependencies: '@types/body-parser': 1.19.6 @@ -9526,6 +9870,10 @@ snapshots: '@types/http-errors@2.0.5': {} + '@types/ip@1.1.3': + dependencies: + '@types/node': 22.19.1 + '@types/js-cookie@3.0.6': {} '@types/json-schema@7.0.15': {} @@ -9607,10 +9955,18 @@ snapshots: '@types/use-sync-external-store@0.0.6': {} + '@types/winston@2.4.4': + dependencies: + winston: 3.18.3 + '@types/ws@8.18.1': dependencies: '@types/node': 22.19.1 + '@types/yaml@1.9.7': + dependencies: + yaml: 2.8.2 + '@typescript-eslint/eslint-plugin@8.46.4(@typescript-eslint/parser@8.46.4(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.1(jiti@1.21.7))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -9797,15 +10153,15 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vitejs/plugin-react-swc@4.2.2(@swc/helpers@0.5.17)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7))': + '@vitejs/plugin-react-swc@4.2.2(@swc/helpers@0.5.17)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@rolldown/pluginutils': 1.0.0-beta.47 '@swc/core': 1.15.1(@swc/helpers@0.5.17) - vite: 6.4.1(@types/node@22.19.1)(jiti@1.21.7) + vite: 6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - '@swc/helpers' - '@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7))': + '@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@babel/core': 7.28.5 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) @@ -9813,7 +10169,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.27 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 6.4.1(@types/node@22.19.1)(jiti@1.21.7) + vite: 6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - supports-color @@ -9826,13 +10182,13 @@ snapshots: chai: 6.2.1 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.9(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7))': + '@vitest/mocker@4.0.9(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 4.0.9 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 6.4.1(@types/node@22.19.1)(jiti@1.21.7) + vite: 6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2) '@vitest/pretty-format@4.0.9': dependencies: @@ -9860,7 +10216,7 @@ snapshots: sirv: 3.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vitest: 4.0.9(@types/debug@4.1.12)(@types/node@22.19.1)(@vitest/ui@4.0.9)(jiti@1.21.7) + vitest: 4.0.9(@types/debug@4.1.12)(@types/node@22.19.1)(@vitest/ui@4.0.9)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2) '@vitest/utils@4.0.9': dependencies: @@ -9994,6 +10350,8 @@ snapshots: is-string: 1.1.1 math-intrinsics: 1.1.0 + array-union@2.1.0: {} + array.prototype.findlast@1.2.5: dependencies: call-bind: 1.0.8 @@ -10385,6 +10743,8 @@ snapshots: commander@4.1.1: {} + commander@9.5.0: {} + comment-parser@1.4.1: {} compressible@2.0.18: @@ -10554,6 +10914,10 @@ snapshots: didyoumean@1.2.2: {} + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + dlv@1.1.3: {} doctrine@2.1.0: @@ -10743,6 +11107,35 @@ snapshots: '@esbuild/win32-ia32': 0.25.12 '@esbuild/win32-x64': 0.25.12 + esbuild@0.27.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.2 + '@esbuild/android-arm': 0.27.2 + '@esbuild/android-arm64': 0.27.2 + '@esbuild/android-x64': 0.27.2 + '@esbuild/darwin-arm64': 0.27.2 + '@esbuild/darwin-x64': 0.27.2 + '@esbuild/freebsd-arm64': 0.27.2 + '@esbuild/freebsd-x64': 0.27.2 + '@esbuild/linux-arm': 0.27.2 + '@esbuild/linux-arm64': 0.27.2 + '@esbuild/linux-ia32': 0.27.2 + '@esbuild/linux-loong64': 0.27.2 + '@esbuild/linux-mips64el': 0.27.2 + '@esbuild/linux-ppc64': 0.27.2 + '@esbuild/linux-riscv64': 0.27.2 + '@esbuild/linux-s390x': 0.27.2 + '@esbuild/linux-x64': 0.27.2 + '@esbuild/netbsd-arm64': 0.27.2 + '@esbuild/netbsd-x64': 0.27.2 + '@esbuild/openbsd-arm64': 0.27.2 + '@esbuild/openbsd-x64': 0.27.2 + '@esbuild/openharmony-arm64': 0.27.2 + '@esbuild/sunos-x64': 0.27.2 + '@esbuild/win32-arm64': 0.27.2 + '@esbuild/win32-ia32': 0.27.2 + '@esbuild/win32-x64': 0.27.2 + escalade@3.2.0: {} escape-html@1.0.3: {} @@ -11386,6 +11779,15 @@ snapshots: define-properties: 1.2.1 gopd: 1.2.0 + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + globrex@0.1.2: {} goober@2.1.18(csstype@3.1.3): @@ -12399,6 +12801,8 @@ snapshots: type-is: 1.6.18 xtend: 4.0.2 + mylas@2.1.14: {} + mz@2.7.0: dependencies: any-promise: 1.3.0 @@ -12638,6 +13042,8 @@ snapshots: path-to-regexp@8.3.0: {} + path-type@4.0.0: {} + pathe@2.0.3: {} pend@1.2.0: {} @@ -12654,6 +13060,10 @@ snapshots: pirates@4.0.7: {} + plimit-lit@1.6.1: + dependencies: + queue-lit: 1.5.2 + possible-typed-array-names@1.1.0: {} postcss-import@15.1.0(postcss@8.5.6): @@ -12668,12 +13078,14 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.5.6 - postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6): + postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.2): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 1.21.7 postcss: 8.5.6 + tsx: 4.21.0 + yaml: 2.8.2 postcss-nested@6.2.0(postcss@8.5.6): dependencies: @@ -12774,6 +13186,8 @@ snapshots: dependencies: side-channel: 1.1.0 + queue-lit@1.5.2: {} + queue-microtask@1.2.3: {} quick-lru@5.1.1: {} @@ -13309,6 +13723,8 @@ snapshots: mrmime: 2.0.1 totalist: 3.0.1 + slash@3.0.0: {} + smart-buffer@4.2.0: {} socks-proxy-agent@7.0.0: @@ -13512,17 +13928,17 @@ snapshots: tailwind-merge@2.6.0: {} - tailwind-variants@0.1.20(tailwindcss@3.4.18): + tailwind-variants@0.1.20(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)): dependencies: tailwind-merge: 1.14.0 - tailwindcss: 3.4.18 + tailwindcss: 3.4.18(tsx@4.21.0)(yaml@2.8.2) - tailwind-variants@0.3.1(tailwindcss@3.4.18): + tailwind-variants@0.3.1(tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2)): dependencies: tailwind-merge: 2.5.4 - tailwindcss: 3.4.18 + tailwindcss: 3.4.18(tsx@4.21.0)(yaml@2.8.2) - tailwindcss@3.4.18: + tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.2): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -13541,7 +13957,7 @@ snapshots: postcss: 8.5.6 postcss-import: 15.1.0(postcss@8.5.6) postcss-js: 4.1.0(postcss@8.5.6) - postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.2) postcss-nested: 6.2.0(postcss@8.5.6) postcss-selector-parser: 6.1.2 resolve: 1.22.11 @@ -13673,6 +14089,16 @@ snapshots: ts-interface-checker@0.1.13: {} + tsc-alias@1.8.16: + dependencies: + chokidar: 3.6.0 + commander: 9.5.0 + get-tsconfig: 4.13.0 + globby: 11.1.0 + mylas: 2.1.14 + normalize-path: 3.0.0 + plimit-lit: 1.6.1 + tsconfck@3.1.6(typescript@5.9.3): optionalDependencies: typescript: 5.9.3 @@ -13688,6 +14114,13 @@ snapshots: tslib@2.8.1: {} + tsx@4.21.0: + dependencies: + esbuild: 0.27.2 + get-tsconfig: 4.13.0 + optionalDependencies: + fsevents: 2.3.3 + tsyringe@4.10.0: dependencies: tslib: 1.14.1 @@ -13959,12 +14392,12 @@ snapshots: remove-trailing-separator: 1.1.0 replace-ext: 1.0.1 - vite-plugin-compression@0.5.1(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)): + vite-plugin-compression@0.5.1(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2)): dependencies: chalk: 4.1.2 debug: 4.4.3 fs-extra: 10.1.0 - vite: 6.4.1(@types/node@22.19.1)(jiti@1.21.7) + vite: 6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - supports-color @@ -13977,35 +14410,35 @@ snapshots: transitivePeerDependencies: - supports-color - vite-plugin-image-optimizer@2.0.3(sharp@0.34.5)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)): + vite-plugin-image-optimizer@2.0.3(sharp@0.34.5)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2)): dependencies: ansi-colors: 4.1.3 pathe: 2.0.3 - vite: 6.4.1(@types/node@22.19.1)(jiti@1.21.7) + vite: 6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2) optionalDependencies: sharp: 0.34.5 - vite-plugin-static-copy@2.3.2(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)): + vite-plugin-static-copy@2.3.2(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2)): dependencies: chokidar: 3.6.0 fast-glob: 3.3.3 fs-extra: 11.3.2 p-map: 7.0.4 picocolors: 1.1.1 - vite: 6.4.1(@types/node@22.19.1)(jiti@1.21.7) + vite: 6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2) - vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)): + vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2)): dependencies: debug: 4.4.3 globrex: 0.1.2 tsconfck: 3.1.6(typescript@5.9.3) optionalDependencies: - vite: 6.4.1(@types/node@22.19.1)(jiti@1.21.7) + vite: 6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - supports-color - typescript - vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7): + vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) @@ -14017,11 +14450,13 @@ snapshots: '@types/node': 22.19.1 fsevents: 2.3.3 jiti: 1.21.7 + tsx: 4.21.0 + yaml: 2.8.2 - vitest@4.0.9(@types/debug@4.1.12)(@types/node@22.19.1)(@vitest/ui@4.0.9)(jiti@1.21.7): + vitest@4.0.9(@types/debug@4.1.12)(@types/node@22.19.1)(@vitest/ui@4.0.9)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2): dependencies: '@vitest/expect': 4.0.9 - '@vitest/mocker': 4.0.9(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)) + '@vitest/mocker': 4.0.9(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/pretty-format': 4.0.9 '@vitest/runner': 4.0.9 '@vitest/snapshot': 4.0.9 @@ -14038,7 +14473,7 @@ snapshots: tinyexec: 0.3.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 6.4.1(@types/node@22.19.1)(jiti@1.21.7) + vite: 6.4.1(@types/node@22.19.1)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: '@types/debug': 4.1.12 @@ -14169,6 +14604,8 @@ snapshots: yallist@4.0.0: {} + yaml@2.8.2: {} + yargs-parser@20.2.9: {} yazl@2.5.1: