From de9d5180fe42a3ab3785ef48815b70cf8dc9fc15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=8B=E7=93=9C=E4=B8=80=E5=8D=81=E9=9B=AA?= Date: Tue, 27 Jan 2026 19:07:17 +0800 Subject: [PATCH] Add payload and return schemas to OneBot actions (#1549) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add payload and return schemas to OneBot actions Introduced explicit payloadSchema and returnSchema definitions for all OneBotAction classes using @sinclair/typebox. This improves type safety, API documentation, and validation for action payloads and return values. Also refactored method signatures and types for consistency across the codebase. * Refactor payload schemas to use string IDs Replaced Type.Union([Type.Number(), Type.String()]) with Type.String for group_id, user_id, and similar fields across all action payload schemas to standardize input types. Also made minor improvements to error handling, return types, and removed unused imports for better code clarity and consistency. * Refactor type definitions and payload schemas in actions Standardized type usage and improved type safety across multiple OneBot action files. Updated payload schemas to use string types for IDs and flags, refined return types, and enhanced message content typing. Added error handling for missing parameters in SetGroupTodo. * Refactor type handling and improve message parsing Updated several actions to use more precise type casting and type guards, improving type safety and clarity. Enhanced message parsing logic for forward messages and group/friend message history. Standardized return schemas and error handling for avatar and group portrait actions. * Add napcat-schema package for OpenAPI generation Introduces the napcat-schema package with scripts and configuration to auto-generate OpenAPI schemas for NapCat OneBot 11 actions. Refactors action handler export in napcat-onebot to support schema extraction. * Add action examples and enhance action metadata Introduced a centralized examples.ts file providing payload and return examples for all actions. Updated numerous action classes to include actionDescription, actionTags, payloadExample, and returnExample fields, improving API documentation and discoverability. * Refactor action example imports and add example files Moved action example data to dedicated 'examples.ts' files for each action category (extends, file, go-cqhttp, group, msg, system, user). Updated all action classes to import and use the new example modules, improving code organization and maintainability. Also added missing actionTags and actionDescription where appropriate. * Update GetGroupMemberList.ts * Add actionSummary and improve action metadata Introduces the actionSummary property to OneBotAction and updates all action classes to provide concise summaries and improved descriptions. Refactors example imports for better modularity, adds new example files for guild and packet actions, and updates the OpenAPI schema generator to use the new summary and improved descriptions. This enhances API documentation clarity and consistency. * Enhance action metadata and add examples for new actions Added actionSummary, actionDescription, and actionTags to multiple OneBot actions for improved API documentation. Introduced payload and response examples for new actions (GetDoubtFriendsAddRequest, SetDoubtFriendsAddRequest) in a new examples.ts file. Also removed unused imports from several files for code clarity. * Refactor action examples and enhance metadata Replaced generic ActionExamples imports with more specific examples modules (FileActionsExamples, GroupActionsExamples, GoCQHTTPActionsExamples) across file, group, and go-cqhttp actions. Added or updated actionSummary, actionDescription, actionTags, payloadExample, and returnExample properties for improved API documentation and clarity. * Refactor extends actions to use new examples module Replaced imports of ActionExamples with ExtendsActionsExamples in all extends actions. Updated action summary, description, tags, and example references for consistency and clarity across actions. This improves maintainability and aligns with the new examples structure. * Add action metadata to OneBot action classes Added or updated actionSummary, actionTags, payloadExample, and returnExample properties for all OneBot action classes in the napcat-onebot package. This improves API documentation and discoverability by providing concise summaries, categorization tags, and usage examples for each action. * Refactor OpenAPI schema generation to 3.0.1 format Updated the OpenAPI schema output to use version 3.0.1, restructured tags, responses, and examples for better clarity and compatibility, and simplified output file locations. Also removed unused scripts from package.json. * Fix SendPokePayloadSchema type definitions Corrected the type definitions for user_id and target_id to only allow strings, and fixed a syntax error in group_id. This ensures payload validation is consistent and accurate. Refactor fileset ID API response and schema handling Updated GetFilesetId action to return a structured object with fileset_id and adjusted its return schema accordingly. Improved frontend TypeBox schema parsing to support allOf (intersection) merging and updated API debug component to construct response schemas in a more robust way for object recognition. Refactor OneBot API schema handling to use TypeBox Replaces Zod-based static API schema definitions with dynamic fetching of schemas from the backend using TypeBox. Removes legacy static schema files, updates frontend API debug components to use TypeBox utilities, and adds @sinclair/typebox as a dependency. Backend now exposes a /schemas endpoint for all OneBot actions. Various schema and description fields are updated for clarity and consistency. * Remove OneBot API navigation list component Deleted nav_list.tsx from the onebot/api components, removing the OneBotApiNavList React component and its related logic. This may be part of a refactor or cleanup to eliminate unused or redundant UI code. * Add action tags to OneBot API schema and update tag name Included the 'tags' property in the OneBot API schema for both backend and frontend, allowing actions to be categorized. Also updated the action tag from '群扩展' to '群组扩展' in SetGroupSign for consistency. * Add napcat-types package for unified type exports Introduced the napcat-types package to aggregate and re-export all types, enums, and classes from napcat-core and napcat-onebot. Added external module shims, test files, and configuration for type-only distribution. Updated core and onebot packages to improve export granularity and fixed import paths for better modularity. * Move external-shims.d.ts to files in tsconfig external-shims.d.ts was moved from the include array to the files array in tsconfig.json to ensure it is always included explicitly. This change clarifies the intent and may help with TypeScript's file resolution. Refactor napcat-types package and update plugin deps Refactored napcat-types to provide more accurate shims, added real type dependencies, and improved build/test scripts. Updated napcat-plugin and napcat-plugin-builtin to depend on napcat-types instead of napcat-onebot. Adjusted imports in affected packages to use napcat-types, and updated pnpm-lock.yaml accordingly. Add build and test scripts to napcat-types package Introduced 'build' and 'test' scripts in the napcat-types package.json for easier development and testing. Also updated dependencies in the lockfile. * 完善部分api描述 * Remove unused statusText constant Deleted the unused statusText constant from FetchCustomFace.ts to clean up the code. * Bump napcat-types version to 0.0.2 Updated the package version in package.public.json from 0.0.1 to 0.0.2. Update napcat-types package metadata and dependencies Set package as public by changing 'private' to false. Move 'napcat-core' and 'napcat-onebot' from dependencies to devDependencies, and remove 'compressing' from dependencies. Add public packaging and build script for napcat-types Introduces package.public.json and a copy-dist.mjs script to automate copying metadata and README into the dist folder for publishing. Updates build script in package.json to use the new copy step. Adds initial package.json and README for napcat-types. Update scripts in napcat-types package configs Added a publish script to package.json and removed scripts from package.public.json to streamline configuration and avoid duplication. * Update publish script to use npm in dist directory Changed the publish script to run 'npm publish' from the 'dist' directory instead of using 'pnpm publish --filter napcat-types'. This ensures the published package uses the built output. * Update pnpm-lock.yaml dependencies Removed 'compressing' from dependencies and cleaned up libc fields for various platform-specific packages. This streamlines the lock file and may improve cross-platform compatibility. * Add workflow to publish OpenAPI schema to NapCatDocs Introduces a new 'publish-schema' job in the auto-release workflow. This job builds the napcat-schema package, copies the generated OpenAPI schema to the NapCatDocs repository under a versioned path, and commits the update. Automates schema publishing on release events. * AI修正部分api文档 * Update OpenAPI version and use dynamic version from napcat-common Changed OpenAPI spec version to 3.1.0 and replaced the hardcoded API version with napCatVersion from napcat-common. Added napcat-common as a dependency in package.json. * Update napcat-schema build and OpenAPI version Renamed the build script from build:schema to build:openapi in napcat-schema and updated the workflow to use the new script. Changed OpenAPI version from 3.1.0 to 3.0.1 in the schema generator. Added napcat-vite as a dependency and integrated its version plugin into the Vite config. * 暂时OK * Refactor action examples structure and imports Moved action example files into a new 'example' directory and updated all imports accordingly. Removed the monolithic 'examples.ts' and redefined ActionExamples in OneBotAction.ts to only include common error codes. This improves code organization and maintainability. * Fix type for rate limiter middleware in router Casts the rate limiter middleware to RequestHandler to resolve type compatibility issues with Express router middleware. * Add OB11 message segment schemas and update SendMsg Introduces a comprehensive message segment schema (OB11) in a new file, refactors SendMsg payload to use the new OB11MessageMixTypeSchema, and updates related type definitions for improved type safety and extensibility in message handling. * Refactor OB11 message types to use TypeBox schemas Migrates all OB11 message segment and message type definitions from interface/enums to TypeBox schemas in types/message.ts. Removes the now-redundant message-segment-schema.ts file and updates imports to use the new schema-based types. This unifies type validation and TypeScript types, improving maintainability and consistency. --------- Co-authored-by: pohgxz --- .github/workflows/auto-release.yml | 57 + package/package.json | 24 + packages/napcat-core/apis/online.ts | 13 +- packages/napcat-core/index.ts | 6 + packages/napcat-core/types/index.ts | 4 + packages/napcat-core/types/msg.ts | 2 +- packages/napcat-onebot/action/OneBotAction.ts | 24 +- .../action/example/ExtendsActionsExamples.ts | 45 + .../action/example/FileActionsExamples.ts | 22 + .../action/example/GoCQHTTPActionsExamples.ts | 102 ++ .../action/example/GroupActionsExamples.ts | 79 ++ .../action/example/GuildActionsExamples.ts | 10 + .../action/example/NewActionsExamples.ts | 10 + .../action/example/PacketActionsExamples.ts | 14 + .../action/example/SystemActionsExamples.ts | 42 + .../action/example/UserActionsExamples.ts | 38 + .../napcat-onebot/action/extends/BotExit.ts | 7 + .../extends/ClickInlineKeyboardButton.ts | 37 +- .../action/extends/CreateCollection.ts | 29 +- .../action/extends/DelGroupAlbumMedia.ts | 31 +- .../action/extends/DoGroupAlbumComment.ts | 30 +- .../action/extends/FetchCustomFace.ts | 26 +- .../action/extends/FetchEmojiLike.ts | 63 +- .../action/extends/GetAiCharacters.ts | 50 +- .../action/extends/GetClientkey.ts | 20 +- .../action/extends/GetCollectionList.ts | 77 +- .../action/extends/GetEmojiLikes.ts | 15 + .../action/extends/GetFriendWithCategory.ts | 32 +- .../action/extends/GetGroupAddRequest.ts | 43 +- .../action/extends/GetGroupAlbumMediaList.ts | 32 +- .../action/extends/GetGroupInfoEx.ts | 25 +- .../action/extends/GetMiniAppArk.ts | 96 +- .../action/extends/GetProfileLike.ts | 79 +- .../action/extends/GetQunAlbumList.ts | 33 +- .../napcat-onebot/action/extends/GetRkey.ts | 18 +- .../action/extends/GetRobotUinRange.ts | 15 +- .../extends/GetUnidirectionalFriendList.ts | 57 +- .../action/extends/GetUserStatus.ts | 35 +- .../action/extends/MoveGroupFile.ts | 38 +- .../napcat-onebot/action/extends/OCRImage.ts | 27 +- .../action/extends/RenameGroupFile.ts | 38 +- .../action/extends/SendPacket.ts | 33 +- .../action/extends/SetDiyOnlineStatus.ts | 30 +- .../action/extends/SetGroupAddOption.ts | 30 +- .../action/extends/SetGroupAlbumMediaLike.ts | 36 +- .../action/extends/SetGroupKickMembers.ts | 28 +- .../action/extends/SetGroupRemark.ts | 28 +- .../action/extends/SetGroupRobotAddOption.ts | 27 +- .../action/extends/SetGroupSearch.ts | 27 +- .../action/extends/SetGroupSign.ts | 23 +- .../action/extends/SetInputStatus.ts | 27 +- .../action/extends/SetLongNick.ts | 24 +- .../action/extends/SetOnlineStatus.ts | 243 ++++- .../action/extends/SetQQAvatar.ts | 27 +- .../action/extends/SetSpecialTitle.ts | 28 +- .../action/extends/ShareContact.ts | 59 +- .../action/extends/TransGroupFile.ts | 32 +- .../action/extends/TranslateEnWordToZn.ts | 30 +- .../action/extends/UploadImageToQunAlbum.ts | 34 +- packages/napcat-onebot/action/file/GetFile.ts | 39 +- .../action/file/GetGroupFileUrl.ts | 30 +- .../napcat-onebot/action/file/GetImage.ts | 7 + .../action/file/GetPrivateFileUrl.ts | 28 +- .../napcat-onebot/action/file/GetRecord.ts | 27 +- .../action/file/flash/CreateFlashTask.ts | 29 +- .../action/file/flash/DownloadFileset.ts | 19 +- .../action/file/flash/GetFilesetIdByCode.ts | 26 +- .../action/file/flash/GetFilesetInfo.ts | 22 +- .../action/file/flash/GetFlashFileList.ts | 24 +- .../action/file/flash/GetFlashFileUrl.ts | 25 +- .../action/file/flash/GetShareLink.ts | 19 +- .../action/file/flash/SendFlashMsg.ts | 26 +- .../action/file/online/CancelOnlineFile.ts | 22 +- .../file/online/GetOnlineFileMessages.ts | 19 +- .../action/file/online/ReceiveOnlineFile.ts | 25 +- .../action/file/online/RefuseOnlineFile.ts | 24 +- .../action/file/online/SendOnlineFile.ts | 25 +- .../action/file/online/SendOnlineFolder.ts | 24 +- .../action/go-cqhttp/CreateGroupFileFolder.ts | 41 +- .../action/go-cqhttp/DeleteGroupFile.ts | 27 +- .../action/go-cqhttp/DeleteGroupFileFolder.ts | 29 +- .../action/go-cqhttp/DownloadFile.ts | 37 +- .../action/go-cqhttp/GetForwardMsg.ts | 66 +- .../action/go-cqhttp/GetFriendMsgHistory.ts | 44 +- .../action/go-cqhttp/GetGroupAtAllRemain.ts | 35 +- .../go-cqhttp/GetGroupFileSystemInfo.ts | 33 +- .../action/go-cqhttp/GetGroupFilesByFolder.ts | 43 +- .../action/go-cqhttp/GetGroupHonorInfo.ts | 41 +- .../action/go-cqhttp/GetGroupMsgHistory.ts | 45 +- .../action/go-cqhttp/GetGroupRootFiles.ts | 33 +- .../action/go-cqhttp/GetOnlineClient.ts | 20 +- .../action/go-cqhttp/GetStrangerInfo.ts | 54 +- .../go-cqhttp/GoCQHTTPCheckUrlSafely.ts | 23 +- .../action/go-cqhttp/GoCQHTTPDeleteFriend.ts | 25 +- .../action/go-cqhttp/GoCQHTTPGetModelShow.ts | 33 +- .../action/go-cqhttp/GoCQHTTPSetModelShow.ts | 10 + .../action/go-cqhttp/QuickAction.ts | 72 +- .../action/go-cqhttp/SendForwardMsg.ts | 42 +- .../action/go-cqhttp/SendGroupNotice.ts | 35 +- .../action/go-cqhttp/SetGroupPortrait.ts | 39 +- .../action/go-cqhttp/SetQQProfile.ts | 24 +- .../action/go-cqhttp/UploadGroupFile.ts | 37 +- .../action/go-cqhttp/UploadPrivateFile.ts | 35 +- .../action/group/DelEssenceMsg.ts | 35 +- .../action/group/DelGroupNotice.ts | 26 +- .../napcat-onebot/action/group/GetAiRecord.ts | 30 +- .../action/group/GetGroupDetailInfo.ts | 31 +- .../action/group/GetGroupEssence.ts | 59 +- .../action/group/GetGroupIgnoredNotifies.ts | 35 +- .../action/group/GetGroupInfo.ts | 26 +- .../action/group/GetGroupList.ts | 25 +- .../action/group/GetGroupMemberInfo.ts | 32 +- .../action/group/GetGroupMemberList.ts | 26 +- .../action/group/GetGroupNotice.ts | 66 +- .../action/group/GetGroupShutList.ts | 30 +- .../action/group/SendGroupAiRecord.ts | 34 +- .../action/group/SendGroupMsg.ts | 14 +- .../action/group/SetEssenceMsg.ts | 24 +- .../action/group/SetGroupAddRequest.ts | 30 +- .../action/group/SetGroupAdmin.ts | 28 +- .../napcat-onebot/action/group/SetGroupBan.ts | 29 +- .../action/group/SetGroupCard.ts | 28 +- .../action/group/SetGroupKick.ts | 28 +- .../action/group/SetGroupLeave.ts | 27 +- .../action/group/SetGroupName.ts | 26 +- .../action/group/SetGroupWholeBan.ts | 26 +- .../action/guild/GetGuildList.ts | 10 + .../action/guild/GetGuildProfile.ts | 10 + packages/napcat-onebot/action/index.ts | 6 +- .../napcat-onebot/action/msg/DeleteMsg.ts | 25 +- .../action/msg/ForwardSingleMsg.ts | 35 +- packages/napcat-onebot/action/msg/GetMsg.ts | 44 +- .../napcat-onebot/action/msg/MarkMsgAsRead.ts | 43 +- packages/napcat-onebot/action/msg/SendMsg.ts | 87 +- .../action/msg/SendPrivateMsg.ts | 17 +- .../action/msg/SetMsgEmojiLike.ts | 31 +- packages/napcat-onebot/action/msg/examples.ts | 33 + .../action/new/GetDoubtFriendsAddRequest.ts | 19 +- .../action/new/SetDoubtFriendsAddRequest.ts | 23 +- .../action/packet/GetPacketStatus.ts | 10 +- .../napcat-onebot/action/packet/GetRkeyEx.ts | 29 +- .../action/packet/GetRkeyServer.ts | 30 +- .../napcat-onebot/action/packet/SendPoke.ts | 28 +- .../action/packet/SetGroupTodo.ts | 34 +- packages/napcat-onebot/action/schemas.ts | 98 ++ .../action/stream/CleanStreamTempFile.ts | 9 + .../action/stream/DownloadFileImageStream.ts | 25 +- .../action/stream/DownloadFileRecordStream.ts | 27 +- .../action/stream/DownloadFileStream.ts | 29 +- .../action/stream/TestStreamDownload.ts | 21 +- .../action/stream/UploadFileStream.ts | 54 +- .../action/system/CanSendImage.ts | 5 + .../action/system/CanSendRecord.ts | 22 +- .../napcat-onebot/action/system/CleanCache.ts | 8 + .../napcat-onebot/action/system/GetCSRF.ts | 18 +- .../action/system/GetCredentials.ts | 35 +- .../action/system/GetLoginInfo.ts | 12 +- .../napcat-onebot/action/system/GetStatus.ts | 29 +- .../action/system/GetSystemMsg.ts | 50 +- .../action/system/GetVersionInfo.ts | 31 +- .../napcat-onebot/action/system/SetRestart.ts | 8 + .../action/test/TestAutoRegister01.ts | 3 + .../action/test/TestAutoRegister02.ts | 3 + .../napcat-onebot/action/user/GetCookies.ts | 34 +- .../action/user/GetFriendList.ts | 25 +- .../action/user/GetRecentContact.ts | 62 +- .../napcat-onebot/action/user/SendLike.ts | 28 +- .../action/user/SetFriendAddRequest.ts | 27 +- .../action/user/SetFriendRemark.ts | 30 +- packages/napcat-onebot/api/index.ts | 1 + packages/napcat-onebot/config/index.ts | 2 + packages/napcat-onebot/event/index.ts | 5 + packages/napcat-onebot/event/message/index.ts | 1 + packages/napcat-onebot/event/meta/index.ts | 3 + packages/napcat-onebot/event/notice/index.ts | 23 + packages/napcat-onebot/event/request/index.ts | 3 + packages/napcat-onebot/index.ts | 5 +- packages/napcat-onebot/types/message.ts | 664 +++++++----- packages/napcat-plugin-builtin/index.ts | 8 +- packages/napcat-plugin-builtin/package.json | 2 +- packages/napcat-plugin/index.ts | 6 +- packages/napcat-plugin/package.json | 2 +- packages/napcat-schema/index.ts | 219 ++++ packages/napcat-schema/package.json | 20 + packages/napcat-schema/tsconfig.json | 11 + packages/napcat-schema/vite.config.ts | 47 + packages/napcat-types/README.md | 3 + packages/napcat-types/external-shims.d.ts | 178 ++++ packages/napcat-types/index.ts | 9 + packages/napcat-types/package.json | 30 + packages/napcat-types/package.public.json | 25 + packages/napcat-types/scripts/copy-dist.mjs | 13 + packages/napcat-types/test-dist.ts | 38 + packages/napcat-types/test-export.ts | 20 + packages/napcat-types/tsconfig.json | 49 + .../napcat-webui-backend/src/api/Debug.ts | 36 + .../napcat-webui-backend/src/router/File.ts | 4 +- packages/napcat-webui-frontend/package.json | 1 + .../src/components/onebot/api/debug.tsx | 25 +- .../src/components/onebot/api/nav_list.tsx | 182 ---- .../src/const/ob_api/group.ts | 744 ------------- .../src/const/ob_api/index.ts | 58 +- .../src/const/ob_api/message/group.ts | 84 -- .../src/const/ob_api/message/index.ts | 290 ----- .../src/const/ob_api/message/node.ts | 120 --- .../src/const/ob_api/message/private.ts | 80 -- .../src/const/ob_api/online_status.ts | 335 ------ .../src/const/ob_api/response.ts | 16 - .../src/const/ob_api/system.ts | 366 ------- .../src/const/ob_api/user.ts | 278 ----- .../src/pages/dashboard/debug/http/index.tsx | 56 +- .../src/utils/typebox.ts | 123 +++ pnpm-lock.yaml | 997 +++++++++++++----- 213 files changed, 6303 insertions(+), 4395 deletions(-) create mode 100644 package/package.json create mode 100644 packages/napcat-onebot/action/example/ExtendsActionsExamples.ts create mode 100644 packages/napcat-onebot/action/example/FileActionsExamples.ts create mode 100644 packages/napcat-onebot/action/example/GoCQHTTPActionsExamples.ts create mode 100644 packages/napcat-onebot/action/example/GroupActionsExamples.ts create mode 100644 packages/napcat-onebot/action/example/GuildActionsExamples.ts create mode 100644 packages/napcat-onebot/action/example/NewActionsExamples.ts create mode 100644 packages/napcat-onebot/action/example/PacketActionsExamples.ts create mode 100644 packages/napcat-onebot/action/example/SystemActionsExamples.ts create mode 100644 packages/napcat-onebot/action/example/UserActionsExamples.ts create mode 100644 packages/napcat-onebot/action/msg/examples.ts create mode 100644 packages/napcat-onebot/action/schemas.ts create mode 100644 packages/napcat-onebot/event/index.ts create mode 100644 packages/napcat-onebot/event/message/index.ts create mode 100644 packages/napcat-onebot/event/meta/index.ts create mode 100644 packages/napcat-onebot/event/notice/index.ts create mode 100644 packages/napcat-onebot/event/request/index.ts create mode 100644 packages/napcat-schema/index.ts create mode 100644 packages/napcat-schema/package.json create mode 100644 packages/napcat-schema/tsconfig.json create mode 100644 packages/napcat-schema/vite.config.ts create mode 100644 packages/napcat-types/README.md create mode 100644 packages/napcat-types/external-shims.d.ts create mode 100644 packages/napcat-types/index.ts create mode 100644 packages/napcat-types/package.json create mode 100644 packages/napcat-types/package.public.json create mode 100644 packages/napcat-types/scripts/copy-dist.mjs create mode 100644 packages/napcat-types/test-dist.ts create mode 100644 packages/napcat-types/test-export.ts create mode 100644 packages/napcat-types/tsconfig.json delete mode 100644 packages/napcat-webui-frontend/src/components/onebot/api/nav_list.tsx delete mode 100644 packages/napcat-webui-frontend/src/const/ob_api/group.ts delete mode 100644 packages/napcat-webui-frontend/src/const/ob_api/message/group.ts delete mode 100644 packages/napcat-webui-frontend/src/const/ob_api/message/index.ts delete mode 100644 packages/napcat-webui-frontend/src/const/ob_api/message/node.ts delete mode 100644 packages/napcat-webui-frontend/src/const/ob_api/message/private.ts delete mode 100644 packages/napcat-webui-frontend/src/const/ob_api/online_status.ts delete mode 100644 packages/napcat-webui-frontend/src/const/ob_api/response.ts delete mode 100644 packages/napcat-webui-frontend/src/const/ob_api/system.ts delete mode 100644 packages/napcat-webui-frontend/src/const/ob_api/user.ts create mode 100644 packages/napcat-webui-frontend/src/utils/typebox.ts 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: