sa2kit 1.6.60 → 1.6.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/UniversalFileService-C3WQAFOV.js +15 -0
- package/dist/{UniversalFileService-J6ET6KZK.js.map → UniversalFileService-C3WQAFOV.js.map} +1 -1
- package/dist/UniversalFileService-O3IEROBN.mjs +6 -0
- package/dist/{UniversalFileService-336GFY6N.mjs.map → UniversalFileService-O3IEROBN.mjs.map} +1 -1
- package/dist/ai/llm/index.d.mts +70 -0
- package/dist/ai/llm/index.d.ts +70 -0
- package/dist/ai/llm/index.js +54 -0
- package/dist/ai/llm/index.js.map +1 -0
- package/dist/ai/llm/index.mjs +5 -0
- package/dist/ai/llm/index.mjs.map +1 -0
- package/dist/ai/llm/ui/electron/index.d.mts +5 -0
- package/dist/ai/llm/ui/electron/index.d.ts +5 -0
- package/dist/ai/llm/ui/electron/index.js +21 -0
- package/dist/ai/llm/ui/electron/index.js.map +1 -0
- package/dist/ai/llm/ui/electron/index.mjs +8 -0
- package/dist/ai/llm/ui/electron/index.mjs.map +1 -0
- package/dist/ai/llm/ui/miniapp/index.d.mts +9 -0
- package/dist/ai/llm/ui/miniapp/index.d.ts +9 -0
- package/dist/ai/llm/ui/miniapp/index.js +107 -0
- package/dist/ai/llm/ui/miniapp/index.js.map +1 -0
- package/dist/ai/llm/ui/miniapp/index.mjs +101 -0
- package/dist/ai/llm/ui/miniapp/index.mjs.map +1 -0
- package/dist/ai/llm/ui/rn/index.d.mts +9 -0
- package/dist/ai/llm/ui/rn/index.d.ts +9 -0
- package/dist/ai/llm/ui/rn/index.js +249 -0
- package/dist/ai/llm/ui/rn/index.js.map +1 -0
- package/dist/ai/llm/ui/rn/index.mjs +243 -0
- package/dist/ai/llm/ui/rn/index.mjs.map +1 -0
- package/dist/ai/llm/ui/web/index.d.mts +15 -0
- package/dist/ai/llm/ui/web/index.d.ts +15 -0
- package/dist/ai/llm/ui/web/index.js +21 -0
- package/dist/ai/llm/ui/web/index.js.map +1 -0
- package/dist/ai/llm/ui/web/index.mjs +8 -0
- package/dist/ai/llm/ui/web/index.mjs.map +1 -0
- package/dist/ar/index.d.mts +7 -0
- package/dist/ar/index.d.ts +7 -0
- package/dist/ar/index.js +17 -0
- package/dist/ar/index.js.map +1 -0
- package/dist/ar/index.mjs +4 -0
- package/dist/ar/index.mjs.map +1 -0
- package/dist/auth/index.js +22 -22
- package/dist/auth/index.mjs +2 -2
- package/dist/auth/legacy/db/index.d.mts +5 -0
- package/dist/auth/legacy/db/index.d.ts +5 -0
- package/dist/auth/legacy/db/index.js +34 -0
- package/dist/auth/legacy/db/index.js.map +1 -0
- package/dist/auth/legacy/db/index.mjs +5 -0
- package/dist/auth/legacy/db/index.mjs.map +1 -0
- package/dist/auth/legacy/index.d.mts +51 -0
- package/dist/auth/legacy/index.d.ts +51 -0
- package/dist/auth/legacy/index.js +146 -0
- package/dist/auth/legacy/index.js.map +1 -0
- package/dist/auth/legacy/index.mjs +13 -0
- package/dist/auth/legacy/index.mjs.map +1 -0
- package/dist/auth/legacy/logic/index.d.mts +9 -0
- package/dist/auth/legacy/logic/index.d.ts +9 -0
- package/dist/auth/legacy/logic/index.js +18 -0
- package/dist/auth/legacy/logic/index.js.map +1 -0
- package/dist/auth/legacy/logic/index.mjs +5 -0
- package/dist/auth/legacy/logic/index.mjs.map +1 -0
- package/dist/auth/legacy/routes/index.d.mts +50 -0
- package/dist/auth/legacy/routes/index.d.ts +50 -0
- package/dist/auth/legacy/routes/index.js +34 -0
- package/dist/auth/legacy/routes/index.js.map +1 -0
- package/dist/auth/legacy/routes/index.mjs +5 -0
- package/dist/auth/legacy/routes/index.mjs.map +1 -0
- package/dist/auth/legacy/schema/index.d.mts +401 -0
- package/dist/auth/legacy/schema/index.d.ts +401 -0
- package/dist/auth/legacy/schema/index.js +29 -0
- package/dist/auth/legacy/schema/index.js.map +1 -0
- package/dist/auth/legacy/schema/index.mjs +4 -0
- package/dist/auth/legacy/schema/index.mjs.map +1 -0
- package/dist/auth/legacy/server/index.d.mts +15 -0
- package/dist/auth/legacy/server/index.d.ts +15 -0
- package/dist/auth/legacy/server/index.js +65 -0
- package/dist/auth/legacy/server/index.js.map +1 -0
- package/dist/auth/legacy/server/index.mjs +8 -0
- package/dist/auth/legacy/server/index.mjs.map +1 -0
- package/dist/auth/legacy/services/index.d.mts +40 -0
- package/dist/auth/legacy/services/index.d.ts +40 -0
- package/dist/auth/legacy/services/index.js +14 -0
- package/dist/auth/legacy/services/index.js.map +1 -0
- package/dist/auth/legacy/services/index.mjs +5 -0
- package/dist/auth/legacy/services/index.mjs.map +1 -0
- package/dist/auth/legacy/ui/miniapp/index.d.mts +10 -0
- package/dist/auth/legacy/ui/miniapp/index.d.ts +10 -0
- package/dist/auth/legacy/ui/miniapp/index.js +23 -0
- package/dist/auth/legacy/ui/miniapp/index.js.map +1 -0
- package/dist/auth/legacy/ui/miniapp/index.mjs +6 -0
- package/dist/auth/legacy/ui/miniapp/index.mjs.map +1 -0
- package/dist/auth/legacy/ui/web/index.d.mts +22 -0
- package/dist/auth/legacy/ui/web/index.d.ts +22 -0
- package/dist/auth/legacy/ui/web/index.js +31 -0
- package/dist/auth/legacy/ui/web/index.js.map +1 -0
- package/dist/auth/legacy/ui/web/index.mjs +6 -0
- package/dist/auth/legacy/ui/web/index.mjs.map +1 -0
- package/dist/calendar/index.d.mts +390 -237
- package/dist/calendar/index.d.ts +390 -237
- package/dist/calendar/index.js +3825 -3785
- package/dist/calendar/index.js.map +1 -1
- package/dist/calendar/index.mjs +3730 -3696
- package/dist/calendar/index.mjs.map +1 -1
- package/dist/calendar/routes/index.js +30 -327
- package/dist/calendar/routes/index.js.map +1 -1
- package/dist/calendar/routes/index.mjs +1 -323
- package/dist/calendar/routes/index.mjs.map +1 -1
- package/dist/calendar/server.d.mts +6 -0
- package/dist/calendar/server.d.ts +6 -0
- package/dist/calendar/server.js +41 -13
- package/dist/calendar/server.js.map +1 -1
- package/dist/calendar/server.mjs +2 -2
- package/dist/calendar/server.mjs.map +1 -1
- package/dist/chunk-24F7KUED.js +263 -0
- package/dist/chunk-24F7KUED.js.map +1 -0
- package/dist/{chunk-YMS6BPXS.js → chunk-27IUMDDK.js} +3 -3
- package/dist/{chunk-YMS6BPXS.js.map → chunk-27IUMDDK.js.map} +1 -1
- package/dist/chunk-37M6NZIF.js +279 -0
- package/dist/chunk-37M6NZIF.js.map +1 -0
- package/dist/chunk-3JMUNOUT.js +144 -0
- package/dist/chunk-3JMUNOUT.js.map +1 -0
- package/dist/chunk-3PFCOTJP.mjs +256 -0
- package/dist/chunk-3PFCOTJP.mjs.map +1 -0
- package/dist/{chunk-NZZZUMMX.mjs → chunk-57MVE5LL.mjs} +3 -3
- package/dist/{chunk-NZZZUMMX.mjs.map → chunk-57MVE5LL.mjs.map} +1 -1
- package/dist/{chunk-622Y6LTH.mjs → chunk-5BLZEVWK.mjs} +196 -468
- package/dist/chunk-5BLZEVWK.mjs.map +1 -0
- package/dist/{chunk-YN4MJFIG.js → chunk-5LCGOCKG.js} +5 -5
- package/dist/{chunk-YN4MJFIG.js.map → chunk-5LCGOCKG.js.map} +1 -1
- package/dist/chunk-6XUQ2B4K.js +219 -0
- package/dist/chunk-6XUQ2B4K.js.map +1 -0
- package/dist/{chunk-NCOXT7SK.js → chunk-77UEPWVQ.js} +4 -4
- package/dist/{chunk-NCOXT7SK.js.map → chunk-77UEPWVQ.js.map} +1 -1
- package/dist/chunk-CFM56MGO.mjs +35 -0
- package/dist/chunk-CFM56MGO.mjs.map +1 -0
- package/dist/chunk-CPSFYP34.mjs +140 -0
- package/dist/chunk-CPSFYP34.mjs.map +1 -0
- package/dist/chunk-D22QBOCM.mjs +336 -0
- package/dist/chunk-D22QBOCM.mjs.map +1 -0
- package/dist/chunk-DA4QV64P.mjs +35 -0
- package/dist/chunk-DA4QV64P.mjs.map +1 -0
- package/dist/chunk-EKDLZND6.js +275 -0
- package/dist/chunk-EKDLZND6.js.map +1 -0
- package/dist/chunk-EKQPFZXQ.js +12 -0
- package/dist/chunk-EKQPFZXQ.js.map +1 -0
- package/dist/chunk-ERAAB5VG.js +324 -0
- package/dist/chunk-ERAAB5VG.js.map +1 -0
- package/dist/chunk-ESLY72VI.mjs +175 -0
- package/dist/chunk-ESLY72VI.mjs.map +1 -0
- package/dist/chunk-FGQGWW73.js +38 -0
- package/dist/chunk-FGQGWW73.js.map +1 -0
- package/dist/chunk-FXQOXLDE.js +120 -0
- package/dist/chunk-FXQOXLDE.js.map +1 -0
- package/dist/chunk-FZELCJR7.mjs +19 -0
- package/dist/chunk-FZELCJR7.mjs.map +1 -0
- package/dist/{chunk-HHVDOIPV.js → chunk-H3P2PGZL.js} +3 -3
- package/dist/{chunk-HHVDOIPV.js.map → chunk-H3P2PGZL.js.map} +1 -1
- package/dist/chunk-HBQMN5QM.mjs +10 -0
- package/dist/chunk-HBQMN5QM.mjs.map +1 -0
- package/dist/chunk-ITRIXMXF.mjs +862 -0
- package/dist/chunk-ITRIXMXF.mjs.map +1 -0
- package/dist/chunk-IUWSCUDC.js +4 -0
- package/dist/chunk-IUWSCUDC.js.map +1 -0
- package/dist/chunk-JCKCKRC2.js +50 -0
- package/dist/chunk-JCKCKRC2.js.map +1 -0
- package/dist/chunk-L7GQNY54.mjs +286 -0
- package/dist/chunk-L7GQNY54.mjs.map +1 -0
- package/dist/{chunk-ZRWED7Q6.js → chunk-LDVJ7URJ.js} +235 -520
- package/dist/chunk-LDVJ7URJ.js.map +1 -0
- package/dist/{chunk-CYTXGBP2.js → chunk-MLP74E3O.js} +573 -1607
- package/dist/chunk-MLP74E3O.js.map +1 -0
- package/dist/chunk-NAX4TUT7.js +182 -0
- package/dist/chunk-NAX4TUT7.js.map +1 -0
- package/dist/chunk-NW4EN4YI.mjs +213 -0
- package/dist/chunk-NW4EN4YI.mjs.map +1 -0
- package/dist/chunk-P3QMT3AY.mjs +44 -0
- package/dist/chunk-P3QMT3AY.mjs.map +1 -0
- package/dist/chunk-PJ4KYAQZ.mjs +631 -0
- package/dist/chunk-PJ4KYAQZ.mjs.map +1 -0
- package/dist/chunk-PLSEAREM.js +345 -0
- package/dist/chunk-PLSEAREM.js.map +1 -0
- package/dist/{chunk-EGJPS7OL.mjs → chunk-QZU4UJZG.mjs} +3 -3
- package/dist/{chunk-EGJPS7OL.mjs.map → chunk-QZU4UJZG.mjs.map} +1 -1
- package/dist/chunk-RJVR33ME.mjs +3 -0
- package/dist/chunk-RJVR33ME.mjs.map +1 -0
- package/dist/chunk-SYBHDB2D.js +650 -0
- package/dist/chunk-SYBHDB2D.js.map +1 -0
- package/dist/chunk-TVKVM7JT.js +21 -0
- package/dist/chunk-TVKVM7JT.js.map +1 -0
- package/dist/{chunk-PONZPO3U.mjs → chunk-UTB72ZJ7.mjs} +414 -1448
- package/dist/chunk-UTB72ZJ7.mjs.map +1 -0
- package/dist/chunk-V7EVKD5G.mjs +116 -0
- package/dist/chunk-V7EVKD5G.mjs.map +1 -0
- package/dist/chunk-VGPR3KLR.js +872 -0
- package/dist/chunk-VGPR3KLR.js.map +1 -0
- package/dist/chunk-VS7WATQD.js +255 -0
- package/dist/chunk-VS7WATQD.js.map +1 -0
- package/dist/chunk-VSP7XJT5.mjs +272 -0
- package/dist/chunk-VSP7XJT5.mjs.map +1 -0
- package/dist/{chunk-CSDIPQQO.mjs → chunk-VTKAIOP5.mjs} +5 -5
- package/dist/{chunk-CSDIPQQO.mjs.map → chunk-VTKAIOP5.mjs.map} +1 -1
- package/dist/chunk-VULJUXTF.mjs +267 -0
- package/dist/chunk-VULJUXTF.mjs.map +1 -0
- package/dist/chunk-XAHM6B3V.js +44 -0
- package/dist/chunk-XAHM6B3V.js.map +1 -0
- package/dist/chunk-YSF5YISM.mjs +248 -0
- package/dist/chunk-YSF5YISM.mjs.map +1 -0
- package/dist/{chunk-OFYBMMWT.mjs → chunk-YYJEVAJI.mjs} +3 -3
- package/dist/{chunk-OFYBMMWT.mjs.map → chunk-YYJEVAJI.mjs.map} +1 -1
- package/dist/components/index.d.mts +1 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +182 -181
- package/dist/components/index.mjs +4 -3
- package/dist/index-DNKZ7-R_.d.mts +184 -0
- package/dist/index-DNKZ7-R_.d.ts +184 -0
- package/dist/index.d.mts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +285 -229
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +15 -10
- package/dist/index.mjs.map +1 -1
- package/dist/mikuFusionGame/index.js +3 -3
- package/dist/mikuFusionGame/index.mjs +2 -2
- package/dist/mmd/index.d.mts +67 -9
- package/dist/mmd/index.d.ts +67 -9
- package/dist/mmd/index.js +969 -625
- package/dist/mmd/index.js.map +1 -1
- package/dist/mmd/index.mjs +969 -628
- package/dist/mmd/index.mjs.map +1 -1
- package/dist/portfolio/index.js +10 -9
- package/dist/portfolio/index.mjs +5 -4
- package/dist/qqbot/index.d.mts +2 -0
- package/dist/qqbot/index.d.ts +2 -0
- package/dist/qqbot/index.js +21 -0
- package/dist/qqbot/index.js.map +1 -0
- package/dist/qqbot/index.mjs +4 -0
- package/dist/qqbot/index.mjs.map +1 -0
- package/dist/qqbot/server/index.d.mts +91 -0
- package/dist/qqbot/server/index.d.ts +91 -0
- package/dist/qqbot/server/index.js +21 -0
- package/dist/qqbot/server/index.js.map +1 -0
- package/dist/qqbot/server/index.mjs +4 -0
- package/dist/qqbot/server/index.mjs.map +1 -0
- package/dist/qqbot/ui/web/index.d.mts +10 -0
- package/dist/qqbot/ui/web/index.d.ts +10 -0
- package/dist/qqbot/ui/web/index.js +105 -0
- package/dist/qqbot/ui/web/index.js.map +1 -0
- package/dist/qqbot/ui/web/index.mjs +99 -0
- package/dist/qqbot/ui/web/index.mjs.map +1 -0
- package/dist/screenReceiver/index.d.mts +78 -0
- package/dist/screenReceiver/index.d.ts +78 -0
- package/dist/screenReceiver/index.js +17 -0
- package/dist/screenReceiver/index.js.map +1 -0
- package/dist/screenReceiver/index.mjs +4 -0
- package/dist/screenReceiver/index.mjs.map +1 -0
- package/dist/screenReceiver/server/index.d.mts +36 -0
- package/dist/screenReceiver/server/index.d.ts +36 -0
- package/dist/screenReceiver/server/index.js +160 -0
- package/dist/screenReceiver/server/index.js.map +1 -0
- package/dist/screenReceiver/server/index.mjs +157 -0
- package/dist/screenReceiver/server/index.mjs.map +1 -0
- package/dist/showmasterpiece/db/index.js +42 -42
- package/dist/showmasterpiece/db/index.mjs +1 -1
- package/dist/showmasterpiece/index.js +52 -41
- package/dist/showmasterpiece/index.js.map +1 -1
- package/dist/showmasterpiece/index.mjs +15 -4
- package/dist/showmasterpiece/index.mjs.map +1 -1
- package/dist/showmasterpiece/server/index.js +42 -42
- package/dist/showmasterpiece/server/index.mjs +1 -1
- package/dist/showmasterpiece/ui/miniapp/index.d.mts +2 -0
- package/dist/showmasterpiece/ui/miniapp/index.d.ts +2 -0
- package/dist/showmasterpiece/ui/miniapp/index.js +83 -55
- package/dist/showmasterpiece/ui/miniapp/index.js.map +1 -1
- package/dist/showmasterpiece/ui/miniapp/index.mjs +83 -55
- package/dist/showmasterpiece/ui/miniapp/index.mjs.map +1 -1
- package/dist/showmasterpiece/ui/web/index.js +43 -32
- package/dist/showmasterpiece/ui/web/index.mjs +15 -4
- package/dist/testYourself/index.js +13 -13
- package/dist/testYourself/index.mjs +2 -2
- package/dist/types-B-hOccQw.d.mts +122 -0
- package/dist/types-B8rGXc4e.d.mts +38 -0
- package/dist/types-Cg89HGz2.d.ts +38 -0
- package/dist/types-CvKvpyN8.d.mts +48 -0
- package/dist/types-CvKvpyN8.d.ts +48 -0
- package/dist/types-Dy6x2gJW.d.ts +122 -0
- package/dist/universalFile/server/index.js +11 -11
- package/dist/universalFile/server/index.mjs +4 -4
- package/package.json +101 -1
- package/dist/UniversalFileService-336GFY6N.mjs +0 -6
- package/dist/UniversalFileService-J6ET6KZK.js +0 -15
- package/dist/chunk-622Y6LTH.mjs.map +0 -1
- package/dist/chunk-CYTXGBP2.js.map +0 -1
- package/dist/chunk-GVVS4IMM.mjs +0 -302
- package/dist/chunk-GVVS4IMM.mjs.map +0 -1
- package/dist/chunk-PONZPO3U.mjs.map +0 -1
- package/dist/chunk-WC5QFO3T.js +0 -314
- package/dist/chunk-WC5QFO3T.js.map +0 -1
- package/dist/chunk-ZRWED7Q6.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/universalFile/server/utils/mime.ts","../src/universalFile/server/UniversalFileService.ts"],"names":["path","createLogger","EventEmitter","uuidv4","StorageProviderError","FileUploadError","path2","createHash","FileProcessingError"],"mappings":"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","file":"chunk-YMS6BPXS.js","sourcesContent":["/**\n * MIME 类型工具函数\n */\n\nimport * as path from 'path';\n\n/** MIME 类型映射表 */\nconst MIME_TYPES: Record<string, string> = {\n // 图片\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.png': 'image/png',\n '.gif': 'image/gif',\n '.webp': 'image/webp',\n '.svg': 'image/svg+xml',\n '.bmp': 'image/bmp',\n '.ico': 'image/x-icon',\n\n // 视频\n '.mp4': 'video/mp4',\n '.avi': 'video/x-msvideo',\n '.mov': 'video/quicktime',\n '.wmv': 'video/x-ms-wmv',\n '.flv': 'video/x-flv',\n '.mkv': 'video/x-matroska',\n '.webm': 'video/webm',\n\n // 音频\n '.mp3': 'audio/mpeg',\n '.wav': 'audio/wav',\n '.ogg': 'audio/ogg',\n '.m4a': 'audio/mp4',\n '.flac': 'audio/flac',\n '.aac': 'audio/aac',\n\n // 文档\n '.pdf': 'application/pdf',\n '.doc': 'application/msword',\n '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n '.xls': 'application/vnd.ms-excel',\n '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n '.ppt': 'application/vnd.ms-powerpoint',\n '.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n '.txt': 'text/plain',\n '.rtf': 'application/rtf',\n\n // 压缩文件\n '.zip': 'application/zip',\n '.rar': 'application/x-rar-compressed',\n '.7z': 'application/x-7z-compressed',\n '.tar': 'application/x-tar',\n '.gz': 'application/gzip',\n\n // 代码文件\n '.js': 'application/javascript',\n '.json': 'application/json',\n '.xml': 'application/xml',\n '.html': 'text/html',\n '.css': 'text/css',\n '.ts': 'application/typescript',\n\n // 其他\n '.csv': 'text/csv',\n '.md': 'text/markdown',\n};\n\n/**\n * 根据文件名获取 MIME 类型\n *\n * @param filename 文件名\n * @returns MIME 类型\n *\n * @example\n * ```typescript\n * getMimeType('photo.jpg') // 'image/jpeg'\n * getMimeType('video.mp4') // 'video/mp4'\n * getMimeType('unknown.xyz') // 'application/octet-stream'\n * ```\n */\nexport function getMimeType(filename: string): string {\n const ext = path.extname(filename).toLowerCase();\n return MIME_TYPES[ext] || 'application/octet-stream';\n}\n\n/**\n * 根据 MIME 类型获取文件扩展名\n *\n * @param mimeType MIME 类型\n * @returns 文件扩展名(包含点号)\n *\n * @example\n * ```typescript\n * getExtensionFromMimeType('image/jpeg') // '.jpg'\n * getExtensionFromMimeType('video/mp4') // '.mp4'\n * ```\n */\nexport function getExtensionFromMimeType(mimeType: string): string | null {\n for (const [ext, mime] of Object.entries(MIME_TYPES)) {\n if (mime === mimeType) {\n return ext;\n }\n }\n return null;\n}\n\n/**\n * 检查是否为图片类型\n *\n * @param mimeType MIME 类型\n * @returns 是否为图片\n */\nexport function isImageType(mimeType: string): boolean {\n return mimeType.startsWith('image/');\n}\n\n/**\n * 检查是否为视频类型\n *\n * @param mimeType MIME 类型\n * @returns 是否为视频\n */\nexport function isVideoType(mimeType: string): boolean {\n return mimeType.startsWith('video/');\n}\n\n/**\n * 检查是否为音频类型\n *\n * @param mimeType MIME 类型\n * @returns 是否为音频\n */\nexport function isAudioType(mimeType: string): boolean {\n return mimeType.startsWith('audio/');\n}\n\n/**\n * 检查是否为文档类型\n *\n * @param mimeType MIME 类型\n * @returns 是否为文档\n */\nexport function isDocumentType(mimeType: string): boolean {\n const documentTypes = [\n 'application/pdf',\n 'application/msword',\n 'application/vnd.openxmlformats-officedocument',\n 'text/plain',\n 'application/rtf',\n ];\n return documentTypes.some(type => mimeType.includes(type));\n}\n\n/**\n * 验证 MIME 类型是否在允许列表中\n *\n * @param mimeType MIME 类型\n * @param allowedTypes 允许的类型列表(支持通配符)\n * @returns 是否允许\n *\n * @example\n * ```typescript\n * isAllowedMimeType('image/jpeg', ['image/*']) // true\n * isAllowedMimeType('video/mp4', ['image/*']) // false\n * isAllowedMimeType('image/png', ['image/jpeg']) // false\n * ```\n */\nexport function isAllowedMimeType(\n mimeType: string,\n allowedTypes: string[]\n): boolean {\n return allowedTypes.some(allowed => {\n if (allowed === '*/*') {\n return true;\n }\n if (allowed.endsWith('/*')) {\n const prefix = allowed.slice(0, -2);\n return mimeType.startsWith(prefix + '/');\n }\n return mimeType === allowed;\n });\n}\n\n","/**\n * 通用文件服务核心实现\n *\n * 提供统一的文件上传、下载、管理接口\n */\n\nimport { EventEmitter } from 'events';\nimport { v4 as uuidv4 } from 'uuid';\nimport { createHash } from 'crypto';\nimport * as path from 'path';\nimport { createLogger } from '../../logger';\nimport { getMimeType } from './utils/mime';\n\nconst logger = createLogger('UniversalFileService');\n\nimport type {\n StorageType,\n CDNType,\n ProcessorType,\n FileMetadata,\n UploadFileInfo,\n UploadProgress,\n FileQueryOptions,\n PaginatedResult,\n BatchOperationResult,\n FileEvent,\n FileEventListener,\n UploadStatus,\n} from '../types';\n\n// Backend specific types\nimport type {\n UniversalFileServiceConfig,\n IStorageProvider,\n ICDNProvider,\n IFileProcessor,\n} from './types';\n\nimport {\n FileUploadError,\n FileProcessingError,\n StorageProviderError,\n} from '../types';\n\n/**\n * 通用文件服务类\n */\nexport class UniversalFileService extends EventEmitter {\n private config: UniversalFileServiceConfig;\n private storageProviders = new Map<StorageType, IStorageProvider>();\n private cdnProviders = new Map<CDNType, ICDNProvider>();\n private fileProcessors = new Map<ProcessorType, IFileProcessor>();\n private uploadProgressMap = new Map<string, UploadProgress>();\n private metadataCache = new Map<string, { data: FileMetadata; expires: number }>();\n private urlCache = new Map<string, { url: string; expires: number }>();\n private processingQueue: Array<{\n fileId: string;\n processor: IFileProcessor;\n inputPath: string;\n outputPath: string;\n options: any;\n }> = [];\n private isProcessingQueueRunning = false;\n\n constructor(config: UniversalFileServiceConfig) {\n super();\n this.config = config;\n\n // 如果启用了持久化,设置自动监听器\n if (this.config.persistence?.enabled && this.config.persistence.repository) {\n this.setupPersistenceListeners();\n }\n }\n\n // ============= 持久化设置 =============\n\n /**\n * 设置数据库持久化监听器\n *\n * 当文件上传完成或删除时,自动触发数据库操作\n */\n private setupPersistenceListeners(): void {\n const { repository, autoPersist = true } = this.config.persistence!;\n\n if (!autoPersist) {\n logger.info('⚙️ [UniversalFileService] 自动持久化已禁用');\n return;\n }\n\n logger.info('✅ [UniversalFileService] 已启用数据库持久化,自动监听文件事件');\n\n // 监听文件上传完成事件\n this.on('upload:complete', async (fileId: string, data: any) => {\n try {\n const metadata = data.metadata || data;\n await repository.save(metadata);\n logger.info('💾 [Persistence] 文件元数据已自动保存: ' + (fileId));\n } catch (error) {\n logger.error('❌ [Persistence] 保存失败: ' + (fileId), error);\n // 不抛出错误,避免影响上传流程\n }\n });\n\n // 监听文件删除事件\n this.on('file:deleted', async (fileId: string) => {\n try {\n await repository.delete(fileId);\n logger.info('🗑️ [Persistence] 文件元数据已自动删除: ' + (fileId));\n } catch (error) {\n logger.error('❌ [Persistence] 删除失败: ' + (fileId), error);\n }\n });\n\n // 监听批量删除事件\n this.on('files:batch-deleted', async (fileIds: string[]) => {\n try {\n await repository.batchDelete(fileIds);\n logger.info('🗑️ [Persistence] 批量删除元数据: ' + (fileIds.length) + ' 个文件');\n } catch (error) {\n logger.error(`❌ [Persistence] 批量删除失败`, error);\n }\n });\n }\n\n // ============= 初始化方法 =============\n\n /**\n * 初始化文件服务\n */\n async initialize(): Promise<void> {\n logger.info('🚀 [UniversalFileService] 开始初始化文件服务...');\n\n try {\n // 验证配置是否完整\n await this.validateConfiguration();\n\n // 初始化存储提供者\n await this.initializeStorageProviders();\n\n // 初始化CDN提供者\n await this.initializeCDNProviders();\n\n // 初始化文件处理器\n await this.initializeFileProcessors();\n\n logger.info('✅ [UniversalFileService] 文件服务初始化完成');\n } catch (error) {\n console.error('❌ [UniversalFileService] 文件服务初始化失败:', error);\n throw error;\n }\n }\n\n /**\n * 重新初始化存储提供者(支持配置热更新)\n */\n async reinitializeStorageProviders(): Promise<void> {\n logger.info('🔄 [UniversalFileService] 重新初始化存储提供者...');\n\n try {\n // 重新初始化所有存储提供者\n for (const [type, provider] of this.storageProviders) {\n if ('reinitialize' in provider) {\n try {\n logger.info('🔄 [UniversalFileService] 重新初始化存储提供者: ' + (type) + '...');\n\n // 获取对应的配置(从原始配置中获取)\n const config = (this.config as any).storageProviders?.[type as string];\n if (config) {\n await (provider as any).reinitialize(config);\n logger.info('✅ [UniversalFileService] 存储提供者重新初始化完成: ' + (type));\n } else {\n logger.warn('⚠️ [UniversalFileService] 存储提供者配置不存在: ' + (type));\n }\n } catch (error) {\n logger.error('❌ [UniversalFileService] 存储提供者重新初始化失败: ' + (type), error);\n // 继续处理其他提供者\n }\n }\n }\n\n logger.info('✅ [UniversalFileService] 存储提供者重新初始化完成');\n } catch (error) {\n console.error('❌ [UniversalFileService] 存储提供者重新初始化失败:', error);\n throw error;\n }\n }\n\n /**\n * 注册存储提供者\n */\n registerStorageProvider(provider: IStorageProvider): void {\n this.storageProviders.set(provider.type, provider);\n logger.info('📦 [UniversalFileService] 注册存储提供者: ' + (provider.type));\n }\n\n /**\n * 注册CDN提供者\n */\n registerCDNProvider(provider: ICDNProvider): void {\n this.cdnProviders.set(provider.type, provider);\n logger.info('🌐 [UniversalFileService] 注册CDN提供者: ' + (provider.type));\n }\n\n /**\n * 注册文件处理器\n */\n registerFileProcessor(processor: IFileProcessor): void {\n this.fileProcessors.set(processor.type, processor);\n logger.info('⚙️ [UniversalFileService] 注册文件处理器: ' + (processor.type));\n }\n\n // ============= 核心文件操作方法 =============\n\n /**\n * 上传文件\n */\n async uploadFile(\n fileInfo: UploadFileInfo,\n storageType?: StorageType,\n onProgress?: (progress: UploadProgress) => void\n ): Promise<FileMetadata> {\n const fileId = uuidv4();\n const startTime = Date.now();\n\n logger.info('📤 [UniversalFileService] 开始上传文件: ' + (fileInfo.file.name) + ', ID: ' + (fileId));\n\n try {\n // 验证文件\n await this.validateFile(fileInfo.file);\n\n // 初始化上传进度\n const progress: UploadProgress = {\n fileId,\n status: 'pending',\n progress: 0,\n uploadedBytes: 0,\n totalBytes: fileInfo.file.size,\n speed: 0,\n remainingTime: 0,\n };\n\n this.uploadProgressMap.set(fileId, progress);\n this.emitFileEvent('upload:start', fileId, { fileName: fileInfo.file.name });\n\n // 生成文件元数据\n const metadata = await this.generateFileMetadata(fileId, fileInfo);\n\n // 选择存储提供者\n const selectedStorageType = storageType || this.config.defaultStorage;\n let storageProvider = this.storageProviders.get(selectedStorageType as StorageType);\n\n // 如果指定的存储提供者不可用,优先尝试OSS\n if (!storageProvider) {\n logger.info(\n '⚠️ [UniversalFileService] 存储提供者 ' + (selectedStorageType) + ' 不可用,尝试使用OSS'\n );\n storageProvider = this.storageProviders.get('aliyun-oss');\n\n // 如果OSS也不可用,回退到本地存储\n if (!storageProvider) {\n logger.info(`⚠️ [UniversalFileService] OSS不可用,回退到本地存储`);\n storageProvider = this.storageProviders.get('local');\n }\n }\n\n if (!storageProvider) {\n throw new StorageProviderError(`没有可用的存储提供者`);\n }\n\n // 生成存储路径\n const storagePath = this.generateStoragePath(metadata);\n\n // 更新上传状态\n progress.status = 'uploading';\n progress.progress = 10;\n this.uploadProgressMap.set(fileId, progress);\n onProgress?.(progress);\n this.emitFileEvent('upload:progress', fileId, { progress: progress.progress });\n\n // 执行上传\n const uploadResult = await storageProvider.upload(fileInfo, storagePath);\n\n if (!uploadResult.success) {\n throw new FileUploadError('上传失败: ' + (uploadResult.error));\n }\n\n // 更新元数据\n metadata.storagePath = uploadResult.path || storagePath;\n metadata.storageProvider = selectedStorageType as StorageType;\n\n // 生成CDN URL(如果启用)\n if (this.config.defaultCDN !== 'none') {\n const cdnProvider = this.cdnProviders.get(this.config.defaultCDN as CDNType);\n if (cdnProvider && uploadResult.url) {\n metadata.cdnUrl = await cdnProvider.generateUrl(uploadResult.url);\n }\n }\n\n // 更新上传进度\n progress.status = fileInfo.needsProcessing ? 'processing' : 'completed';\n progress.progress = fileInfo.needsProcessing ? 70 : 100;\n this.uploadProgressMap.set(fileId, progress);\n onProgress?.(progress);\n\n // 如果需要处理,添加到处理队列\n if (fileInfo.needsProcessing && fileInfo.processingOptions) {\n await this.queueFileProcessing(metadata, fileInfo.processingOptions);\n }\n\n // 缓存元数据\n this.cacheMetadata(metadata);\n\n // 保存到数据库通过事件触发(如果启用了持久化)\n // persistence.repository 会监听 'upload:complete' 事件自动保存\n\n // 完成上传\n progress.status = 'completed';\n progress.progress = 100;\n this.uploadProgressMap.set(fileId, progress);\n onProgress?.(progress);\n\n const uploadTime = Date.now() - startTime;\n logger.info('✅ [UniversalFileService] 文件上传完成: ' + (fileId) + ', 耗时: ' + (uploadTime) + 'ms');\n\n this.emitFileEvent('upload:complete', fileId, {\n fileName: fileInfo.file.name,\n size: fileInfo.file.size,\n uploadTime,\n });\n\n return metadata;\n } catch (error) {\n console.error('❌ [UniversalFileService] 文件上传失败: ' + (fileId) + ':', error);\n\n // 更新上传状态为失败\n const progress = this.uploadProgressMap.get(fileId);\n if (progress) {\n progress.status = 'failed';\n progress.error = error instanceof Error ? error.message : '上传失败';\n this.uploadProgressMap.set(fileId, progress);\n onProgress?.(progress);\n }\n\n this.emitFileEvent(\n 'upload:error',\n fileId,\n undefined,\n error instanceof Error ? error.message : '上传失败'\n );\n throw error;\n } finally {\n // 清理上传进度(可选,或设置过期时间)\n setTimeout(\n () => {\n this.uploadProgressMap.delete(fileId);\n },\n 5 * 60 * 1000\n ); // 5分钟后清理\n }\n }\n\n\n /**\n * 下载文件\n */\n async downloadFile(fileId: string, userId?: string): Promise<Buffer> {\n logger.info('📥 [UniversalFileService] 开始下载文件: ' + (fileId));\n\n try {\n this.emitFileEvent('download:start', fileId);\n\n // 获取文件元数据\n const metadata = await this.getFileMetadata(fileId);\n\n if (!metadata) {\n throw new FileUploadError('文件不存在: ' + (fileId));\n }\n\n // 检查权限\n await this.checkFileAccess(metadata, userId);\n\n // 获取存储提供者\n const storageProvider = this.storageProviders.get(metadata.storageProvider);\n\n if (!storageProvider) {\n throw new StorageProviderError('存储提供者不存在: ' + (metadata.storageProvider));\n }\n\n // 下载文件\n const fileBuffer = await storageProvider.download(metadata.storagePath);\n\n // 更新访问统计 (如果启用了持久化)\n if (this.config.persistence?.enabled) {\n await this.updateAccessStats(fileId);\n }\n\n logger.info('✅ [UniversalFileService] 文件下载完成: ' + (fileId));\n this.emitFileEvent('download:complete', fileId, { size: fileBuffer.length });\n\n return fileBuffer;\n } catch (error) {\n console.error('❌ [UniversalFileService] 文件下载失败: ' + (fileId) + ':', error);\n this.emitFileEvent('download:error', fileId, undefined, error instanceof Error ? error.message : '下载失败');\n throw error;\n }\n }\n\n /**\n * 删除文件\n */\n async deleteFile(fileId: string, userId?: string): Promise<void> {\n logger.info('🗑️ [UniversalFileService] 开始删除文件: ' + (fileId));\n\n try {\n // 获取文件元数据\n const metadata = await this.getFileMetadata(fileId);\n\n if (!metadata) {\n throw new FileUploadError('文件不存在: ' + (fileId));\n }\n\n // 检查删除权限\n await this.checkFileDeleteAccess(metadata, userId);\n\n // 获取存储提供者\n const storageProvider = this.storageProviders.get(metadata.storageProvider);\n\n if (!storageProvider) {\n throw new StorageProviderError('存储提供者不存在: ' + (metadata.storageProvider));\n }\n\n // 从存储中删除文件\n const deleteResult = await storageProvider.delete(metadata.storagePath);\n\n if (!deleteResult.success) {\n console.warn('⚠️ [UniversalFileService] 存储文件删除失败: ' + (deleteResult.error));\n }\n\n // 从数据库中删除元数据 (通过事件触发)\n if (this.config.persistence?.enabled) {\n await this.deleteFileMetadata(fileId);\n }\n\n // 清除缓存\n this.clearMetadataCache(fileId);\n\n logger.info('✅ [UniversalFileService] 文件删除完成: ' + (fileId));\n this.emitFileEvent('delete:complete', fileId);\n this.emit('file:deleted', fileId);\n } catch (error) {\n console.error('❌ [UniversalFileService] 文件删除失败: ' + (fileId) + ':', error);\n this.emitFileEvent('delete:error', fileId, undefined, error instanceof Error ? error.message : '删除失败');\n throw error;\n }\n }\n\n /**\n * 获取文件访问URL\n */\n async getFileUrl(fileId: string, userId?: string, expiresIn?: number): Promise<string> {\n // 检查缓存\n const cacheKey = (fileId) + '_' + (userId || 'public') + '_' + (expiresIn || 0);\n const cached = this.urlCache.get(cacheKey);\n\n if (cached && cached.expires > Date.now()) {\n return cached.url;\n }\n\n // 获取文件元数据\n const metadata = await this.getFileMetadata(fileId);\n\n if (!metadata) {\n throw new FileUploadError('文件不存在: ' + (fileId));\n }\n\n // 检查访问权限\n await this.checkFileAccess(metadata, userId);\n\n let url: string;\n\n // 优先使用CDN URL\n if (metadata.cdnUrl) {\n url = metadata.cdnUrl;\n } else {\n // 获取存储提供者访问URL\n const storageProvider = this.storageProviders.get(metadata.storageProvider);\n\n if (!storageProvider) {\n throw new StorageProviderError('存储提供者不存在: ' + (metadata.storageProvider));\n }\n\n url = await storageProvider.getAccessUrl(metadata.storagePath, expiresIn);\n }\n\n // 缓存URL\n const cacheExpires = Date.now() + (this.config.cache?.urlTTL || 1800) * 1000;\n this.urlCache.set(cacheKey, { url, expires: cacheExpires });\n\n return url;\n }\n\n /**\n * 获取文件元数据\n */\n async getFileMetadata(fileId: string): Promise<FileMetadata | null> {\n // 检查缓存\n const cached = this.metadataCache.get(fileId);\n if (cached && cached.expires > Date.now()) {\n return cached.data;\n }\n\n // 如果启用了持久化,从数据库查询\n if (this.config.persistence?.enabled && this.config.persistence.repository) {\n try {\n const metadata = await this.config.persistence.repository.get(fileId);\n if (metadata) {\n // 缓存结果\n this.cacheMetadata(metadata);\n }\n return metadata;\n } catch (error) {\n console.error('❌ [UniversalFileService] 查询文件元数据失败:', error);\n return null;\n }\n }\n\n // 如果没有启用持久化,返回 null\n logger.warn('⚠️ [UniversalFileService] 持久化未启用,无法查询文件元数据: ' + (fileId));\n return null;\n }\n\n /**\n * 查询文件列表\n */\n async queryFiles(options: FileQueryOptions): Promise<PaginatedResult<FileMetadata>> {\n if (!this.config.persistence?.enabled || !this.config.persistence.repository) {\n logger.warn('⚠️ [UniversalFileService] 持久化未启用,无法查询文件列表');\n return {\n items: [],\n total: 0,\n page: options.page || 1,\n pageSize: options.pageSize || 20,\n totalPages: 0,\n hasNext: false,\n hasPrev: false,\n };\n }\n\n try {\n const result = await this.config.persistence.repository.query(options);\n // 添加 hasNext 和 hasPrev\n const hasNext = result.page < result.totalPages;\n const hasPrev = result.page > 1;\n return {\n ...result,\n hasNext,\n hasPrev,\n };\n } catch (error) {\n console.error('❌ [UniversalFileService] 查询文件列表失败:', error);\n throw error;\n }\n }\n\n /**\n * 批量删除文件\n */\n async batchDeleteFiles(fileIds: string[], userId?: string): Promise<BatchOperationResult> {\n const result: BatchOperationResult = {\n successCount: 0,\n failureCount: 0,\n failures: [],\n };\n\n for (const fileId of fileIds) {\n try {\n await this.deleteFile(fileId, userId);\n result.successCount++;\n } catch (error) {\n result.failureCount++;\n result.failures.push({\n fileId,\n error: error instanceof Error ? error.message : '删除失败',\n });\n }\n }\n\n // 触发批量删除事件\n if (result.successCount > 0) {\n this.emit('files:batch-deleted', fileIds.filter((_, i) => i < result.successCount));\n }\n\n return result;\n }\n\n /**\n * 获取上传进度\n */\n getUploadProgress(fileId: string): UploadProgress | undefined {\n return this.uploadProgressMap.get(fileId);\n }\n\n // ============= 事件处理方法 =============\n\n /**\n * 监听文件事件\n */\n onFileEvent(eventType: string, listener: FileEventListener): void {\n this.on(eventType, listener);\n }\n\n /**\n * 移除文件事件监听器\n */\n offFileEvent(eventType: string, listener: FileEventListener): void {\n this.off(eventType, listener);\n }\n\n // ============= 私有方法 =============\n\n /**\n * 验证配置是否完整\n */\n private async validateConfiguration(): Promise<void> {\n logger.info('🔍 [UniversalFileService] 验证配置文件...');\n\n // 检查基础配置\n if (!this.config) {\n throw new Error('文件服务配置为空');\n }\n\n // 检查存储配置\n if (!this.config.storage) {\n throw new Error('存储配置为空');\n }\n\n // 检查存储提供者配置\n if (this.config.storage.type === 'aliyun-oss') {\n const ossConfig = this.config.storage as any;\n\n // 如果配置不完整,等待配置加载\n if (!ossConfig.accessKeyId || !ossConfig.accessKeySecret || !ossConfig.bucket || !ossConfig.region) {\n logger.warn('⚠️ [UniversalFileService] OSS配置不完整,等待配置加载...');\n\n // 轮询检查配置是否加载完成,最多等待30秒\n const maxRetries = 30;\n const retryInterval = 1000; // 1秒\n\n for (let i = 0; i < maxRetries; i++) {\n await new Promise(resolve => setTimeout(resolve, retryInterval));\n\n // 重新检查配置(这里假设配置可能会被外部更新)\n const updatedConfig = this.config.storage as any;\n if (updatedConfig.accessKeyId && updatedConfig.accessKeySecret && updatedConfig.bucket && updatedConfig.region) {\n logger.info('✅ [UniversalFileService] OSS配置加载完成');\n break;\n }\n\n if (i === maxRetries - 1) {\n throw new Error('OSS配置加载超时:缺少必需的配置项 (accessKeyId, accessKeySecret, bucket, region)');\n }\n\n logger.debug('等待OSS配置加载中... (' + (i + 1) + '/' + (maxRetries) + ')');\n }\n }\n }\n\n // 检查默认存储类型\n if (!this.config.defaultStorage) {\n this.config.defaultStorage = this.config.storage.type as any;\n }\n\n logger.info('✅ [UniversalFileService] 配置验证完成');\n }\n\n private async initializeStorageProviders(): Promise<void> {\n logger.info('📦 [UniversalFileService] 开始初始化存储提供者...');\n\n // 如果还没有注册任何存储提供者,先注册默认的\n if (this.storageProviders.size === 0) {\n await this.registerDefaultStorageProviders();\n }\n\n if (this.config.storageProviders) {\n for (const [type, config] of Object.entries(this.config.storageProviders)) {\n if (config && config.enabled) {\n const provider = this.storageProviders.get(type as StorageType);\n if (provider) {\n try {\n await provider.initialize(config);\n logger.info('✅ [UniversalFileService] 存储提供者初始化完成: ' + (type));\n } catch (error) {\n console.warn('⚠️ [UniversalFileService] 存储提供者初始化失败: ' + (type) + ':', error);\n // 如果默认存储提供者初始化失败,切换到本地存储\n // if (type === this.config.defaultStorage) {\n // console.warn('⚠️ [UniversalFileService] 默认存储提供者 ' + (type) + ' 初始化失败,切换到本地存储');\n // this.config.defaultStorage = 'local';\n // }\n }\n } else {\n console.warn('⚠️ [UniversalFileService] 存储提供者未注册: ' + (type));\n }\n }\n }\n }\n }\n\n private async registerDefaultStorageProviders(): Promise<void> {\n logger.info('📦 [UniversalFileService] 注册默认存储提供者...');\n\n // 根据配置注册相应的存储提供者\n try {\n if (this.config.storage) {\n if (this.config.storage.type === 'aliyun-oss' && this.config.storage.enabled) {\n const { AliyunOSSProvider } = await import('./providers/AliyunOSSProvider');\n const ossProvider = new AliyunOSSProvider();\n this.registerStorageProvider(ossProvider);\n logger.info('✅ [UniversalFileService] 阿里云OSS提供者注册成功');\n } else if (this.config.storage.type === 'local' && this.config.storage.enabled) {\n const { LocalStorageProvider } = await import('./providers/LocalStorageProvider');\n const localProvider = new LocalStorageProvider();\n this.registerStorageProvider(localProvider);\n logger.info('✅ [UniversalFileService] 本地存储提供者注册成功');\n }\n }\n\n // 如果没有注册任何提供者,注册本地存储作为后备\n if (this.storageProviders.size === 0) {\n const { LocalStorageProvider } = await import('./providers/LocalStorageProvider');\n const fallbackProvider = new LocalStorageProvider();\n this.registerStorageProvider(fallbackProvider);\n logger.info('✅ [UniversalFileService] 已注册备用本地存储提供者');\n }\n } catch (error) {\n console.warn('⚠️ [UniversalFileService] 注册默认存储提供者失败:', error);\n throw new Error('无法初始化存储提供者');\n }\n }\n\n private async initializeCDNProviders(): Promise<void> {\n // CDN 初始化暂时跳过,未来支持多个 CDN 提供者时实现\n if (this.config.cdn && this.config.cdn.enabled) {\n logger.info('✅ [UniversalFileService] CDN配置已启用: ' + (this.config.cdn.type));\n }\n }\n\n private async initializeFileProcessors(): Promise<void> {\n for (const processor of Array.from(this.fileProcessors.values())) {\n await processor.initialize();\n logger.info('✅ [UniversalFileService] 文件处理器初始化完成: ' + (processor.type));\n }\n }\n\n private async validateFile(file: File): Promise<void> {\n // 检查文件大小\n if (this.config.maxFileSize && file.size > this.config.maxFileSize) {\n throw new FileUploadError('文件大小超过限制: ' + (file.size) + ' > ' + (this.config.maxFileSize));\n }\n\n // 检查文件类型\n const mimeType = file.type || getMimeType(file.name);\n\n if (\n this.config.allowedMimeTypes &&\n this.config.allowedMimeTypes.length > 0 &&\n !this.config.allowedMimeTypes.includes(mimeType)\n ) {\n throw new FileUploadError('不支持的文件类型: ' + (mimeType));\n }\n }\n\n private async generateFileMetadata(\n fileId: string,\n fileInfo: UploadFileInfo\n ): Promise<FileMetadata> {\n const now = new Date();\n const mimeType = fileInfo.file.type || getMimeType(fileInfo.file.name);\n const extension = path.extname(fileInfo.file.name).toLowerCase();\n\n // 生成文件哈希(用于去重检测)\n const hash = await this.generateFileHash(fileInfo.file);\n\n return {\n id: fileId,\n originalName: fileInfo.file.name,\n storageName: (fileId) + (extension),\n size: fileInfo.file.size,\n mimeType,\n extension,\n hash,\n uploadTime: now,\n permission: fileInfo.permission || 'public',\n uploaderId: fileInfo.metadata?.uploadedBy || 'system',\n moduleId: fileInfo.moduleId,\n businessId: fileInfo.businessId,\n storageProvider: (this.config.defaultStorage || 'local') as StorageType,\n storagePath: '',\n accessCount: 0,\n metadata: fileInfo.metadata || {},\n };\n }\n\n private generateStoragePath(metadata: FileMetadata): string {\n const date = new Date();\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n\n return (metadata.moduleId) + '/' + (year) + '/' + (month) + '/' + (day) + '/' + (metadata.storageName);\n }\n\n private async generateFileHash(file: File): Promise<string> {\n const buffer = await file.arrayBuffer();\n const hash = createHash('sha256');\n hash.update(Buffer.from(buffer));\n return hash.digest('hex');\n }\n\n private async queueFileProcessing(metadata: FileMetadata, options: any): Promise<void> {\n if (!this.config.processors?.length || 0 > 0) {\n return;\n }\n\n const processor = this.fileProcessors.get(options.type);\n if (!processor) {\n console.warn('⚠️ [UniversalFileService] 文件处理器不存在: ' + (options.type));\n return;\n }\n\n if (this.processingQueue.length >= 1000) {\n throw new FileProcessingError('处理队列已满');\n }\n\n this.processingQueue.push({\n fileId: metadata.id,\n processor,\n inputPath: metadata.storagePath,\n outputPath: this.generateProcessedPath(metadata, options),\n options,\n });\n\n // 启动处理队列\n if (!this.isProcessingQueueRunning) {\n this.processFileQueue();\n }\n }\n\n private generateProcessedPath(metadata: FileMetadata, options: any): string {\n const basePath = metadata.storagePath;\n const extension = path.extname(basePath);\n const basename = basePath.replace(extension, '');\n\n return (basename) + '_processed' + (extension);\n }\n\n private async processFileQueue(): Promise<void> {\n if (this.isProcessingQueueRunning || this.processingQueue.length === 0) {\n return;\n }\n\n this.isProcessingQueueRunning = true;\n\n while (this.processingQueue.length > 0) {\n const task = this.processingQueue.shift();\n if (!task) break;\n\n try {\n this.emitFileEvent('processing:start', task.fileId);\n\n const result = await task.processor.process(task.inputPath, task.outputPath, task.options);\n\n if (result.success) {\n this.emitFileEvent('processing:complete', task.fileId, result);\n } else {\n this.emitFileEvent('processing:error', task.fileId, undefined, result.error);\n }\n } catch (error) {\n console.error('❌ [UniversalFileService] 文件处理失败: ' + (task.fileId) + ':', error);\n this.emitFileEvent(\n 'processing:error',\n task.fileId,\n undefined,\n error instanceof Error ? error.message : '处理失败'\n );\n }\n }\n\n this.isProcessingQueueRunning = false;\n }\n\n private cacheMetadata(metadata: FileMetadata): void {\n const expires = Date.now() + (this.config.cache?.metadataTTL || 3600) * 1000;\n this.metadataCache.set(metadata.id, { data: metadata, expires });\n }\n\n private clearMetadataCache(fileId: string): void {\n this.metadataCache.delete(fileId);\n }\n\n private emitFileEvent(type: string, fileId: string, data?: any, error?: string): void {\n const event: FileEvent = {\n type: type as any,\n fileId,\n timestamp: new Date(),\n data,\n error,\n };\n\n this.emit(type, event);\n this.emit('*', event); // 通用事件监听\n }\n\n // ============= 数据库操作私有方法 =============\n\n /**\n * 保存文件元数据到数据库 (通过持久化仓储)\n */\n private async saveFileMetadata(metadata: FileMetadata): Promise<void> {\n if (!this.config.persistence?.enabled || !this.config.persistence.repository) {\n logger.warn('⚠️ [UniversalFileService] 持久化未启用,跳过保存元数据');\n return;\n }\n\n try {\n await this.config.persistence.repository.save(metadata);\n logger.info('💾 [UniversalFileService] 文件元数据保存成功:', metadata.id);\n } catch (error) {\n console.error('❌ [UniversalFileService] 保存文件元数据失败:', error);\n throw new FileUploadError(\n '保存文件元数据失败: ' + (error instanceof Error ? error.message : '未知错误')\n );\n }\n }\n\n /**\n * 从数据库删除文件元数据 (通过持久化仓储)\n */\n private async deleteFileMetadata(fileId: string): Promise<void> {\n if (!this.config.persistence?.enabled || !this.config.persistence.repository) {\n return;\n }\n\n try {\n await this.config.persistence.repository.delete(fileId);\n logger.info('🗑️ [UniversalFileService] 文件元数据删除成功:', fileId);\n } catch (error) {\n console.error('❌ [UniversalFileService] 删除文件元数据失败:', error);\n throw new FileUploadError(\n '删除文件元数据失败: ' + (error instanceof Error ? error.message : '未知错误')\n );\n }\n }\n\n /**\n * 更新访问统计\n */\n private async updateAccessStats(fileId: string): Promise<void> {\n // 访问统计更新由数据库仓储实现决定\n // 这里只记录日志\n logger.info('📊 [UniversalFileService] 需要更新访问统计:', fileId);\n }\n\n /**\n * 检查文件访问权限\n */\n private async checkFileAccess(metadata: FileMetadata, userId?: string): Promise<void> {\n // 如果文件是公开的,允许访问\n if (metadata.permission === 'public') {\n return;\n }\n\n // 如果是私有文件,检查用户权限\n if (metadata.permission === 'private' && metadata.uploaderId !== userId) {\n throw new FileUploadError('无权限访问此文件');\n }\n\n // 如果是认证用户可访问,检查是否提供了 userId\n if (metadata.permission === 'authenticated' && !userId) {\n throw new FileUploadError('需要登录才能访问此文件');\n }\n }\n\n /**\n * 检查文件删除权限\n */\n private async checkFileDeleteAccess(metadata: FileMetadata, userId?: string): Promise<void> {\n // 只有上传者可以删除文件\n if (metadata.uploaderId !== userId) {\n throw new FileUploadError('无权限删除此文件');\n }\n }\n\n /**\n * 检查服务是否完全可用(包括存储提供者)\n */\n isFullyInitialized(): boolean {\n // 检查是否有可用的存储提供者\n const hasStorageProvider = Array.from(this.storageProviders.values()).some(provider =>\n provider.type === 'aliyun-oss' || provider.type === 'local'\n );\n\n return hasStorageProvider;\n }\n\n /**\n * 等待服务完全初始化(带超时)\n */\n async waitForInitialization(timeoutMs: number = 30000): Promise<void> {\n const startTime = Date.now();\n\n while (!this.isFullyInitialized()) {\n if (Date.now() - startTime > timeoutMs) {\n throw new Error('服务初始化超时 (' + (timeoutMs) + 'ms)');\n }\n\n // 等待100ms后重试\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n\n logger.info('✅ [UniversalFileService] 服务完全初始化就绪');\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/universalFile/server/utils/mime.ts","../src/universalFile/server/UniversalFileService.ts"],"names":["path","createLogger","EventEmitter","uuidv4","StorageProviderError","FileUploadError","path2","createHash","FileProcessingError"],"mappings":"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","file":"chunk-27IUMDDK.js","sourcesContent":["/**\n * MIME 类型工具函数\n */\n\nimport * as path from 'path';\n\n/** MIME 类型映射表 */\nconst MIME_TYPES: Record<string, string> = {\n // 图片\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.png': 'image/png',\n '.gif': 'image/gif',\n '.webp': 'image/webp',\n '.svg': 'image/svg+xml',\n '.bmp': 'image/bmp',\n '.ico': 'image/x-icon',\n\n // 视频\n '.mp4': 'video/mp4',\n '.avi': 'video/x-msvideo',\n '.mov': 'video/quicktime',\n '.wmv': 'video/x-ms-wmv',\n '.flv': 'video/x-flv',\n '.mkv': 'video/x-matroska',\n '.webm': 'video/webm',\n\n // 音频\n '.mp3': 'audio/mpeg',\n '.wav': 'audio/wav',\n '.ogg': 'audio/ogg',\n '.m4a': 'audio/mp4',\n '.flac': 'audio/flac',\n '.aac': 'audio/aac',\n\n // 文档\n '.pdf': 'application/pdf',\n '.doc': 'application/msword',\n '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n '.xls': 'application/vnd.ms-excel',\n '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n '.ppt': 'application/vnd.ms-powerpoint',\n '.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n '.txt': 'text/plain',\n '.rtf': 'application/rtf',\n\n // 压缩文件\n '.zip': 'application/zip',\n '.rar': 'application/x-rar-compressed',\n '.7z': 'application/x-7z-compressed',\n '.tar': 'application/x-tar',\n '.gz': 'application/gzip',\n\n // 代码文件\n '.js': 'application/javascript',\n '.json': 'application/json',\n '.xml': 'application/xml',\n '.html': 'text/html',\n '.css': 'text/css',\n '.ts': 'application/typescript',\n\n // 其他\n '.csv': 'text/csv',\n '.md': 'text/markdown',\n};\n\n/**\n * 根据文件名获取 MIME 类型\n *\n * @param filename 文件名\n * @returns MIME 类型\n *\n * @example\n * ```typescript\n * getMimeType('photo.jpg') // 'image/jpeg'\n * getMimeType('video.mp4') // 'video/mp4'\n * getMimeType('unknown.xyz') // 'application/octet-stream'\n * ```\n */\nexport function getMimeType(filename: string): string {\n const ext = path.extname(filename).toLowerCase();\n return MIME_TYPES[ext] || 'application/octet-stream';\n}\n\n/**\n * 根据 MIME 类型获取文件扩展名\n *\n * @param mimeType MIME 类型\n * @returns 文件扩展名(包含点号)\n *\n * @example\n * ```typescript\n * getExtensionFromMimeType('image/jpeg') // '.jpg'\n * getExtensionFromMimeType('video/mp4') // '.mp4'\n * ```\n */\nexport function getExtensionFromMimeType(mimeType: string): string | null {\n for (const [ext, mime] of Object.entries(MIME_TYPES)) {\n if (mime === mimeType) {\n return ext;\n }\n }\n return null;\n}\n\n/**\n * 检查是否为图片类型\n *\n * @param mimeType MIME 类型\n * @returns 是否为图片\n */\nexport function isImageType(mimeType: string): boolean {\n return mimeType.startsWith('image/');\n}\n\n/**\n * 检查是否为视频类型\n *\n * @param mimeType MIME 类型\n * @returns 是否为视频\n */\nexport function isVideoType(mimeType: string): boolean {\n return mimeType.startsWith('video/');\n}\n\n/**\n * 检查是否为音频类型\n *\n * @param mimeType MIME 类型\n * @returns 是否为音频\n */\nexport function isAudioType(mimeType: string): boolean {\n return mimeType.startsWith('audio/');\n}\n\n/**\n * 检查是否为文档类型\n *\n * @param mimeType MIME 类型\n * @returns 是否为文档\n */\nexport function isDocumentType(mimeType: string): boolean {\n const documentTypes = [\n 'application/pdf',\n 'application/msword',\n 'application/vnd.openxmlformats-officedocument',\n 'text/plain',\n 'application/rtf',\n ];\n return documentTypes.some(type => mimeType.includes(type));\n}\n\n/**\n * 验证 MIME 类型是否在允许列表中\n *\n * @param mimeType MIME 类型\n * @param allowedTypes 允许的类型列表(支持通配符)\n * @returns 是否允许\n *\n * @example\n * ```typescript\n * isAllowedMimeType('image/jpeg', ['image/*']) // true\n * isAllowedMimeType('video/mp4', ['image/*']) // false\n * isAllowedMimeType('image/png', ['image/jpeg']) // false\n * ```\n */\nexport function isAllowedMimeType(\n mimeType: string,\n allowedTypes: string[]\n): boolean {\n return allowedTypes.some(allowed => {\n if (allowed === '*/*') {\n return true;\n }\n if (allowed.endsWith('/*')) {\n const prefix = allowed.slice(0, -2);\n return mimeType.startsWith(prefix + '/');\n }\n return mimeType === allowed;\n });\n}\n\n","/**\n * 通用文件服务核心实现\n *\n * 提供统一的文件上传、下载、管理接口\n */\n\nimport { EventEmitter } from 'events';\nimport { v4 as uuidv4 } from 'uuid';\nimport { createHash } from 'crypto';\nimport * as path from 'path';\nimport { createLogger } from '../../logger';\nimport { getMimeType } from './utils/mime';\n\nconst logger = createLogger('UniversalFileService');\n\nimport type {\n StorageType,\n CDNType,\n ProcessorType,\n FileMetadata,\n UploadFileInfo,\n UploadProgress,\n FileQueryOptions,\n PaginatedResult,\n BatchOperationResult,\n FileEvent,\n FileEventListener,\n UploadStatus,\n} from '../types';\n\n// Backend specific types\nimport type {\n UniversalFileServiceConfig,\n IStorageProvider,\n ICDNProvider,\n IFileProcessor,\n} from './types';\n\nimport {\n FileUploadError,\n FileProcessingError,\n StorageProviderError,\n} from '../types';\n\n/**\n * 通用文件服务类\n */\nexport class UniversalFileService extends EventEmitter {\n private config: UniversalFileServiceConfig;\n private storageProviders = new Map<StorageType, IStorageProvider>();\n private cdnProviders = new Map<CDNType, ICDNProvider>();\n private fileProcessors = new Map<ProcessorType, IFileProcessor>();\n private uploadProgressMap = new Map<string, UploadProgress>();\n private metadataCache = new Map<string, { data: FileMetadata; expires: number }>();\n private urlCache = new Map<string, { url: string; expires: number }>();\n private processingQueue: Array<{\n fileId: string;\n processor: IFileProcessor;\n inputPath: string;\n outputPath: string;\n options: any;\n }> = [];\n private isProcessingQueueRunning = false;\n\n constructor(config: UniversalFileServiceConfig) {\n super();\n this.config = config;\n\n // 如果启用了持久化,设置自动监听器\n if (this.config.persistence?.enabled && this.config.persistence.repository) {\n this.setupPersistenceListeners();\n }\n }\n\n // ============= 持久化设置 =============\n\n /**\n * 设置数据库持久化监听器\n *\n * 当文件上传完成或删除时,自动触发数据库操作\n */\n private setupPersistenceListeners(): void {\n const { repository, autoPersist = true } = this.config.persistence!;\n\n if (!autoPersist) {\n logger.info('⚙️ [UniversalFileService] 自动持久化已禁用');\n return;\n }\n\n logger.info('✅ [UniversalFileService] 已启用数据库持久化,自动监听文件事件');\n\n // 监听文件上传完成事件\n this.on('upload:complete', async (fileId: string, data: any) => {\n try {\n const metadata = data.metadata || data;\n await repository.save(metadata);\n logger.info('💾 [Persistence] 文件元数据已自动保存: ' + (fileId));\n } catch (error) {\n logger.error('❌ [Persistence] 保存失败: ' + (fileId), error);\n // 不抛出错误,避免影响上传流程\n }\n });\n\n // 监听文件删除事件\n this.on('file:deleted', async (fileId: string) => {\n try {\n await repository.delete(fileId);\n logger.info('🗑️ [Persistence] 文件元数据已自动删除: ' + (fileId));\n } catch (error) {\n logger.error('❌ [Persistence] 删除失败: ' + (fileId), error);\n }\n });\n\n // 监听批量删除事件\n this.on('files:batch-deleted', async (fileIds: string[]) => {\n try {\n await repository.batchDelete(fileIds);\n logger.info('🗑️ [Persistence] 批量删除元数据: ' + (fileIds.length) + ' 个文件');\n } catch (error) {\n logger.error(`❌ [Persistence] 批量删除失败`, error);\n }\n });\n }\n\n // ============= 初始化方法 =============\n\n /**\n * 初始化文件服务\n */\n async initialize(): Promise<void> {\n logger.info('🚀 [UniversalFileService] 开始初始化文件服务...');\n\n try {\n // 验证配置是否完整\n await this.validateConfiguration();\n\n // 初始化存储提供者\n await this.initializeStorageProviders();\n\n // 初始化CDN提供者\n await this.initializeCDNProviders();\n\n // 初始化文件处理器\n await this.initializeFileProcessors();\n\n logger.info('✅ [UniversalFileService] 文件服务初始化完成');\n } catch (error) {\n console.error('❌ [UniversalFileService] 文件服务初始化失败:', error);\n throw error;\n }\n }\n\n /**\n * 重新初始化存储提供者(支持配置热更新)\n */\n async reinitializeStorageProviders(): Promise<void> {\n logger.info('🔄 [UniversalFileService] 重新初始化存储提供者...');\n\n try {\n // 重新初始化所有存储提供者\n for (const [type, provider] of this.storageProviders) {\n if ('reinitialize' in provider) {\n try {\n logger.info('🔄 [UniversalFileService] 重新初始化存储提供者: ' + (type) + '...');\n\n // 获取对应的配置(从原始配置中获取)\n const config = (this.config as any).storageProviders?.[type as string];\n if (config) {\n await (provider as any).reinitialize(config);\n logger.info('✅ [UniversalFileService] 存储提供者重新初始化完成: ' + (type));\n } else {\n logger.warn('⚠️ [UniversalFileService] 存储提供者配置不存在: ' + (type));\n }\n } catch (error) {\n logger.error('❌ [UniversalFileService] 存储提供者重新初始化失败: ' + (type), error);\n // 继续处理其他提供者\n }\n }\n }\n\n logger.info('✅ [UniversalFileService] 存储提供者重新初始化完成');\n } catch (error) {\n console.error('❌ [UniversalFileService] 存储提供者重新初始化失败:', error);\n throw error;\n }\n }\n\n /**\n * 注册存储提供者\n */\n registerStorageProvider(provider: IStorageProvider): void {\n this.storageProviders.set(provider.type, provider);\n logger.info('📦 [UniversalFileService] 注册存储提供者: ' + (provider.type));\n }\n\n /**\n * 注册CDN提供者\n */\n registerCDNProvider(provider: ICDNProvider): void {\n this.cdnProviders.set(provider.type, provider);\n logger.info('🌐 [UniversalFileService] 注册CDN提供者: ' + (provider.type));\n }\n\n /**\n * 注册文件处理器\n */\n registerFileProcessor(processor: IFileProcessor): void {\n this.fileProcessors.set(processor.type, processor);\n logger.info('⚙️ [UniversalFileService] 注册文件处理器: ' + (processor.type));\n }\n\n // ============= 核心文件操作方法 =============\n\n /**\n * 上传文件\n */\n async uploadFile(\n fileInfo: UploadFileInfo,\n storageType?: StorageType,\n onProgress?: (progress: UploadProgress) => void\n ): Promise<FileMetadata> {\n const fileId = uuidv4();\n const startTime = Date.now();\n\n logger.info('📤 [UniversalFileService] 开始上传文件: ' + (fileInfo.file.name) + ', ID: ' + (fileId));\n\n try {\n // 验证文件\n await this.validateFile(fileInfo.file);\n\n // 初始化上传进度\n const progress: UploadProgress = {\n fileId,\n status: 'pending',\n progress: 0,\n uploadedBytes: 0,\n totalBytes: fileInfo.file.size,\n speed: 0,\n remainingTime: 0,\n };\n\n this.uploadProgressMap.set(fileId, progress);\n this.emitFileEvent('upload:start', fileId, { fileName: fileInfo.file.name });\n\n // 生成文件元数据\n const metadata = await this.generateFileMetadata(fileId, fileInfo);\n\n // 选择存储提供者\n const selectedStorageType = storageType || this.config.defaultStorage;\n let storageProvider = this.storageProviders.get(selectedStorageType as StorageType);\n\n // 如果指定的存储提供者不可用,优先尝试OSS\n if (!storageProvider) {\n logger.info(\n '⚠️ [UniversalFileService] 存储提供者 ' + (selectedStorageType) + ' 不可用,尝试使用OSS'\n );\n storageProvider = this.storageProviders.get('aliyun-oss');\n\n // 如果OSS也不可用,回退到本地存储\n if (!storageProvider) {\n logger.info(`⚠️ [UniversalFileService] OSS不可用,回退到本地存储`);\n storageProvider = this.storageProviders.get('local');\n }\n }\n\n if (!storageProvider) {\n throw new StorageProviderError(`没有可用的存储提供者`);\n }\n\n // 生成存储路径\n const storagePath = this.generateStoragePath(metadata);\n\n // 更新上传状态\n progress.status = 'uploading';\n progress.progress = 10;\n this.uploadProgressMap.set(fileId, progress);\n onProgress?.(progress);\n this.emitFileEvent('upload:progress', fileId, { progress: progress.progress });\n\n // 执行上传\n const uploadResult = await storageProvider.upload(fileInfo, storagePath);\n\n if (!uploadResult.success) {\n throw new FileUploadError('上传失败: ' + (uploadResult.error));\n }\n\n // 更新元数据\n metadata.storagePath = uploadResult.path || storagePath;\n metadata.storageProvider = selectedStorageType as StorageType;\n\n // 生成CDN URL(如果启用)\n if (this.config.defaultCDN !== 'none') {\n const cdnProvider = this.cdnProviders.get(this.config.defaultCDN as CDNType);\n if (cdnProvider && uploadResult.url) {\n metadata.cdnUrl = await cdnProvider.generateUrl(uploadResult.url);\n }\n }\n\n // 更新上传进度\n progress.status = fileInfo.needsProcessing ? 'processing' : 'completed';\n progress.progress = fileInfo.needsProcessing ? 70 : 100;\n this.uploadProgressMap.set(fileId, progress);\n onProgress?.(progress);\n\n // 如果需要处理,添加到处理队列\n if (fileInfo.needsProcessing && fileInfo.processingOptions) {\n await this.queueFileProcessing(metadata, fileInfo.processingOptions);\n }\n\n // 缓存元数据\n this.cacheMetadata(metadata);\n\n // 保存到数据库通过事件触发(如果启用了持久化)\n // persistence.repository 会监听 'upload:complete' 事件自动保存\n\n // 完成上传\n progress.status = 'completed';\n progress.progress = 100;\n this.uploadProgressMap.set(fileId, progress);\n onProgress?.(progress);\n\n const uploadTime = Date.now() - startTime;\n logger.info('✅ [UniversalFileService] 文件上传完成: ' + (fileId) + ', 耗时: ' + (uploadTime) + 'ms');\n\n this.emitFileEvent('upload:complete', fileId, {\n fileName: fileInfo.file.name,\n size: fileInfo.file.size,\n uploadTime,\n });\n\n return metadata;\n } catch (error) {\n console.error('❌ [UniversalFileService] 文件上传失败: ' + (fileId) + ':', error);\n\n // 更新上传状态为失败\n const progress = this.uploadProgressMap.get(fileId);\n if (progress) {\n progress.status = 'failed';\n progress.error = error instanceof Error ? error.message : '上传失败';\n this.uploadProgressMap.set(fileId, progress);\n onProgress?.(progress);\n }\n\n this.emitFileEvent(\n 'upload:error',\n fileId,\n undefined,\n error instanceof Error ? error.message : '上传失败'\n );\n throw error;\n } finally {\n // 清理上传进度(可选,或设置过期时间)\n setTimeout(\n () => {\n this.uploadProgressMap.delete(fileId);\n },\n 5 * 60 * 1000\n ); // 5分钟后清理\n }\n }\n\n\n /**\n * 下载文件\n */\n async downloadFile(fileId: string, userId?: string): Promise<Buffer> {\n logger.info('📥 [UniversalFileService] 开始下载文件: ' + (fileId));\n\n try {\n this.emitFileEvent('download:start', fileId);\n\n // 获取文件元数据\n const metadata = await this.getFileMetadata(fileId);\n\n if (!metadata) {\n throw new FileUploadError('文件不存在: ' + (fileId));\n }\n\n // 检查权限\n await this.checkFileAccess(metadata, userId);\n\n // 获取存储提供者\n const storageProvider = this.storageProviders.get(metadata.storageProvider);\n\n if (!storageProvider) {\n throw new StorageProviderError('存储提供者不存在: ' + (metadata.storageProvider));\n }\n\n // 下载文件\n const fileBuffer = await storageProvider.download(metadata.storagePath);\n\n // 更新访问统计 (如果启用了持久化)\n if (this.config.persistence?.enabled) {\n await this.updateAccessStats(fileId);\n }\n\n logger.info('✅ [UniversalFileService] 文件下载完成: ' + (fileId));\n this.emitFileEvent('download:complete', fileId, { size: fileBuffer.length });\n\n return fileBuffer;\n } catch (error) {\n console.error('❌ [UniversalFileService] 文件下载失败: ' + (fileId) + ':', error);\n this.emitFileEvent('download:error', fileId, undefined, error instanceof Error ? error.message : '下载失败');\n throw error;\n }\n }\n\n /**\n * 删除文件\n */\n async deleteFile(fileId: string, userId?: string): Promise<void> {\n logger.info('🗑️ [UniversalFileService] 开始删除文件: ' + (fileId));\n\n try {\n // 获取文件元数据\n const metadata = await this.getFileMetadata(fileId);\n\n if (!metadata) {\n throw new FileUploadError('文件不存在: ' + (fileId));\n }\n\n // 检查删除权限\n await this.checkFileDeleteAccess(metadata, userId);\n\n // 获取存储提供者\n const storageProvider = this.storageProviders.get(metadata.storageProvider);\n\n if (!storageProvider) {\n throw new StorageProviderError('存储提供者不存在: ' + (metadata.storageProvider));\n }\n\n // 从存储中删除文件\n const deleteResult = await storageProvider.delete(metadata.storagePath);\n\n if (!deleteResult.success) {\n console.warn('⚠️ [UniversalFileService] 存储文件删除失败: ' + (deleteResult.error));\n }\n\n // 从数据库中删除元数据 (通过事件触发)\n if (this.config.persistence?.enabled) {\n await this.deleteFileMetadata(fileId);\n }\n\n // 清除缓存\n this.clearMetadataCache(fileId);\n\n logger.info('✅ [UniversalFileService] 文件删除完成: ' + (fileId));\n this.emitFileEvent('delete:complete', fileId);\n this.emit('file:deleted', fileId);\n } catch (error) {\n console.error('❌ [UniversalFileService] 文件删除失败: ' + (fileId) + ':', error);\n this.emitFileEvent('delete:error', fileId, undefined, error instanceof Error ? error.message : '删除失败');\n throw error;\n }\n }\n\n /**\n * 获取文件访问URL\n */\n async getFileUrl(fileId: string, userId?: string, expiresIn?: number): Promise<string> {\n // 检查缓存\n const cacheKey = (fileId) + '_' + (userId || 'public') + '_' + (expiresIn || 0);\n const cached = this.urlCache.get(cacheKey);\n\n if (cached && cached.expires > Date.now()) {\n return cached.url;\n }\n\n // 获取文件元数据\n const metadata = await this.getFileMetadata(fileId);\n\n if (!metadata) {\n throw new FileUploadError('文件不存在: ' + (fileId));\n }\n\n // 检查访问权限\n await this.checkFileAccess(metadata, userId);\n\n let url: string;\n\n // 优先使用CDN URL\n if (metadata.cdnUrl) {\n url = metadata.cdnUrl;\n } else {\n // 获取存储提供者访问URL\n const storageProvider = this.storageProviders.get(metadata.storageProvider);\n\n if (!storageProvider) {\n throw new StorageProviderError('存储提供者不存在: ' + (metadata.storageProvider));\n }\n\n url = await storageProvider.getAccessUrl(metadata.storagePath, expiresIn);\n }\n\n // 缓存URL\n const cacheExpires = Date.now() + (this.config.cache?.urlTTL || 1800) * 1000;\n this.urlCache.set(cacheKey, { url, expires: cacheExpires });\n\n return url;\n }\n\n /**\n * 获取文件元数据\n */\n async getFileMetadata(fileId: string): Promise<FileMetadata | null> {\n // 检查缓存\n const cached = this.metadataCache.get(fileId);\n if (cached && cached.expires > Date.now()) {\n return cached.data;\n }\n\n // 如果启用了持久化,从数据库查询\n if (this.config.persistence?.enabled && this.config.persistence.repository) {\n try {\n const metadata = await this.config.persistence.repository.get(fileId);\n if (metadata) {\n // 缓存结果\n this.cacheMetadata(metadata);\n }\n return metadata;\n } catch (error) {\n console.error('❌ [UniversalFileService] 查询文件元数据失败:', error);\n return null;\n }\n }\n\n // 如果没有启用持久化,返回 null\n logger.warn('⚠️ [UniversalFileService] 持久化未启用,无法查询文件元数据: ' + (fileId));\n return null;\n }\n\n /**\n * 查询文件列表\n */\n async queryFiles(options: FileQueryOptions): Promise<PaginatedResult<FileMetadata>> {\n if (!this.config.persistence?.enabled || !this.config.persistence.repository) {\n logger.warn('⚠️ [UniversalFileService] 持久化未启用,无法查询文件列表');\n return {\n items: [],\n total: 0,\n page: options.page || 1,\n pageSize: options.pageSize || 20,\n totalPages: 0,\n hasNext: false,\n hasPrev: false,\n };\n }\n\n try {\n const result = await this.config.persistence.repository.query(options);\n // 添加 hasNext 和 hasPrev\n const hasNext = result.page < result.totalPages;\n const hasPrev = result.page > 1;\n return {\n ...result,\n hasNext,\n hasPrev,\n };\n } catch (error) {\n console.error('❌ [UniversalFileService] 查询文件列表失败:', error);\n throw error;\n }\n }\n\n /**\n * 批量删除文件\n */\n async batchDeleteFiles(fileIds: string[], userId?: string): Promise<BatchOperationResult> {\n const result: BatchOperationResult = {\n successCount: 0,\n failureCount: 0,\n failures: [],\n };\n\n for (const fileId of fileIds) {\n try {\n await this.deleteFile(fileId, userId);\n result.successCount++;\n } catch (error) {\n result.failureCount++;\n result.failures.push({\n fileId,\n error: error instanceof Error ? error.message : '删除失败',\n });\n }\n }\n\n // 触发批量删除事件\n if (result.successCount > 0) {\n this.emit('files:batch-deleted', fileIds.filter((_, i) => i < result.successCount));\n }\n\n return result;\n }\n\n /**\n * 获取上传进度\n */\n getUploadProgress(fileId: string): UploadProgress | undefined {\n return this.uploadProgressMap.get(fileId);\n }\n\n // ============= 事件处理方法 =============\n\n /**\n * 监听文件事件\n */\n onFileEvent(eventType: string, listener: FileEventListener): void {\n this.on(eventType, listener);\n }\n\n /**\n * 移除文件事件监听器\n */\n offFileEvent(eventType: string, listener: FileEventListener): void {\n this.off(eventType, listener);\n }\n\n // ============= 私有方法 =============\n\n /**\n * 验证配置是否完整\n */\n private async validateConfiguration(): Promise<void> {\n logger.info('🔍 [UniversalFileService] 验证配置文件...');\n\n // 检查基础配置\n if (!this.config) {\n throw new Error('文件服务配置为空');\n }\n\n // 检查存储配置\n if (!this.config.storage) {\n throw new Error('存储配置为空');\n }\n\n // 检查存储提供者配置\n if (this.config.storage.type === 'aliyun-oss') {\n const ossConfig = this.config.storage as any;\n\n // 如果配置不完整,等待配置加载\n if (!ossConfig.accessKeyId || !ossConfig.accessKeySecret || !ossConfig.bucket || !ossConfig.region) {\n logger.warn('⚠️ [UniversalFileService] OSS配置不完整,等待配置加载...');\n\n // 轮询检查配置是否加载完成,最多等待30秒\n const maxRetries = 30;\n const retryInterval = 1000; // 1秒\n\n for (let i = 0; i < maxRetries; i++) {\n await new Promise(resolve => setTimeout(resolve, retryInterval));\n\n // 重新检查配置(这里假设配置可能会被外部更新)\n const updatedConfig = this.config.storage as any;\n if (updatedConfig.accessKeyId && updatedConfig.accessKeySecret && updatedConfig.bucket && updatedConfig.region) {\n logger.info('✅ [UniversalFileService] OSS配置加载完成');\n break;\n }\n\n if (i === maxRetries - 1) {\n throw new Error('OSS配置加载超时:缺少必需的配置项 (accessKeyId, accessKeySecret, bucket, region)');\n }\n\n logger.debug('等待OSS配置加载中... (' + (i + 1) + '/' + (maxRetries) + ')');\n }\n }\n }\n\n // 检查默认存储类型\n if (!this.config.defaultStorage) {\n this.config.defaultStorage = this.config.storage.type as any;\n }\n\n logger.info('✅ [UniversalFileService] 配置验证完成');\n }\n\n private async initializeStorageProviders(): Promise<void> {\n logger.info('📦 [UniversalFileService] 开始初始化存储提供者...');\n\n // 如果还没有注册任何存储提供者,先注册默认的\n if (this.storageProviders.size === 0) {\n await this.registerDefaultStorageProviders();\n }\n\n if (this.config.storageProviders) {\n for (const [type, config] of Object.entries(this.config.storageProviders)) {\n if (config && config.enabled) {\n const provider = this.storageProviders.get(type as StorageType);\n if (provider) {\n try {\n await provider.initialize(config);\n logger.info('✅ [UniversalFileService] 存储提供者初始化完成: ' + (type));\n } catch (error) {\n console.warn('⚠️ [UniversalFileService] 存储提供者初始化失败: ' + (type) + ':', error);\n // 如果默认存储提供者初始化失败,切换到本地存储\n // if (type === this.config.defaultStorage) {\n // console.warn('⚠️ [UniversalFileService] 默认存储提供者 ' + (type) + ' 初始化失败,切换到本地存储');\n // this.config.defaultStorage = 'local';\n // }\n }\n } else {\n console.warn('⚠️ [UniversalFileService] 存储提供者未注册: ' + (type));\n }\n }\n }\n }\n }\n\n private async registerDefaultStorageProviders(): Promise<void> {\n logger.info('📦 [UniversalFileService] 注册默认存储提供者...');\n\n // 根据配置注册相应的存储提供者\n try {\n if (this.config.storage) {\n if (this.config.storage.type === 'aliyun-oss' && this.config.storage.enabled) {\n const { AliyunOSSProvider } = await import('./providers/AliyunOSSProvider');\n const ossProvider = new AliyunOSSProvider();\n this.registerStorageProvider(ossProvider);\n logger.info('✅ [UniversalFileService] 阿里云OSS提供者注册成功');\n } else if (this.config.storage.type === 'local' && this.config.storage.enabled) {\n const { LocalStorageProvider } = await import('./providers/LocalStorageProvider');\n const localProvider = new LocalStorageProvider();\n this.registerStorageProvider(localProvider);\n logger.info('✅ [UniversalFileService] 本地存储提供者注册成功');\n }\n }\n\n // 如果没有注册任何提供者,注册本地存储作为后备\n if (this.storageProviders.size === 0) {\n const { LocalStorageProvider } = await import('./providers/LocalStorageProvider');\n const fallbackProvider = new LocalStorageProvider();\n this.registerStorageProvider(fallbackProvider);\n logger.info('✅ [UniversalFileService] 已注册备用本地存储提供者');\n }\n } catch (error) {\n console.warn('⚠️ [UniversalFileService] 注册默认存储提供者失败:', error);\n throw new Error('无法初始化存储提供者');\n }\n }\n\n private async initializeCDNProviders(): Promise<void> {\n // CDN 初始化暂时跳过,未来支持多个 CDN 提供者时实现\n if (this.config.cdn && this.config.cdn.enabled) {\n logger.info('✅ [UniversalFileService] CDN配置已启用: ' + (this.config.cdn.type));\n }\n }\n\n private async initializeFileProcessors(): Promise<void> {\n for (const processor of Array.from(this.fileProcessors.values())) {\n await processor.initialize();\n logger.info('✅ [UniversalFileService] 文件处理器初始化完成: ' + (processor.type));\n }\n }\n\n private async validateFile(file: File): Promise<void> {\n // 检查文件大小\n if (this.config.maxFileSize && file.size > this.config.maxFileSize) {\n throw new FileUploadError('文件大小超过限制: ' + (file.size) + ' > ' + (this.config.maxFileSize));\n }\n\n // 检查文件类型\n const mimeType = file.type || getMimeType(file.name);\n\n if (\n this.config.allowedMimeTypes &&\n this.config.allowedMimeTypes.length > 0 &&\n !this.config.allowedMimeTypes.includes(mimeType)\n ) {\n throw new FileUploadError('不支持的文件类型: ' + (mimeType));\n }\n }\n\n private async generateFileMetadata(\n fileId: string,\n fileInfo: UploadFileInfo\n ): Promise<FileMetadata> {\n const now = new Date();\n const mimeType = fileInfo.file.type || getMimeType(fileInfo.file.name);\n const extension = path.extname(fileInfo.file.name).toLowerCase();\n\n // 生成文件哈希(用于去重检测)\n const hash = await this.generateFileHash(fileInfo.file);\n\n return {\n id: fileId,\n originalName: fileInfo.file.name,\n storageName: (fileId) + (extension),\n size: fileInfo.file.size,\n mimeType,\n extension,\n hash,\n uploadTime: now,\n permission: fileInfo.permission || 'public',\n uploaderId: fileInfo.metadata?.uploadedBy || 'system',\n moduleId: fileInfo.moduleId,\n businessId: fileInfo.businessId,\n storageProvider: (this.config.defaultStorage || 'local') as StorageType,\n storagePath: '',\n accessCount: 0,\n metadata: fileInfo.metadata || {},\n };\n }\n\n private generateStoragePath(metadata: FileMetadata): string {\n const date = new Date();\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n\n return (metadata.moduleId) + '/' + (year) + '/' + (month) + '/' + (day) + '/' + (metadata.storageName);\n }\n\n private async generateFileHash(file: File): Promise<string> {\n const buffer = await file.arrayBuffer();\n const hash = createHash('sha256');\n hash.update(Buffer.from(buffer));\n return hash.digest('hex');\n }\n\n private async queueFileProcessing(metadata: FileMetadata, options: any): Promise<void> {\n if (!this.config.processors?.length || 0 > 0) {\n return;\n }\n\n const processor = this.fileProcessors.get(options.type);\n if (!processor) {\n console.warn('⚠️ [UniversalFileService] 文件处理器不存在: ' + (options.type));\n return;\n }\n\n if (this.processingQueue.length >= 1000) {\n throw new FileProcessingError('处理队列已满');\n }\n\n this.processingQueue.push({\n fileId: metadata.id,\n processor,\n inputPath: metadata.storagePath,\n outputPath: this.generateProcessedPath(metadata, options),\n options,\n });\n\n // 启动处理队列\n if (!this.isProcessingQueueRunning) {\n this.processFileQueue();\n }\n }\n\n private generateProcessedPath(metadata: FileMetadata, options: any): string {\n const basePath = metadata.storagePath;\n const extension = path.extname(basePath);\n const basename = basePath.replace(extension, '');\n\n return (basename) + '_processed' + (extension);\n }\n\n private async processFileQueue(): Promise<void> {\n if (this.isProcessingQueueRunning || this.processingQueue.length === 0) {\n return;\n }\n\n this.isProcessingQueueRunning = true;\n\n while (this.processingQueue.length > 0) {\n const task = this.processingQueue.shift();\n if (!task) break;\n\n try {\n this.emitFileEvent('processing:start', task.fileId);\n\n const result = await task.processor.process(task.inputPath, task.outputPath, task.options);\n\n if (result.success) {\n this.emitFileEvent('processing:complete', task.fileId, result);\n } else {\n this.emitFileEvent('processing:error', task.fileId, undefined, result.error);\n }\n } catch (error) {\n console.error('❌ [UniversalFileService] 文件处理失败: ' + (task.fileId) + ':', error);\n this.emitFileEvent(\n 'processing:error',\n task.fileId,\n undefined,\n error instanceof Error ? error.message : '处理失败'\n );\n }\n }\n\n this.isProcessingQueueRunning = false;\n }\n\n private cacheMetadata(metadata: FileMetadata): void {\n const expires = Date.now() + (this.config.cache?.metadataTTL || 3600) * 1000;\n this.metadataCache.set(metadata.id, { data: metadata, expires });\n }\n\n private clearMetadataCache(fileId: string): void {\n this.metadataCache.delete(fileId);\n }\n\n private emitFileEvent(type: string, fileId: string, data?: any, error?: string): void {\n const event: FileEvent = {\n type: type as any,\n fileId,\n timestamp: new Date(),\n data,\n error,\n };\n\n this.emit(type, event);\n this.emit('*', event); // 通用事件监听\n }\n\n // ============= 数据库操作私有方法 =============\n\n /**\n * 保存文件元数据到数据库 (通过持久化仓储)\n */\n private async saveFileMetadata(metadata: FileMetadata): Promise<void> {\n if (!this.config.persistence?.enabled || !this.config.persistence.repository) {\n logger.warn('⚠️ [UniversalFileService] 持久化未启用,跳过保存元数据');\n return;\n }\n\n try {\n await this.config.persistence.repository.save(metadata);\n logger.info('💾 [UniversalFileService] 文件元数据保存成功:', metadata.id);\n } catch (error) {\n console.error('❌ [UniversalFileService] 保存文件元数据失败:', error);\n throw new FileUploadError(\n '保存文件元数据失败: ' + (error instanceof Error ? error.message : '未知错误')\n );\n }\n }\n\n /**\n * 从数据库删除文件元数据 (通过持久化仓储)\n */\n private async deleteFileMetadata(fileId: string): Promise<void> {\n if (!this.config.persistence?.enabled || !this.config.persistence.repository) {\n return;\n }\n\n try {\n await this.config.persistence.repository.delete(fileId);\n logger.info('🗑️ [UniversalFileService] 文件元数据删除成功:', fileId);\n } catch (error) {\n console.error('❌ [UniversalFileService] 删除文件元数据失败:', error);\n throw new FileUploadError(\n '删除文件元数据失败: ' + (error instanceof Error ? error.message : '未知错误')\n );\n }\n }\n\n /**\n * 更新访问统计\n */\n private async updateAccessStats(fileId: string): Promise<void> {\n // 访问统计更新由数据库仓储实现决定\n // 这里只记录日志\n logger.info('📊 [UniversalFileService] 需要更新访问统计:', fileId);\n }\n\n /**\n * 检查文件访问权限\n */\n private async checkFileAccess(metadata: FileMetadata, userId?: string): Promise<void> {\n // 如果文件是公开的,允许访问\n if (metadata.permission === 'public') {\n return;\n }\n\n // 如果是私有文件,检查用户权限\n if (metadata.permission === 'private' && metadata.uploaderId !== userId) {\n throw new FileUploadError('无权限访问此文件');\n }\n\n // 如果是认证用户可访问,检查是否提供了 userId\n if (metadata.permission === 'authenticated' && !userId) {\n throw new FileUploadError('需要登录才能访问此文件');\n }\n }\n\n /**\n * 检查文件删除权限\n */\n private async checkFileDeleteAccess(metadata: FileMetadata, userId?: string): Promise<void> {\n // 只有上传者可以删除文件\n if (metadata.uploaderId !== userId) {\n throw new FileUploadError('无权限删除此文件');\n }\n }\n\n /**\n * 检查服务是否完全可用(包括存储提供者)\n */\n isFullyInitialized(): boolean {\n // 检查是否有可用的存储提供者\n const hasStorageProvider = Array.from(this.storageProviders.values()).some(provider =>\n provider.type === 'aliyun-oss' || provider.type === 'local'\n );\n\n return hasStorageProvider;\n }\n\n /**\n * 等待服务完全初始化(带超时)\n */\n async waitForInitialization(timeoutMs: number = 30000): Promise<void> {\n const startTime = Date.now();\n\n while (!this.isFullyInitialized()) {\n if (Date.now() - startTime > timeoutMs) {\n throw new Error('服务初始化超时 (' + (timeoutMs) + 'ms)');\n }\n\n // 等待100ms后重试\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n\n logger.info('✅ [UniversalFileService] 服务完全初始化就绪');\n }\n}\n"]}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkERAAB5VG_js = require('./chunk-ERAAB5VG.js');
|
|
4
|
+
var chunkFXQOXLDE_js = require('./chunk-FXQOXLDE.js');
|
|
5
|
+
var chunkZWQJSZEY_js = require('./chunk-ZWQJSZEY.js');
|
|
6
|
+
var React2 = require('react');
|
|
7
|
+
|
|
8
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
|
|
10
|
+
var React2__default = /*#__PURE__*/_interopDefault(React2);
|
|
11
|
+
|
|
12
|
+
var AiChatDialog = ({
|
|
13
|
+
open,
|
|
14
|
+
onOpenChange,
|
|
15
|
+
client,
|
|
16
|
+
title = "AI \u5BF9\u8BDD",
|
|
17
|
+
placeholder = "\u8F93\u5165\u4F60\u60F3\u54A8\u8BE2\u7684\u95EE\u9898...",
|
|
18
|
+
systemPrompt,
|
|
19
|
+
template,
|
|
20
|
+
templateVariables,
|
|
21
|
+
initialMessages,
|
|
22
|
+
requestOptions,
|
|
23
|
+
onResponse,
|
|
24
|
+
onError,
|
|
25
|
+
className,
|
|
26
|
+
contentClassName
|
|
27
|
+
}) => {
|
|
28
|
+
const { messages, sendMessage, isLoading, error } = chunkFXQOXLDE_js.useAiChat({
|
|
29
|
+
client,
|
|
30
|
+
systemPrompt,
|
|
31
|
+
template,
|
|
32
|
+
initialMessages
|
|
33
|
+
});
|
|
34
|
+
const [input, setInput] = React2.useState("");
|
|
35
|
+
const listRef = React2.useRef(null);
|
|
36
|
+
const hasMessages = messages.length > 0;
|
|
37
|
+
const helperText = React2.useMemo(() => {
|
|
38
|
+
return template ? "\u6A21\u677F\u5DF2\u542F\u7528\uFF0C\u652F\u6301 {{input}} \u53D8\u91CF\u3002" : "\u76F4\u63A5\u8F93\u5165\u5373\u53EF\u5F00\u59CB\u5BF9\u8BDD\u3002";
|
|
39
|
+
}, [template]);
|
|
40
|
+
React2.useEffect(() => {
|
|
41
|
+
if (!listRef.current) return;
|
|
42
|
+
listRef.current.scrollTop = listRef.current.scrollHeight;
|
|
43
|
+
}, [messages, open, isLoading]);
|
|
44
|
+
const handleSend = async () => {
|
|
45
|
+
const content = input.trim();
|
|
46
|
+
if (!content || isLoading) return;
|
|
47
|
+
setInput("");
|
|
48
|
+
try {
|
|
49
|
+
const response = await sendMessage(content, {
|
|
50
|
+
...requestOptions,
|
|
51
|
+
template,
|
|
52
|
+
variables: templateVariables
|
|
53
|
+
});
|
|
54
|
+
onResponse?.(response);
|
|
55
|
+
} catch (err) {
|
|
56
|
+
const nextError = err instanceof Error ? err : new Error(String(err));
|
|
57
|
+
onError?.(nextError);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const handleKeyDown = (event) => {
|
|
61
|
+
if (event.key === "Enter" && !event.shiftKey) {
|
|
62
|
+
event.preventDefault();
|
|
63
|
+
handleSend();
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
return /* @__PURE__ */ React2__default.default.createElement(chunkERAAB5VG_js.Dialog, { open, onOpenChange }, /* @__PURE__ */ React2__default.default.createElement(
|
|
67
|
+
chunkERAAB5VG_js.DialogContent,
|
|
68
|
+
{
|
|
69
|
+
className: chunkZWQJSZEY_js.cn(
|
|
70
|
+
"max-w-3xl border border-slate-200 bg-white p-0",
|
|
71
|
+
contentClassName
|
|
72
|
+
)
|
|
73
|
+
},
|
|
74
|
+
/* @__PURE__ */ React2__default.default.createElement("div", { className: chunkZWQJSZEY_js.cn("flex flex-col", className) }, /* @__PURE__ */ React2__default.default.createElement(chunkERAAB5VG_js.DialogHeader, { className: "border-b border-slate-100 px-6 py-4" }, /* @__PURE__ */ React2__default.default.createElement(chunkERAAB5VG_js.DialogTitle, { className: "text-base font-semibold text-slate-900" }, title)), /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex flex-1 flex-col gap-4 px-6 py-4" }, /* @__PURE__ */ React2__default.default.createElement(
|
|
75
|
+
"div",
|
|
76
|
+
{
|
|
77
|
+
ref: listRef,
|
|
78
|
+
className: "max-h-[60vh] min-h-[240px] overflow-y-auto rounded-xl border border-slate-100 bg-slate-50/60 p-4"
|
|
79
|
+
},
|
|
80
|
+
!hasMessages && /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex h-full flex-col items-center justify-center gap-2 text-sm text-slate-400" }, /* @__PURE__ */ React2__default.default.createElement("span", null, "\u6682\u65E0\u5BF9\u8BDD\u5185\u5BB9"), /* @__PURE__ */ React2__default.default.createElement("span", null, "\u8F93\u5165\u6D88\u606F\u5F00\u59CB\u4F53\u9A8C AI \u5BF9\u8BDD\u3002")),
|
|
81
|
+
/* @__PURE__ */ React2__default.default.createElement("div", { className: "flex flex-col gap-3" }, messages.map((message, index) => {
|
|
82
|
+
const isUser = message.role === "user";
|
|
83
|
+
return /* @__PURE__ */ React2__default.default.createElement(
|
|
84
|
+
"div",
|
|
85
|
+
{
|
|
86
|
+
key: `${message.role}-${index}`,
|
|
87
|
+
className: chunkZWQJSZEY_js.cn(
|
|
88
|
+
"max-w-[85%] whitespace-pre-wrap rounded-2xl px-4 py-2 text-sm leading-relaxed",
|
|
89
|
+
isUser ? "ml-auto bg-slate-900 text-white" : "mr-auto border border-slate-200 bg-white text-slate-800"
|
|
90
|
+
)
|
|
91
|
+
},
|
|
92
|
+
message.content
|
|
93
|
+
);
|
|
94
|
+
}), isLoading && /* @__PURE__ */ React2__default.default.createElement("div", { className: "mr-auto max-w-[70%] rounded-2xl border border-slate-200 bg-white px-4 py-2 text-sm text-slate-500" }, "AI \u6B63\u5728\u601D\u8003..."))
|
|
95
|
+
), /* @__PURE__ */ React2__default.default.createElement("div", { className: "rounded-xl border border-slate-100 bg-white p-4 shadow-sm" }, /* @__PURE__ */ React2__default.default.createElement(
|
|
96
|
+
"textarea",
|
|
97
|
+
{
|
|
98
|
+
value: input,
|
|
99
|
+
onChange: (event) => setInput(event.target.value),
|
|
100
|
+
onKeyDown: handleKeyDown,
|
|
101
|
+
placeholder,
|
|
102
|
+
className: "min-h-[96px] w-full resize-none rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-300"
|
|
103
|
+
}
|
|
104
|
+
), /* @__PURE__ */ React2__default.default.createElement("div", { className: "mt-3 flex flex-wrap items-center justify-between gap-3" }, /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-xs text-slate-400" }, helperText), /* @__PURE__ */ React2__default.default.createElement(chunkERAAB5VG_js.Button, { onClick: handleSend, disabled: !input.trim() || isLoading }, isLoading ? "\u53D1\u9001\u4E2D..." : "\u53D1\u9001")), error && /* @__PURE__ */ React2__default.default.createElement("div", { className: "mt-2 rounded-md border border-rose-200 bg-rose-50 px-3 py-2 text-xs text-rose-600" }, error.message || "\u5BF9\u8BDD\u51FA\u9519\uFF0C\u8BF7\u91CD\u8BD5\u3002"))))
|
|
105
|
+
));
|
|
106
|
+
};
|
|
107
|
+
var DEFAULT_AI_CONFIG = {
|
|
108
|
+
apiKey: "",
|
|
109
|
+
baseUrl: "https://api.openai.com/v1",
|
|
110
|
+
model: "gpt-3.5-turbo",
|
|
111
|
+
systemPrompt: "",
|
|
112
|
+
template: "{{input}}",
|
|
113
|
+
temperature: 0.7,
|
|
114
|
+
topP: 1,
|
|
115
|
+
maxTokens: 1024
|
|
116
|
+
};
|
|
117
|
+
var mergeConfig = (base, overrides, stored) => {
|
|
118
|
+
return {
|
|
119
|
+
...base,
|
|
120
|
+
...overrides ?? {},
|
|
121
|
+
...stored ?? {}
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
var AiConfigPage = ({
|
|
125
|
+
storageKey = "sa2kit-ai-config",
|
|
126
|
+
initialConfig,
|
|
127
|
+
title = "AI \u914D\u7F6E",
|
|
128
|
+
description = "\u914D\u7F6E API Key\u3001\u6A21\u578B\u4E0E\u63D0\u793A\u8BCD\u6A21\u677F\uFF0C\u7528\u4E8E AI \u5BF9\u8BDD\u80FD\u529B\u3002",
|
|
129
|
+
onSave,
|
|
130
|
+
onChange
|
|
131
|
+
}) => {
|
|
132
|
+
const baseConfig = React2.useMemo(
|
|
133
|
+
() => mergeConfig(DEFAULT_AI_CONFIG, initialConfig),
|
|
134
|
+
[initialConfig]
|
|
135
|
+
);
|
|
136
|
+
const [config, setConfig] = React2.useState(baseConfig);
|
|
137
|
+
const [status, setStatus] = React2.useState(null);
|
|
138
|
+
const [showApiKey, setShowApiKey] = React2.useState(false);
|
|
139
|
+
React2.useEffect(() => {
|
|
140
|
+
if (typeof window === "undefined") {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (!storageKey) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const storedRaw = localStorage.getItem(storageKey);
|
|
147
|
+
if (!storedRaw) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
const stored = JSON.parse(storedRaw);
|
|
152
|
+
setConfig(mergeConfig(DEFAULT_AI_CONFIG, initialConfig, stored));
|
|
153
|
+
} catch (error) {
|
|
154
|
+
console.warn("[AiConfigPage] Failed to parse stored config:", error);
|
|
155
|
+
}
|
|
156
|
+
}, [storageKey, initialConfig]);
|
|
157
|
+
const updateConfig = (updates) => {
|
|
158
|
+
setConfig((prev) => {
|
|
159
|
+
const next = { ...prev, ...updates };
|
|
160
|
+
onChange?.(next);
|
|
161
|
+
return next;
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
const updateNumber = (key, value) => {
|
|
165
|
+
const nextValue = Number(value);
|
|
166
|
+
if (Number.isNaN(nextValue)) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
updateConfig({ [key]: nextValue });
|
|
170
|
+
};
|
|
171
|
+
const saveConfig = () => {
|
|
172
|
+
if (typeof window !== "undefined" && storageKey) {
|
|
173
|
+
try {
|
|
174
|
+
localStorage.setItem(storageKey, JSON.stringify(config));
|
|
175
|
+
} catch (error) {
|
|
176
|
+
setStatus({ type: "error", text: "\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u6D4F\u89C8\u5668\u5B58\u50A8\u6743\u9650\u3002" });
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
setStatus({ type: "success", text: "\u5DF2\u4FDD\u5B58\u914D\u7F6E\u3002" });
|
|
181
|
+
onSave?.(config);
|
|
182
|
+
};
|
|
183
|
+
const resetConfig = () => {
|
|
184
|
+
const next = mergeConfig(DEFAULT_AI_CONFIG, initialConfig);
|
|
185
|
+
setConfig(next);
|
|
186
|
+
onChange?.(next);
|
|
187
|
+
if (typeof window !== "undefined" && storageKey) {
|
|
188
|
+
localStorage.removeItem(storageKey);
|
|
189
|
+
}
|
|
190
|
+
setStatus({ type: "success", text: "\u5DF2\u6062\u590D\u9ED8\u8BA4\u914D\u7F6E\u3002" });
|
|
191
|
+
};
|
|
192
|
+
return /* @__PURE__ */ React2__default.default.createElement("div", { className: "w-full rounded-2xl border border-slate-200 bg-white p-6 shadow-sm" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex flex-col gap-2 border-b border-slate-100 pb-4" }, /* @__PURE__ */ React2__default.default.createElement("h2", { className: "text-xl font-semibold text-slate-900" }, title), /* @__PURE__ */ React2__default.default.createElement("p", { className: "text-sm text-slate-500" }, description)), /* @__PURE__ */ React2__default.default.createElement("div", { className: "mt-6 grid gap-6" }, /* @__PURE__ */ React2__default.default.createElement("section", { className: "rounded-xl border border-slate-100 bg-slate-50/60 p-4" }, /* @__PURE__ */ React2__default.default.createElement("h3", { className: "text-sm font-semibold text-slate-700" }, "API \u4FE1\u606F"), /* @__PURE__ */ React2__default.default.createElement("div", { className: "mt-4 grid gap-4" }, /* @__PURE__ */ React2__default.default.createElement("div", null, /* @__PURE__ */ React2__default.default.createElement("label", { className: "text-xs font-medium text-slate-500" }, "Base URL"), /* @__PURE__ */ React2__default.default.createElement(
|
|
193
|
+
chunkERAAB5VG_js.Input,
|
|
194
|
+
{
|
|
195
|
+
value: config.baseUrl,
|
|
196
|
+
onChange: (event) => updateConfig({ baseUrl: event.target.value }),
|
|
197
|
+
placeholder: "https://api.openai.com/v1",
|
|
198
|
+
className: "mt-2"
|
|
199
|
+
}
|
|
200
|
+
)), /* @__PURE__ */ React2__default.default.createElement("div", null, /* @__PURE__ */ React2__default.default.createElement("label", { className: "text-xs font-medium text-slate-500" }, "API Key"), /* @__PURE__ */ React2__default.default.createElement("div", { className: "mt-2 flex gap-2" }, /* @__PURE__ */ React2__default.default.createElement(
|
|
201
|
+
chunkERAAB5VG_js.Input,
|
|
202
|
+
{
|
|
203
|
+
value: config.apiKey,
|
|
204
|
+
onChange: (event) => updateConfig({ apiKey: event.target.value }),
|
|
205
|
+
placeholder: "sk-...",
|
|
206
|
+
type: showApiKey ? "text" : "password"
|
|
207
|
+
}
|
|
208
|
+
), /* @__PURE__ */ React2__default.default.createElement(
|
|
209
|
+
chunkERAAB5VG_js.Button,
|
|
210
|
+
{
|
|
211
|
+
type: "button",
|
|
212
|
+
variant: "outline",
|
|
213
|
+
onClick: () => setShowApiKey((prev) => !prev)
|
|
214
|
+
},
|
|
215
|
+
showApiKey ? "\u9690\u85CF" : "\u663E\u793A"
|
|
216
|
+
))), /* @__PURE__ */ React2__default.default.createElement("div", null, /* @__PURE__ */ React2__default.default.createElement("label", { className: "text-xs font-medium text-slate-500" }, "\u6A21\u578B"), /* @__PURE__ */ React2__default.default.createElement(
|
|
217
|
+
chunkERAAB5VG_js.Input,
|
|
218
|
+
{
|
|
219
|
+
value: config.model,
|
|
220
|
+
onChange: (event) => updateConfig({ model: event.target.value }),
|
|
221
|
+
placeholder: "gpt-3.5-turbo",
|
|
222
|
+
className: "mt-2"
|
|
223
|
+
}
|
|
224
|
+
)))), /* @__PURE__ */ React2__default.default.createElement("section", { className: "rounded-xl border border-slate-100 bg-white p-4 shadow-sm" }, /* @__PURE__ */ React2__default.default.createElement("h3", { className: "text-sm font-semibold text-slate-700" }, "\u63D0\u793A\u8BCD\u4E0E\u4E0A\u4E0B\u6587"), /* @__PURE__ */ React2__default.default.createElement("div", { className: "mt-4 grid gap-4" }, /* @__PURE__ */ React2__default.default.createElement("div", null, /* @__PURE__ */ React2__default.default.createElement("label", { className: "text-xs font-medium text-slate-500" }, "\u7CFB\u7EDF\u63D0\u793A\u8BCD"), /* @__PURE__ */ React2__default.default.createElement(
|
|
225
|
+
"textarea",
|
|
226
|
+
{
|
|
227
|
+
value: config.systemPrompt,
|
|
228
|
+
onChange: (event) => updateConfig({ systemPrompt: event.target.value }),
|
|
229
|
+
placeholder: "\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684 AI \u52A9\u624B...",
|
|
230
|
+
className: "mt-2 min-h-[96px] w-full rounded-md border border-slate-200 bg-white px-3 py-2 text-sm text-slate-900 shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-300"
|
|
231
|
+
}
|
|
232
|
+
)), /* @__PURE__ */ React2__default.default.createElement("div", null, /* @__PURE__ */ React2__default.default.createElement("label", { className: "text-xs font-medium text-slate-500" }, "\u63D0\u793A\u8BCD\u6A21\u677F"), /* @__PURE__ */ React2__default.default.createElement(
|
|
233
|
+
"textarea",
|
|
234
|
+
{
|
|
235
|
+
value: config.template,
|
|
236
|
+
onChange: (event) => updateConfig({ template: event.target.value }),
|
|
237
|
+
placeholder: "\u8BF7\u56DE\u7B54\uFF1A{{input}}",
|
|
238
|
+
className: "mt-2 min-h-[96px] w-full rounded-md border border-slate-200 bg-white px-3 py-2 text-sm text-slate-900 shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-300"
|
|
239
|
+
}
|
|
240
|
+
), /* @__PURE__ */ React2__default.default.createElement("p", { className: "mt-2 text-xs text-slate-400" }, "\u652F\u6301\u53D8\u91CF\u63D2\u5165\uFF1A", /* @__PURE__ */ React2__default.default.createElement("code", { className: "rounded bg-slate-100 px-1" }, "{{input}}"))))), /* @__PURE__ */ React2__default.default.createElement("section", { className: "rounded-xl border border-slate-100 bg-slate-50/60 p-4" }, /* @__PURE__ */ React2__default.default.createElement("h3", { className: "text-sm font-semibold text-slate-700" }, "\u6A21\u578B\u53C2\u6570"), /* @__PURE__ */ React2__default.default.createElement("div", { className: "mt-4 grid gap-4 md:grid-cols-3" }, /* @__PURE__ */ React2__default.default.createElement("div", null, /* @__PURE__ */ React2__default.default.createElement("label", { className: "text-xs font-medium text-slate-500" }, "Temperature"), /* @__PURE__ */ React2__default.default.createElement(
|
|
241
|
+
chunkERAAB5VG_js.Input,
|
|
242
|
+
{
|
|
243
|
+
type: "number",
|
|
244
|
+
value: config.temperature,
|
|
245
|
+
onChange: (event) => updateNumber("temperature", event.target.value),
|
|
246
|
+
className: "mt-2"
|
|
247
|
+
}
|
|
248
|
+
)), /* @__PURE__ */ React2__default.default.createElement("div", null, /* @__PURE__ */ React2__default.default.createElement("label", { className: "text-xs font-medium text-slate-500" }, "Top P"), /* @__PURE__ */ React2__default.default.createElement(
|
|
249
|
+
chunkERAAB5VG_js.Input,
|
|
250
|
+
{
|
|
251
|
+
type: "number",
|
|
252
|
+
value: config.topP,
|
|
253
|
+
onChange: (event) => updateNumber("topP", event.target.value),
|
|
254
|
+
className: "mt-2"
|
|
255
|
+
}
|
|
256
|
+
)), /* @__PURE__ */ React2__default.default.createElement("div", null, /* @__PURE__ */ React2__default.default.createElement("label", { className: "text-xs font-medium text-slate-500" }, "Max Tokens"), /* @__PURE__ */ React2__default.default.createElement(
|
|
257
|
+
chunkERAAB5VG_js.Input,
|
|
258
|
+
{
|
|
259
|
+
type: "number",
|
|
260
|
+
value: config.maxTokens,
|
|
261
|
+
onChange: (event) => updateNumber("maxTokens", event.target.value),
|
|
262
|
+
className: "mt-2"
|
|
263
|
+
}
|
|
264
|
+
)))), /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex flex-wrap items-center gap-3" }, /* @__PURE__ */ React2__default.default.createElement(chunkERAAB5VG_js.Button, { onClick: saveConfig }, "\u4FDD\u5B58\u914D\u7F6E"), /* @__PURE__ */ React2__default.default.createElement(chunkERAAB5VG_js.Button, { variant: "outline", onClick: resetConfig }, "\u6062\u590D\u9ED8\u8BA4"), status && /* @__PURE__ */ React2__default.default.createElement(
|
|
265
|
+
"span",
|
|
266
|
+
{
|
|
267
|
+
className: chunkZWQJSZEY_js.cn(
|
|
268
|
+
"text-xs",
|
|
269
|
+
status.type === "success" ? "text-emerald-600" : "text-rose-600"
|
|
270
|
+
)
|
|
271
|
+
},
|
|
272
|
+
status.text
|
|
273
|
+
))));
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
exports.AiChatDialog = AiChatDialog;
|
|
277
|
+
exports.AiConfigPage = AiConfigPage;
|
|
278
|
+
//# sourceMappingURL=chunk-37M6NZIF.js.map
|
|
279
|
+
//# sourceMappingURL=chunk-37M6NZIF.js.map
|