NapCatQQ/packages/napcat-onebot/action/go-cqhttp/UploadPrivateFile.ts
手瓜一十雪 819224b788 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.
2026-01-25 20:24:30 +08:00

74 lines
3.5 KiB
TypeScript

import { OneBotAction } from '@/napcat-onebot/action/OneBotAction';
import { ActionName } from '@/napcat-onebot/action/router';
import { ChatType, Peer, SendFileElement, ElementType } from 'napcat-core/types';
import fs from 'fs';
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 './examples';
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: '是否执行上传' }),
});
export type GoCQHTTPUploadPrivateFilePayload = Static<typeof GoCQHTTPUploadPrivateFilePayloadSchema>;
export const GoCQHTTPUploadPrivateFileReturnSchema = Type.Object({
file_id: Type.Union([Type.String(), Type.Null()], { description: '文件 ID' }),
});
export type GoCQHTTPUploadPrivateFileResponse = Static<typeof GoCQHTTPUploadPrivateFileReturnSchema>;
export default class GoCQHTTPUploadPrivateFile extends OneBotAction<GoCQHTTPUploadPrivateFilePayload, GoCQHTTPUploadPrivateFileResponse> {
override actionName = ActionName.GOCQHTTP_UploadPrivateFile;
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: GoCQHTTPUploadPrivateFilePayload): Promise<Peer> {
if (payload.user_id) {
const peerUid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
if (!peerUid) {
throw new Error(`私聊${payload.user_id}不存在`);
}
const isBuddy = await this.core.apis.FriendApi.isBuddy(peerUid);
return { chatType: isBuddy ? ChatType.KCHATTYPEC2C : ChatType.KCHATTYPETEMPC2CFROMGROUP, peerUid };
}
throw new Error('缺少参数 user_id');
}
async _handle (payload: GoCQHTTPUploadPrivateFilePayload): Promise<GoCQHTTPUploadPrivateFileResponse> {
let file = payload.file;
if (fs.existsSync(file)) {
file = `file://${file}`;
}
const downloadResult = await uriToLocalFile(this.core.NapCatTempPath, file);
if (!downloadResult.success) {
throw new Error(downloadResult.errMsg);
}
const msgContext: SendMessageContext = {
peer: await createContext(this.core, {
user_id: payload.user_id.toString(),
}, ContextMode.Private),
deleteAfterSentFiles: [],
};
const sendFileEle: SendFileElement = await this.obContext.apis.FileApi.createValidSendFileElement(msgContext, downloadResult.path, payload.name, '', payload.upload_file);
msgContext.deleteAfterSentFiles.push(downloadResult.path);
const returnMsg = await this.obContext.apis.MsgApi.sendMsgWithOb11UniqueId(await this.getPeer(payload), [sendFileEle], msgContext.deleteAfterSentFiles);
const fileElement = returnMsg.elements.find(ele => ele.elementType === ElementType.FILE);
return {
file_id: fileElement?.fileElement?.fileUuid || null,
};
}
}