UNPKG

mira-app-server

Version:

Mira Server - standalone server application using mira-app-core

243 lines 9.62 kB
"use strict"; /** * 文件模块命令 * * 注意:SDK 的 upload 使用 FormData/Blob。Node 18+ 已内置全局 FormData、File、Blob, * 因此可直接复用 SDK 的 uploadFiles,仅需用 Blob 包装读取出的 Buffer。 */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.registerFiles = registerFiles; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const client_1 = require("../client"); const format_1 = require("../format"); /** * 读取本地文件并构造为全局 File 对象(Node 18+ 内置) */ function readFileAsFile(filePath) { const abs = path_1.default.resolve(filePath); if (!fs_1.default.existsSync(abs)) { throw new Error(`文件不存在: ${abs}`); } const buffer = fs_1.default.readFileSync(abs); const blob = new Blob([new Uint8Array(buffer)]); const name = path_1.default.basename(abs); // File 构造签名: new File(bits, name) return new File([blob], name); } /** * 兼容 Node 环境的文件上传。 * * 注意:SDK 的 FileModule.uploadFiles 在判断 `files instanceof FileList` 时, * 会因 Node 中未定义 FileList 而抛出 ReferenceError。因此这里直接构造 * FormData 并通过 HttpClient.upload 发起上传,绕过该问题。 */ async function uploadFilesToLibrary(client, libraryId, paths, options) { const formData = new FormData(); paths.forEach(p => { const file = readFileAsFile(p); formData.append('files', file, file.name); }); formData.append('libraryId', libraryId); if (options.tags && options.tags.length) { formData.append('payload', JSON.stringify({ data: { tags: options.tags } })); } if (options.folderId) { formData.append('payload', JSON.stringify({ data: { folder_id: options.folderId } })); } return await client.getHttpClient().upload('/api/files/upload', formData); } function registerFiles(program) { const files = program.command('files').description('文件管理'); files .command('list <libraryId>') .description('获取文件列表') .option('--title <title>', '按标题模糊搜索') .option('--ext <extension>', '按扩展名筛选') .option('--tag <tag>', '按标签筛选(可多次)', collect, []) .option('--folder-id <id>', '按文件夹 ID 筛选') .option('--limit <n>', '数量限制', parseInt) .option('--offset <n>', '偏移量', parseInt) .action(async (libraryId, options) => { try { const { client } = (0, client_1.getClient)(); const filters = {}; if (options.title) filters.title = options.title; if (options.ext) filters.extension = options.ext; if (options.tag && options.tag.length) filters.tags = options.tag; if (options.folderId) filters.folder = parseInt(options.folderId); if (options.limit) filters.limit = options.limit; if (options.offset) filters.offset = options.offset; // 服务器返回 { result, limit, offset, total } const resp = await client.files().getFiles({ libraryId, filters }); const list = Array.isArray(resp) ? resp : resp?.result || []; const rows = list.map(f => ({ id: f.id, title: f.title || f.name, extension: f.extension, size: f.size, tags: f.tags || '', folder_id: f.folder_id, })); (0, format_1.output)(rows, () => (0, format_1.formatTable)(rows)); } catch (error) { (0, format_1.fatal)(error); } }); files .command('get <libraryId> <fileId>') .description('获取单个文件信息') .action(async (libraryId, fileId) => { try { const { client } = (0, client_1.getClient)(); const info = await client.files().getFile(libraryId, fileId); (0, format_1.output)(info, () => (0, format_1.formatKeyValue)(info)); } catch (error) { (0, format_1.fatal)(error); } }); files .command('upload <libraryId> <paths...>') .description('上传文件到指定素材库') .option('--tag <tag>', '添加标签(可多次)', collect, []) .option('--folder-id <id>', '目标文件夹 ID') .action(async (libraryId, paths, options) => { try { const { client } = (0, client_1.getClient)(); const opts = {}; if (options.tag && options.tag.length) opts.tags = options.tag; if (options.folderId) opts.folderId = options.folderId; const res = await uploadFilesToLibrary(client, libraryId, paths, opts); (0, format_1.success)(`已上传 ${paths.length} 个文件到 ${libraryId}`); (0, format_1.output)(res); } catch (error) { (0, format_1.fatal)(error); } }); files .command('download <libraryId> <fileId>') .description('下载文件到本地') .option('-o, --output <path>', '保存路径(默认当前目录,使用文件原名)') .action(async (libraryId, fileId, options) => { try { const { client } = (0, client_1.getClient)(); const blob = await client.files().download(libraryId, fileId); const buffer = Buffer.from(await blob.arrayBuffer()); let outPath = options.output; if (!outPath) { try { const info = await client.files().getFile(libraryId, fileId); outPath = path_1.default.resolve(process.cwd(), info.title || fileId); } catch { outPath = path_1.default.resolve(process.cwd(), String(fileId)); } } fs_1.default.writeFileSync(outPath, buffer); (0, format_1.success)(`已下载到: ${outPath} (${buffer.length} bytes)`); } catch (error) { (0, format_1.fatal)(error); } }); files .command('rename <libraryId> <fileId> <name>') .description('重命名文件') .action(async (libraryId, fileId, name) => { try { const { client } = (0, client_1.getClient)(); const res = await client.files().renameFile(libraryId, fileId, name); (0, format_1.success)(`文件已重命名为: ${name}`); (0, format_1.output)(res); } catch (error) { (0, format_1.fatal)(error); } }); files .command('update <libraryId> <fileId> <json>') .description('更新文件元数据(json 为 JSON 字符串)') .action(async (libraryId, fileId, json) => { try { let data; try { data = JSON.parse(json); } catch { throw new Error('json 参数不是合法的 JSON'); } const { client } = (0, client_1.getClient)(); const res = await client.files().updateFile(libraryId, fileId, data); (0, format_1.success)(`文件 ${fileId} 已更新`); (0, format_1.output)(res); } catch (error) { (0, format_1.fatal)(error); } }); files .command('delete <libraryId> <fileId>') .alias('rm') .description('删除文件(默认进回收站)') .option('--permanent', '彻底删除(不进回收站)') .action(async (libraryId, fileId, options) => { try { const { client } = (0, client_1.getClient)(); const res = await client.files().delete(libraryId, fileId, { moveToRecycleBin: !options.permanent, }); (0, format_1.success)(options.permanent ? `文件 ${fileId} 已彻底删除` : `文件 ${fileId} 已移入回收站`); (0, format_1.output)(res); } catch (error) { (0, format_1.fatal)(error); } }); files .command('restore <libraryId> <fileId>') .description('从回收站恢复文件') .action(async (libraryId, fileId) => { try { const { client } = (0, client_1.getClient)(); const res = await client.files().restoreFile(libraryId, fileId); (0, format_1.success)(`文件 ${fileId} 已恢复`); (0, format_1.output)(res); } catch (error) { (0, format_1.fatal)(error); } }); files .command('empty-trash <libraryId>') .description('清空素材库回收站') .action(async (libraryId) => { try { const { client } = (0, client_1.getClient)(); const res = await client.files().emptyTrash(libraryId); (0, format_1.success)(`素材库 ${libraryId} 回收站已清空`); (0, format_1.output)(res); } catch (error) { (0, format_1.fatal)(error); } }); } /** commander collect 辅助:收集多次出现的选项 */ function collect(value, previous) { return previous.concat([value]); } //# sourceMappingURL=files.js.map