sa2kit 1.6.57 → 1.6.59

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.
Files changed (147) hide show
  1. package/dist/AliyunOSSProvider-KSYW2IOG.js +15 -0
  2. package/dist/{AliyunOSSProvider-2FARPAQD.js.map → AliyunOSSProvider-KSYW2IOG.js.map} +1 -1
  3. package/dist/AliyunOSSProvider-TBK3G7YK.mjs +6 -0
  4. package/dist/{AliyunOSSProvider-UMVGVBDJ.mjs.map → AliyunOSSProvider-TBK3G7YK.mjs.map} +1 -1
  5. package/dist/LocalStorageProvider-2DGYRQAB.mjs +6 -0
  6. package/dist/{LocalStorageProvider-PYOHETJV.mjs.map → LocalStorageProvider-2DGYRQAB.mjs.map} +1 -1
  7. package/dist/LocalStorageProvider-SSRW3ZJW.js +15 -0
  8. package/dist/{LocalStorageProvider-JQF5WK5H.js.map → LocalStorageProvider-SSRW3ZJW.js.map} +1 -1
  9. package/dist/UniversalFileService-336GFY6N.mjs +6 -0
  10. package/dist/{UniversalFileService-TNYKO6JN.mjs.map → UniversalFileService-336GFY6N.mjs.map} +1 -1
  11. package/dist/UniversalFileService-J6ET6KZK.js +15 -0
  12. package/dist/{UniversalFileService-RBV6EN5J.js.map → UniversalFileService-J6ET6KZK.js.map} +1 -1
  13. package/dist/calendar/index.js +11 -11
  14. package/dist/calendar/index.mjs +4 -4
  15. package/dist/chunk-25OFOKNF.js +171 -0
  16. package/dist/chunk-25OFOKNF.js.map +1 -0
  17. package/dist/chunk-3DXPQ4YV.mjs +165 -0
  18. package/dist/chunk-3DXPQ4YV.mjs.map +1 -0
  19. package/dist/{chunk-4VJQZSPU.mjs → chunk-3NHAT7D4.mjs} +3 -4
  20. package/dist/chunk-3NHAT7D4.mjs.map +1 -0
  21. package/dist/{chunk-3JW4X3AC.mjs → chunk-622Y6LTH.mjs} +3 -3
  22. package/dist/{chunk-3JW4X3AC.mjs.map → chunk-622Y6LTH.mjs.map} +1 -1
  23. package/dist/{chunk-HYZ5C6FY.mjs → chunk-7CMGQX3S.mjs} +1199 -1995
  24. package/dist/chunk-7CMGQX3S.mjs.map +1 -0
  25. package/dist/chunk-CIVO4R6N.mjs +37 -0
  26. package/dist/chunk-CIVO4R6N.mjs.map +1 -0
  27. package/dist/{chunk-6BJ76BYC.mjs → chunk-EGJPS7OL.mjs} +3 -3
  28. package/dist/{chunk-6BJ76BYC.mjs.map → chunk-EGJPS7OL.mjs.map} +1 -1
  29. package/dist/{chunk-UR5TU4MW.mjs → chunk-FVDPGX6A.mjs} +3 -3
  30. package/dist/{chunk-UR5TU4MW.mjs.map → chunk-FVDPGX6A.mjs.map} +1 -1
  31. package/dist/chunk-HDMIOOZY.mjs +546 -0
  32. package/dist/chunk-HDMIOOZY.mjs.map +1 -0
  33. package/dist/{chunk-MZKATHB7.js → chunk-HHVDOIPV.js} +4 -4
  34. package/dist/{chunk-MZKATHB7.js.map → chunk-HHVDOIPV.js.map} +1 -1
  35. package/dist/chunk-HJ6MH7J7.js +552 -0
  36. package/dist/chunk-HJ6MH7J7.js.map +1 -0
  37. package/dist/chunk-KH6RQ4J5.js +28 -0
  38. package/dist/chunk-KH6RQ4J5.js.map +1 -0
  39. package/dist/{chunk-53WLQ22S.js → chunk-LJGJPAQ4.js} +6 -6
  40. package/dist/{chunk-53WLQ22S.js.map → chunk-LJGJPAQ4.js.map} +1 -1
  41. package/dist/{chunk-35CXIK5Y.js → chunk-NCOXT7SK.js} +11 -11
  42. package/dist/{chunk-35CXIK5Y.js.map → chunk-NCOXT7SK.js.map} +1 -1
  43. package/dist/chunk-NZZZUMMX.mjs +784 -0
  44. package/dist/chunk-NZZZUMMX.mjs.map +1 -0
  45. package/dist/{chunk-OBIPI4GU.mjs → chunk-OFYBMMWT.mjs} +4 -4
  46. package/dist/{chunk-OBIPI4GU.mjs.map → chunk-OFYBMMWT.mjs.map} +1 -1
  47. package/dist/chunk-Q5EDCKQA.js +336 -0
  48. package/dist/chunk-Q5EDCKQA.js.map +1 -0
  49. package/dist/{chunk-U7AQC2Z7.js → chunk-SKCMZYSQ.js} +1203 -2001
  50. package/dist/chunk-SKCMZYSQ.js.map +1 -0
  51. package/dist/{chunk-6NMIKAE7.mjs → chunk-SNBILYSH.mjs} +5 -5
  52. package/dist/{chunk-6NMIKAE7.mjs.map → chunk-SNBILYSH.mjs.map} +1 -1
  53. package/dist/{chunk-IPY26RQH.js → chunk-UVHPCLP6.js} +5 -5
  54. package/dist/{chunk-IPY26RQH.js.map → chunk-UVHPCLP6.js.map} +1 -1
  55. package/dist/{chunk-V6BXO6ZS.mjs → chunk-UZB4IO3T.mjs} +835 -38
  56. package/dist/chunk-UZB4IO3T.mjs.map +1 -0
  57. package/dist/{chunk-W2NCOORK.js → chunk-WK3HTUID.js} +951 -145
  58. package/dist/chunk-WK3HTUID.js.map +1 -0
  59. package/dist/chunk-YMS6BPXS.js +807 -0
  60. package/dist/chunk-YMS6BPXS.js.map +1 -0
  61. package/dist/chunk-YOTQG4NP.mjs +314 -0
  62. package/dist/chunk-YOTQG4NP.mjs.map +1 -0
  63. package/dist/chunk-ZGVB35L2.mjs +25 -0
  64. package/dist/chunk-ZGVB35L2.mjs.map +1 -0
  65. package/dist/chunk-ZRAW3HXA.js +43 -0
  66. package/dist/chunk-ZRAW3HXA.js.map +1 -0
  67. package/dist/{chunk-4XXIBWCO.js → chunk-ZRWED7Q6.js} +66 -66
  68. package/dist/{chunk-4XXIBWCO.js.map → chunk-ZRWED7Q6.js.map} +1 -1
  69. package/dist/{chunk-DVENFCQY.js → chunk-ZWQJSZEY.js} +4 -5
  70. package/dist/chunk-ZWQJSZEY.js.map +1 -0
  71. package/dist/components/index.js +104 -104
  72. package/dist/components/index.mjs +4 -4
  73. package/dist/index.js +146 -148
  74. package/dist/index.js.map +1 -1
  75. package/dist/index.mjs +8 -11
  76. package/dist/index.mjs.map +1 -1
  77. package/dist/logger/index.js +7 -7
  78. package/dist/logger/index.mjs +1 -4
  79. package/dist/mikuFusionGame/index.js +4 -4
  80. package/dist/mikuFusionGame/index.mjs +3 -3
  81. package/dist/portfolio/index.js +10 -10
  82. package/dist/portfolio/index.mjs +5 -5
  83. package/dist/showmasterpiece/db/index.js +42 -42
  84. package/dist/showmasterpiece/db/index.mjs +1 -1
  85. package/dist/showmasterpiece/index.js +143 -144
  86. package/dist/showmasterpiece/index.js.map +1 -1
  87. package/dist/showmasterpiece/index.mjs +7 -9
  88. package/dist/showmasterpiece/index.mjs.map +1 -1
  89. package/dist/showmasterpiece/logic/index.d.mts +10 -1
  90. package/dist/showmasterpiece/logic/index.d.ts +10 -1
  91. package/dist/showmasterpiece/logic/index.js +19 -19
  92. package/dist/showmasterpiece/logic/index.mjs +2 -2
  93. package/dist/showmasterpiece/server/index.js +42 -42
  94. package/dist/showmasterpiece/server/index.mjs +1 -1
  95. package/dist/showmasterpiece/ui/web/index.js +34 -34
  96. package/dist/showmasterpiece/ui/web/index.mjs +6 -6
  97. package/dist/universalExport/server/index.js +2 -4
  98. package/dist/universalExport/server/index.js.map +1 -1
  99. package/dist/universalExport/server/index.mjs +1 -3
  100. package/dist/universalExport/server/index.mjs.map +1 -1
  101. package/dist/universalFile/index.js +6 -9
  102. package/dist/universalFile/index.js.map +1 -1
  103. package/dist/universalFile/index.mjs +1 -5
  104. package/dist/universalFile/index.mjs.map +1 -1
  105. package/dist/universalFile/server/index.js +31 -64
  106. package/dist/universalFile/server/index.js.map +1 -1
  107. package/dist/universalFile/server/index.mjs +7 -42
  108. package/dist/universalFile/server/index.mjs.map +1 -1
  109. package/dist/utils/index.js +11 -11
  110. package/dist/utils/index.mjs +2 -2
  111. package/package.json +1 -1
  112. package/dist/AliyunOSSProvider-2FARPAQD.js +0 -15
  113. package/dist/AliyunOSSProvider-UMVGVBDJ.mjs +0 -9
  114. package/dist/LocalStorageProvider-JQF5WK5H.js +0 -15
  115. package/dist/LocalStorageProvider-PYOHETJV.mjs +0 -9
  116. package/dist/UniversalFileService-RBV6EN5J.js +0 -15
  117. package/dist/UniversalFileService-TNYKO6JN.mjs +0 -9
  118. package/dist/chunk-4NFOSCM6.js +0 -34
  119. package/dist/chunk-4NFOSCM6.js.map +0 -1
  120. package/dist/chunk-4VJQZSPU.mjs.map +0 -1
  121. package/dist/chunk-6AHYPPUP.js +0 -344
  122. package/dist/chunk-6AHYPPUP.js.map +0 -1
  123. package/dist/chunk-76V7EKBX.mjs +0 -796
  124. package/dist/chunk-76V7EKBX.mjs.map +0 -1
  125. package/dist/chunk-ACLOJXXE.js +0 -195
  126. package/dist/chunk-ACLOJXXE.js.map +0 -1
  127. package/dist/chunk-AEXPAH7Z.mjs +0 -32
  128. package/dist/chunk-AEXPAH7Z.mjs.map +0 -1
  129. package/dist/chunk-CFGX3EKK.js +0 -560
  130. package/dist/chunk-CFGX3EKK.js.map +0 -1
  131. package/dist/chunk-D2HXMGXS.js +0 -46
  132. package/dist/chunk-D2HXMGXS.js.map +0 -1
  133. package/dist/chunk-DVENFCQY.js.map +0 -1
  134. package/dist/chunk-HYZ5C6FY.mjs.map +0 -1
  135. package/dist/chunk-K7WNCB4V.mjs +0 -554
  136. package/dist/chunk-K7WNCB4V.mjs.map +0 -1
  137. package/dist/chunk-L4ZYBFB2.mjs +0 -44
  138. package/dist/chunk-L4ZYBFB2.mjs.map +0 -1
  139. package/dist/chunk-M4HGHTIC.js +0 -820
  140. package/dist/chunk-M4HGHTIC.js.map +0 -1
  141. package/dist/chunk-PXWDQFWV.mjs +0 -192
  142. package/dist/chunk-PXWDQFWV.mjs.map +0 -1
  143. package/dist/chunk-U7AQC2Z7.js.map +0 -1
  144. package/dist/chunk-V6BXO6ZS.mjs.map +0 -1
  145. package/dist/chunk-VTGPHE4Z.mjs +0 -322
  146. package/dist/chunk-VTGPHE4Z.mjs.map +0 -1
  147. package/dist/chunk-W2NCOORK.js.map +0 -1
@@ -0,0 +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"]}
@@ -0,0 +1,314 @@
1
+ import { StorageProviderError } from './chunk-ZGVB35L2.mjs';
2
+ import { createLogger } from './chunk-3DXPQ4YV.mjs';
3
+ import { promises, existsSync, createWriteStream, createReadStream } from 'fs';
4
+ import * as path from 'path';
5
+ import { pipeline } from 'stream/promises';
6
+
7
+ var logger = createLogger("LocalStorageProvider");
8
+ var LocalStorageProvider = class {
9
+ constructor() {
10
+ this.type = "local";
11
+ this.config = null;
12
+ this.isInitialized = false;
13
+ }
14
+ /**
15
+ * 初始化存储提供者
16
+ */
17
+ async initialize(config) {
18
+ if (config.type !== "local") {
19
+ throw new StorageProviderError("\u914D\u7F6E\u7C7B\u578B\u4E0D\u5339\u914D\uFF1A\u671F\u671B local");
20
+ }
21
+ this.config = config;
22
+ logger.info("\u{1F4C2} [LocalStorageProvider] \u521D\u59CB\u5316\u672C\u5730\u5B58\u50A8\uFF0C\u6839\u76EE\u5F55: " + this.config.rootPath);
23
+ try {
24
+ await this.ensureDirectoryExists(this.config.rootPath);
25
+ await this.validateDirectoryAccess(this.config.rootPath);
26
+ this.isInitialized = true;
27
+ logger.info("\u2705 [LocalStorageProvider] \u672C\u5730\u5B58\u50A8\u521D\u59CB\u5316\u5B8C\u6210");
28
+ } catch (error) {
29
+ logger.error("\u274C [LocalStorageProvider] \u672C\u5730\u5B58\u50A8\u521D\u59CB\u5316\u5931\u8D25:", error);
30
+ throw new StorageProviderError(`\u672C\u5730\u5B58\u50A8\u521D\u59CB\u5316\u5931\u8D25`);
31
+ }
32
+ }
33
+ /**
34
+ * 上传文件
35
+ */
36
+ async upload(fileInfo, filePath) {
37
+ this.ensureInitialized();
38
+ const startTime = Date.now();
39
+ logger.info("\u{1F4E4} [LocalStorageProvider] \u5F00\u59CB\u4E0A\u4F20\u6587\u4EF6: " + filePath);
40
+ try {
41
+ const fullPath = this.getFullPath(filePath);
42
+ await this.ensureDirectoryExists(path.dirname(fullPath));
43
+ const buffer = Buffer.from(await fileInfo.file.arrayBuffer());
44
+ await promises.writeFile(fullPath, buffer);
45
+ const stats = await promises.stat(fullPath);
46
+ if (stats.size !== fileInfo.file.size) {
47
+ throw new StorageProviderError(
48
+ "\u6587\u4EF6\u5927\u5C0F\u4E0D\u5339\u914D: \u671F\u671B " + fileInfo.file.size + ", \u5B9E\u9645 " + stats.size
49
+ );
50
+ }
51
+ const accessUrl = this.generateAccessUrl(filePath);
52
+ const uploadTime = Date.now() - startTime;
53
+ logger.info("\u2705 [LocalStorageProvider] \u6587\u4EF6\u4E0A\u4F20\u5B8C\u6210: " + filePath + ", \u8017\u65F6: " + uploadTime + "ms");
54
+ return {
55
+ success: true,
56
+ path: filePath,
57
+ url: accessUrl,
58
+ size: stats.size,
59
+ data: {
60
+ fullPath,
61
+ uploadTime
62
+ }
63
+ };
64
+ } catch (error) {
65
+ logger.error("\u274C [LocalStorageProvider] \u6587\u4EF6\u4E0A\u4F20\u5931\u8D25: " + filePath + ":", error);
66
+ return {
67
+ success: false,
68
+ error: error instanceof Error ? error.message : "\u4E0A\u4F20\u5931\u8D25"
69
+ };
70
+ }
71
+ }
72
+ /**
73
+ * 下载文件
74
+ */
75
+ async download(path2) {
76
+ this.ensureInitialized();
77
+ logger.info("\u{1F4E5} [LocalStorageProvider] \u5F00\u59CB\u4E0B\u8F7D\u6587\u4EF6: " + path2);
78
+ try {
79
+ const fullPath = this.getFullPath(path2);
80
+ if (!existsSync(fullPath)) {
81
+ throw new StorageProviderError("\u6587\u4EF6\u4E0D\u5B58\u5728: " + path2);
82
+ }
83
+ const buffer = await promises.readFile(fullPath);
84
+ logger.info("\u2705 [LocalStorageProvider] \u6587\u4EF6\u4E0B\u8F7D\u5B8C\u6210: " + path2 + ", \u5927\u5C0F: " + buffer.length);
85
+ return buffer;
86
+ } catch (error) {
87
+ logger.error("\u274C [LocalStorageProvider] \u6587\u4EF6\u4E0B\u8F7D\u5931\u8D25: " + path2 + ":", error);
88
+ throw new StorageProviderError(
89
+ "\u6587\u4EF6\u4E0B\u8F7D\u5931\u8D25: " + (error instanceof Error ? error.message : "\u672A\u77E5\u9519\u8BEF")
90
+ );
91
+ }
92
+ }
93
+ /**
94
+ * 删除文件
95
+ */
96
+ async delete(path2) {
97
+ this.ensureInitialized();
98
+ logger.info("\u{1F5D1}\uFE0F [LocalStorageProvider] \u5F00\u59CB\u5220\u9664\u6587\u4EF6: " + path2);
99
+ try {
100
+ const fullPath = this.getFullPath(path2);
101
+ if (!existsSync(fullPath)) {
102
+ logger.warn("\u26A0\uFE0F [LocalStorageProvider] \u6587\u4EF6\u4E0D\u5B58\u5728: " + path2);
103
+ return {
104
+ success: true,
105
+ // 文件不存在也视为删除成功
106
+ data: { reason: "file_not_exists" }
107
+ };
108
+ }
109
+ await promises.unlink(fullPath);
110
+ logger.info("\u2705 [LocalStorageProvider] \u6587\u4EF6\u5220\u9664\u5B8C\u6210: " + path2);
111
+ return {
112
+ success: true,
113
+ data: { deletedPath: fullPath }
114
+ };
115
+ } catch (error) {
116
+ logger.error("\u274C [LocalStorageProvider] \u6587\u4EF6\u5220\u9664\u5931\u8D25: " + path2 + ":", error);
117
+ return {
118
+ success: false,
119
+ error: error instanceof Error ? error.message : "\u5220\u9664\u5931\u8D25"
120
+ };
121
+ }
122
+ }
123
+ /**
124
+ * 获取文件信息
125
+ */
126
+ async getFileInfo(path2) {
127
+ this.ensureInitialized();
128
+ try {
129
+ const fullPath = this.getFullPath(path2);
130
+ if (!existsSync(fullPath)) {
131
+ return {
132
+ success: false,
133
+ error: "\u6587\u4EF6\u4E0D\u5B58\u5728"
134
+ };
135
+ }
136
+ const stats = await promises.stat(fullPath);
137
+ return {
138
+ success: true,
139
+ size: stats.size,
140
+ data: {
141
+ fullPath,
142
+ size: stats.size,
143
+ mtime: stats.mtime,
144
+ ctime: stats.ctime,
145
+ isFile: stats.isFile(),
146
+ isDirectory: stats.isDirectory()
147
+ }
148
+ };
149
+ } catch (error) {
150
+ return {
151
+ success: false,
152
+ error: error instanceof Error ? error.message : "\u83B7\u53D6\u6587\u4EF6\u4FE1\u606F\u5931\u8D25"
153
+ };
154
+ }
155
+ }
156
+ /**
157
+ * 生成访问URL
158
+ */
159
+ async getAccessUrl(path2, _expiresIn) {
160
+ this.ensureInitialized();
161
+ return this.generateAccessUrl(path2);
162
+ }
163
+ /**
164
+ * 生成预签名上传URL
165
+ */
166
+ async getUploadUrl(path2, _expiresIn) {
167
+ this.ensureInitialized();
168
+ logger.warn(`\u26A0\uFE0F [LocalStorageProvider] \u672C\u5730\u5B58\u50A8\u4E0D\u652F\u6301\u9884\u7B7E\u540D\u4E0A\u4F20URL`);
169
+ return this.generateAccessUrl(path2);
170
+ }
171
+ /**
172
+ * 检查文件是否存在
173
+ */
174
+ async exists(path2) {
175
+ this.ensureInitialized();
176
+ try {
177
+ const fullPath = this.getFullPath(path2);
178
+ return existsSync(fullPath);
179
+ } catch {
180
+ return false;
181
+ }
182
+ }
183
+ /**
184
+ * 列出文件
185
+ */
186
+ async list(prefix, maxKeys) {
187
+ this.ensureInitialized();
188
+ try {
189
+ const fullPrefix = this.getFullPath(prefix);
190
+ const baseDir = path.dirname(fullPrefix);
191
+ const filePattern = path.basename(fullPrefix);
192
+ if (!existsSync(baseDir)) {
193
+ return [];
194
+ }
195
+ const entries = await promises.readdir(baseDir, { withFileTypes: true });
196
+ let files = entries.filter((entry) => entry.isFile()).map((entry) => entry.name).filter((name) => name.startsWith(filePattern)).map((name) => path.join(path.dirname(prefix), name));
197
+ if (maxKeys && maxKeys > 0) {
198
+ files = files.slice(0, maxKeys);
199
+ }
200
+ return files;
201
+ } catch (error) {
202
+ logger.error("\u274C [LocalStorageProvider] \u5217\u51FA\u6587\u4EF6\u5931\u8D25: " + prefix + ":", error);
203
+ return [];
204
+ }
205
+ }
206
+ // ============= 私有方法 =============
207
+ /**
208
+ * 确保已初始化
209
+ */
210
+ ensureInitialized() {
211
+ if (!this.isInitialized || !this.config) {
212
+ throw new StorageProviderError("\u5B58\u50A8\u63D0\u4F9B\u8005\u672A\u521D\u59CB\u5316");
213
+ }
214
+ }
215
+ /**
216
+ * 获取完整文件路径
217
+ */
218
+ getFullPath(relativePath) {
219
+ if (!this.config) {
220
+ throw new StorageProviderError("\u5B58\u50A8\u63D0\u4F9B\u8005\u672A\u521D\u59CB\u5316");
221
+ }
222
+ const normalizedPath = path.normalize(relativePath);
223
+ if (normalizedPath.includes("..")) {
224
+ throw new StorageProviderError("\u975E\u6CD5\u8DEF\u5F84\uFF1A\u4E0D\u5141\u8BB8\u4F7F\u7528\u7236\u76EE\u5F55\u5F15\u7528");
225
+ }
226
+ return path.join(this.config.rootPath, normalizedPath);
227
+ }
228
+ /**
229
+ * 生成访问URL
230
+ */
231
+ generateAccessUrl(relativePath) {
232
+ if (!this.config) {
233
+ throw new StorageProviderError("\u5B58\u50A8\u63D0\u4F9B\u8005\u672A\u521D\u59CB\u5316");
234
+ }
235
+ const urlPath = relativePath.replace(/\\/g, "/");
236
+ const normalizedUrlPath = urlPath.startsWith("/") ? urlPath : "/" + urlPath;
237
+ return this.config.baseUrl + normalizedUrlPath;
238
+ }
239
+ /**
240
+ * 确保目录存在
241
+ */
242
+ async ensureDirectoryExists(dirPath) {
243
+ try {
244
+ await promises.mkdir(dirPath, { recursive: true });
245
+ } catch (error) {
246
+ if (error instanceof Error && "code" in error && error.code !== "EEXIST") {
247
+ throw error;
248
+ }
249
+ }
250
+ }
251
+ /**
252
+ * 验证目录访问权限
253
+ */
254
+ async validateDirectoryAccess(dirPath) {
255
+ try {
256
+ await promises.access(dirPath, promises.constants.R_OK | promises.constants.W_OK);
257
+ } catch (error) {
258
+ throw new StorageProviderError(
259
+ "\u76EE\u5F55\u8BBF\u95EE\u6743\u9650\u4E0D\u8DB3: " + dirPath + ", " + (error instanceof Error ? error.message : "\u672A\u77E5\u9519\u8BEF")
260
+ );
261
+ }
262
+ }
263
+ /**
264
+ * 流式上传大文件(可选实现)
265
+ */
266
+ async uploadStream(readableStream, filePath) {
267
+ this.ensureInitialized();
268
+ const startTime = Date.now();
269
+ logger.info("\u{1F4E4} [LocalStorageProvider] \u5F00\u59CB\u6D41\u5F0F\u4E0A\u4F20\u6587\u4EF6: " + filePath);
270
+ try {
271
+ const fullPath = this.getFullPath(filePath);
272
+ await this.ensureDirectoryExists(path.dirname(fullPath));
273
+ const writeStream = createWriteStream(fullPath);
274
+ await pipeline(readableStream, writeStream);
275
+ const stats = await promises.stat(fullPath);
276
+ const accessUrl = this.generateAccessUrl(filePath);
277
+ const uploadTime = Date.now() - startTime;
278
+ logger.info(
279
+ "\u2705 [LocalStorageProvider] \u6D41\u5F0F\u4E0A\u4F20\u5B8C\u6210: " + filePath + ", \u5927\u5C0F: " + stats.size + ", \u8017\u65F6: " + uploadTime + "ms"
280
+ );
281
+ return {
282
+ success: true,
283
+ path: filePath,
284
+ url: accessUrl,
285
+ size: stats.size,
286
+ data: {
287
+ fullPath,
288
+ uploadTime
289
+ }
290
+ };
291
+ } catch (error) {
292
+ logger.error("\u274C [LocalStorageProvider] \u6D41\u5F0F\u4E0A\u4F20\u5931\u8D25: " + filePath + ":", error);
293
+ return {
294
+ success: false,
295
+ error: error instanceof Error ? error.message : "\u6D41\u5F0F\u4E0A\u4F20\u5931\u8D25"
296
+ };
297
+ }
298
+ }
299
+ /**
300
+ * 流式下载大文件(可选实现)
301
+ */
302
+ createDownloadStream(path2) {
303
+ this.ensureInitialized();
304
+ const fullPath = this.getFullPath(path2);
305
+ if (!existsSync(fullPath)) {
306
+ throw new StorageProviderError("\u6587\u4EF6\u4E0D\u5B58\u5728: " + path2);
307
+ }
308
+ return createReadStream(fullPath);
309
+ }
310
+ };
311
+
312
+ export { LocalStorageProvider };
313
+ //# sourceMappingURL=chunk-YOTQG4NP.mjs.map
314
+ //# sourceMappingURL=chunk-YOTQG4NP.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/universalFile/server/providers/LocalStorageProvider.ts"],"names":["fs","path"],"mappings":";;;;;;AAqBA,IAAM,MAAA,GAAS,aAAa,sBAAsB,CAAA;AAK3C,IAAM,uBAAN,MAAuD;AAAA,EAAvD,WAAA,GAAA;AACL,IAAA,IAAA,CAAS,IAAA,GAAoB,OAAA;AAE7B,IAAA,IAAA,CAAQ,MAAA,GAAoC,IAAA;AAC5C,IAAA,IAAA,CAAQ,aAAA,GAAgB,KAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKxB,MAAM,WAAW,MAAA,EAAsC;AACrD,IAAA,IAAI,MAAA,CAAO,SAAS,OAAA,EAAS;AAC3B,MAAA,MAAM,IAAI,qBAAqB,oEAAkB,CAAA;AAAA,IACnD;AAEA,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAEd,IAAA,MAAA,CAAO,IAAA,CAAK,uGAAA,GAA6C,IAAA,CAAK,MAAA,CAAO,QAAS,CAAA;AAE9E,IAAA,IAAI;AAEF,MAAA,MAAM,IAAA,CAAK,qBAAA,CAAsB,IAAA,CAAK,MAAA,CAAO,QAAQ,CAAA;AAGrD,MAAA,MAAM,IAAA,CAAK,uBAAA,CAAwB,IAAA,CAAK,MAAA,CAAO,QAAQ,CAAA;AAEvD,MAAA,IAAA,CAAK,aAAA,GAAgB,IAAA;AACrB,MAAA,MAAA,CAAO,KAAK,sFAAoC,CAAA;AAAA,IAClD,SAAS,KAAA,EAAO;AACd,MAAA,MAAA,CAAO,KAAA,CAAM,yFAAuC,KAAK,CAAA;AACzD,MAAA,MAAM,IAAI,qBAAqB,CAAA,sDAAA,CAAW,CAAA;AAAA,IAC5C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAA,CAAO,QAAA,EAA0B,QAAA,EAA0C;AAC/E,IAAA,IAAA,CAAK,iBAAA,EAAkB;AAEvB,IAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAC3B,IAAA,MAAA,CAAO,IAAA,CAAK,4EAAwC,QAAS,CAAA;AAE7D,IAAA,IAAI;AAEF,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,WAAA,CAAY,QAAQ,CAAA;AAG1C,MAAA,MAAM,IAAA,CAAK,qBAAA,CAA2B,IAAA,CAAA,OAAA,CAAQ,QAAQ,CAAC,CAAA;AAGvD,MAAA,MAAM,SAAS,MAAA,CAAO,IAAA,CAAK,MAAM,QAAA,CAAS,IAAA,CAAK,aAAa,CAAA;AAG5D,MAAA,MAAMA,QAAA,CAAG,SAAA,CAAU,QAAA,EAAU,MAAM,CAAA;AAGnC,MAAA,MAAM,KAAA,GAAQ,MAAMA,QAAA,CAAG,IAAA,CAAK,QAAQ,CAAA;AAEpC,MAAA,IAAI,KAAA,CAAM,IAAA,KAAS,QAAA,CAAS,IAAA,CAAK,IAAA,EAAM;AACrC,QAAA,MAAM,IAAI,oBAAA;AAAA,UACR,2DAAA,GAAkB,QAAA,CAAS,IAAA,CAAK,IAAA,GAAQ,oBAAW,KAAA,CAAM;AAAA,SAC3D;AAAA,MACF;AAGA,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,iBAAA,CAAkB,QAAQ,CAAA;AAEjD,MAAA,MAAM,UAAA,GAAa,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA;AAChC,MAAA,MAAA,CAAO,IAAA,CAAK,sEAAA,GAAuC,QAAA,GAAY,kBAAA,GAAY,aAAc,IAAI,CAAA;AAE7F,MAAA,OAAO;AAAA,QACL,OAAA,EAAS,IAAA;AAAA,QACT,IAAA,EAAM,QAAA;AAAA,QACN,GAAA,EAAK,SAAA;AAAA,QACL,MAAM,KAAA,CAAM,IAAA;AAAA,QACZ,IAAA,EAAM;AAAA,UACJ,QAAA;AAAA,UACA;AAAA;AACF,OACF;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,MAAA,CAAO,KAAA,CAAM,sEAAA,GAAuC,QAAA,GAAY,GAAA,EAAK,KAAK,CAAA;AAE1E,MAAA,OAAO;AAAA,QACL,OAAA,EAAS,KAAA;AAAA,QACT,KAAA,EAAO,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU;AAAA,OAClD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAASC,KAAAA,EAA+B;AAC5C,IAAA,IAAA,CAAK,iBAAA,EAAkB;AAEvB,IAAA,MAAA,CAAO,IAAA,CAAK,4EAAwCA,KAAK,CAAA;AAEzD,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,WAAA,CAAYA,KAAI,CAAA;AAGtC,MAAA,IAAI,CAAC,UAAA,CAAW,QAAQ,CAAA,EAAG;AACzB,QAAA,MAAM,IAAI,oBAAA,CAAqB,kCAAA,GAAaA,KAAK,CAAA;AAAA,MACnD;AAGA,MAAA,MAAM,MAAA,GAAS,MAAMD,QAAA,CAAG,QAAA,CAAS,QAAQ,CAAA;AAEzC,MAAA,MAAA,CAAO,IAAA,CAAK,sEAAA,GAAuCC,KAAAA,GAAQ,kBAAA,GAAY,OAAO,MAAO,CAAA;AAErF,MAAA,OAAO,MAAA;AAAA,IACT,SAAS,KAAA,EAAO;AACd,MAAA,MAAA,CAAO,KAAA,CAAM,sEAAA,GAAuCA,KAAAA,GAAQ,GAAA,EAAK,KAAK,CAAA;AACtE,MAAA,MAAM,IAAI,oBAAA;AAAA,QACR,wCAAA,IAAc,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,0BAAA;AAAA,OACzD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAOA,KAAAA,EAAsC;AACjD,IAAA,IAAA,CAAK,iBAAA,EAAkB;AAEvB,IAAA,MAAA,CAAO,IAAA,CAAK,kFAAyCA,KAAK,CAAA;AAE1D,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,WAAA,CAAYA,KAAI,CAAA;AAGtC,MAAA,IAAI,CAAC,UAAA,CAAW,QAAQ,CAAA,EAAG;AACzB,QAAA,MAAA,CAAO,IAAA,CAAK,yEAAuCA,KAAK,CAAA;AACxD,QAAA,OAAO;AAAA,UACL,OAAA,EAAS,IAAA;AAAA;AAAA,UACT,IAAA,EAAM,EAAE,MAAA,EAAQ,iBAAA;AAAkB,SACpC;AAAA,MACF;AAGA,MAAA,MAAMD,QAAA,CAAG,OAAO,QAAQ,CAAA;AAExB,MAAA,MAAA,CAAO,IAAA,CAAK,yEAAuCC,KAAK,CAAA;AAExD,MAAA,OAAO;AAAA,QACL,OAAA,EAAS,IAAA;AAAA,QACT,IAAA,EAAM,EAAE,WAAA,EAAa,QAAA;AAAS,OAChC;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,MAAA,CAAO,KAAA,CAAM,sEAAA,GAAuCA,KAAAA,GAAQ,GAAA,EAAK,KAAK,CAAA;AAEtE,MAAA,OAAO;AAAA,QACL,OAAA,EAAS,KAAA;AAAA,QACT,KAAA,EAAO,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU;AAAA,OAClD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAYA,KAAAA,EAAsC;AACtD,IAAA,IAAA,CAAK,iBAAA,EAAkB;AAEvB,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,WAAA,CAAYA,KAAI,CAAA;AAEtC,MAAA,IAAI,CAAC,UAAA,CAAW,QAAQ,CAAA,EAAG;AACzB,QAAA,OAAO;AAAA,UACL,OAAA,EAAS,KAAA;AAAA,UACT,KAAA,EAAO;AAAA,SACT;AAAA,MACF;AAEA,MAAA,MAAM,KAAA,GAAQ,MAAMD,QAAA,CAAG,IAAA,CAAK,QAAQ,CAAA;AAEpC,MAAA,OAAO;AAAA,QACL,OAAA,EAAS,IAAA;AAAA,QACT,MAAM,KAAA,CAAM,IAAA;AAAA,QACZ,IAAA,EAAM;AAAA,UACJ,QAAA;AAAA,UACA,MAAM,KAAA,CAAM,IAAA;AAAA,UACZ,OAAO,KAAA,CAAM,KAAA;AAAA,UACb,OAAO,KAAA,CAAM,KAAA;AAAA,UACb,MAAA,EAAQ,MAAM,MAAA,EAAO;AAAA,UACrB,WAAA,EAAa,MAAM,WAAA;AAAY;AACjC,OACF;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,OAAO;AAAA,QACL,OAAA,EAAS,KAAA;AAAA,QACT,KAAA,EAAO,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU;AAAA,OAClD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAA,CAAaC,KAAAA,EAAc,UAAA,EAAsC;AACrE,IAAA,IAAA,CAAK,iBAAA,EAAkB;AAGvB,IAAA,OAAO,IAAA,CAAK,kBAAkBA,KAAI,CAAA;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAA,CAAaA,KAAAA,EAAc,UAAA,EAAsC;AACrE,IAAA,IAAA,CAAK,iBAAA,EAAkB;AAGvB,IAAA,MAAA,CAAO,KAAK,CAAA,+GAAA,CAA2C,CAAA;AACvD,IAAA,OAAO,IAAA,CAAK,kBAAkBA,KAAI,CAAA;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAOA,KAAAA,EAAgC;AAC3C,IAAA,IAAA,CAAK,iBAAA,EAAkB;AAEvB,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,WAAA,CAAYA,KAAI,CAAA;AACtC,MAAA,OAAO,WAAW,QAAQ,CAAA;AAAA,IAC5B,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IAAA,CAAK,MAAA,EAAgB,OAAA,EAAqC;AAC9D,IAAA,IAAA,CAAK,iBAAA,EAAkB;AAEvB,IAAA,IAAI;AACF,MAAA,MAAM,UAAA,GAAa,IAAA,CAAK,WAAA,CAAY,MAAM,CAAA;AAC1C,MAAA,MAAM,OAAA,GAAe,aAAQ,UAAU,CAAA;AACvC,MAAA,MAAM,WAAA,GAAmB,cAAS,UAAU,CAAA;AAE5C,MAAA,IAAI,CAAC,UAAA,CAAW,OAAO,CAAA,EAAG;AACxB,QAAA,OAAO,EAAC;AAAA,MACV;AAEA,MAAA,MAAM,OAAA,GAAU,MAAMD,QAAA,CAAG,OAAA,CAAQ,SAAS,EAAE,aAAA,EAAe,MAAM,CAAA;AACjE,MAAA,IAAI,KAAA,GAAQ,OAAA,CACT,MAAA,CAAO,CAAC,KAAA,KAAU,KAAA,CAAM,MAAA,EAAQ,CAAA,CAChC,GAAA,CAAI,CAAC,KAAA,KAAU,MAAM,IAAI,CAAA,CACzB,MAAA,CAAO,CAAC,IAAA,KAAS,IAAA,CAAK,UAAA,CAAW,WAAW,CAAC,CAAA,CAC7C,GAAA,CAAI,CAAC,IAAA,KAAc,IAAA,CAAA,IAAA,CAAU,IAAA,CAAA,OAAA,CAAQ,MAAM,CAAA,EAAG,IAAI,CAAC,CAAA;AAGtD,MAAA,IAAI,OAAA,IAAW,UAAU,CAAA,EAAG;AAC1B,QAAA,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,CAAA,EAAG,OAAO,CAAA;AAAA,MAChC;AAEA,MAAA,OAAO,KAAA;AAAA,IACT,SAAS,KAAA,EAAO;AACd,MAAA,MAAA,CAAO,KAAA,CAAM,sEAAA,GAAuC,MAAA,GAAU,GAAA,EAAK,KAAK,CAAA;AACxE,MAAA,OAAO,EAAC;AAAA,IACV;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,iBAAA,GAA0B;AAChC,IAAA,IAAI,CAAC,IAAA,CAAK,aAAA,IAAiB,CAAC,KAAK,MAAA,EAAQ;AACvC,MAAA,MAAM,IAAI,qBAAqB,wDAAW,CAAA;AAAA,IAC5C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,YAAY,YAAA,EAA8B;AAChD,IAAA,IAAI,CAAC,KAAK,MAAA,EAAQ;AAChB,MAAA,MAAM,IAAI,qBAAqB,wDAAW,CAAA;AAAA,IAC5C;AAGA,IAAA,MAAM,cAAA,GAAsB,eAAU,YAAY,CAAA;AAClD,IAAA,IAAI,cAAA,CAAe,QAAA,CAAS,IAAI,CAAA,EAAG;AACjC,MAAA,MAAM,IAAI,qBAAqB,4FAAiB,CAAA;AAAA,IAClD;AAEA,IAAA,OAAY,IAAA,CAAA,IAAA,CAAK,IAAA,CAAK,MAAA,CAAO,QAAA,EAAU,cAAc,CAAA;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAkB,YAAA,EAA8B;AACtD,IAAA,IAAI,CAAC,KAAK,MAAA,EAAQ;AAChB,MAAA,MAAM,IAAI,qBAAqB,wDAAW,CAAA;AAAA,IAC5C;AAGA,IAAA,MAAM,OAAA,GAAU,YAAA,CAAa,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA;AAG/C,IAAA,MAAM,oBAAoB,OAAA,CAAQ,UAAA,CAAW,GAAG,CAAA,GAAI,UAAU,GAAA,GAAO,OAAA;AAErE,IAAA,OAAQ,IAAA,CAAK,OAAO,OAAA,GAAY,iBAAA;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,sBAAsB,OAAA,EAAgC;AAClE,IAAA,IAAI;AACF,MAAA,MAAMA,SAAG,KAAA,CAAM,OAAA,EAAS,EAAE,SAAA,EAAW,MAAM,CAAA;AAAA,IAC7C,SAAS,KAAA,EAAO;AAEd,MAAA,IAAI,iBAAiB,KAAA,IAAS,MAAA,IAAU,KAAA,IAAS,KAAA,CAAM,SAAS,QAAA,EAAU;AACxE,QAAA,MAAM,KAAA;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,wBAAwB,OAAA,EAAgC;AACpE,IAAA,IAAI;AAEF,MAAA,MAAMA,QAAA,CAAG,OAAO,OAAA,EAASA,QAAA,CAAG,UAAU,IAAA,GAAOA,QAAA,CAAG,UAAU,IAAI,CAAA;AAAA,IAChE,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,IAAI,oBAAA;AAAA,QACR,uDAAgB,OAAA,GAAW,IAAA,IAAQ,KAAA,YAAiB,KAAA,GAAQ,MAAM,OAAA,GAAU,0BAAA;AAAA,OAC9E;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAA,CACJ,cAAA,EACA,QAAA,EACwB;AACxB,IAAA,IAAA,CAAK,iBAAA,EAAkB;AAEvB,IAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAC3B,IAAA,MAAA,CAAO,IAAA,CAAK,wFAA0C,QAAS,CAAA;AAE/D,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,WAAA,CAAY,QAAQ,CAAA;AAG1C,MAAA,MAAM,IAAA,CAAK,qBAAA,CAA2B,IAAA,CAAA,OAAA,CAAQ,QAAQ,CAAC,CAAA;AAGvD,MAAA,MAAM,WAAA,GAAc,kBAAkB,QAAQ,CAAA;AAG9C,MAAA,MAAM,QAAA,CAAS,gBAAgB,WAAW,CAAA;AAG1C,MAAA,MAAM,KAAA,GAAQ,MAAMA,QAAA,CAAG,IAAA,CAAK,QAAQ,CAAA;AAGpC,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,iBAAA,CAAkB,QAAQ,CAAA;AAEjD,MAAA,MAAM,UAAA,GAAa,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA;AAChC,MAAA,MAAA,CAAO,IAAA;AAAA,QACL,yEAAuC,QAAA,GAAY,kBAAA,GAAY,KAAA,CAAM,IAAA,GAAQ,qBAAY,UAAA,GAAc;AAAA,OACzG;AAEA,MAAA,OAAO;AAAA,QACL,OAAA,EAAS,IAAA;AAAA,QACT,IAAA,EAAM,QAAA;AAAA,QACN,GAAA,EAAK,SAAA;AAAA,QACL,MAAM,KAAA,CAAM,IAAA;AAAA,QACZ,IAAA,EAAM;AAAA,UACJ,QAAA;AAAA,UACA;AAAA;AACF,OACF;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,MAAA,CAAO,KAAA,CAAM,sEAAA,GAAuC,QAAA,GAAY,GAAA,EAAK,KAAK,CAAA;AAE1E,MAAA,OAAO;AAAA,QACL,OAAA,EAAS,KAAA;AAAA,QACT,KAAA,EAAO,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU;AAAA,OAClD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,qBAAqBC,KAAAA,EAAqC;AACxD,IAAA,IAAA,CAAK,iBAAA,EAAkB;AAEvB,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,WAAA,CAAYA,KAAI,CAAA;AAEtC,IAAA,IAAI,CAAC,UAAA,CAAW,QAAQ,CAAA,EAAG;AACzB,MAAA,MAAM,IAAI,oBAAA,CAAqB,kCAAA,GAAaA,KAAK,CAAA;AAAA,IACnD;AAEA,IAAA,OAAO,iBAAiB,QAAQ,CAAA;AAAA,EAClC;AACF","file":"chunk-YOTQG4NP.mjs","sourcesContent":["/**\n * 本地存储提供者实现\n */\n\nimport { promises as fs } from 'fs';\nimport { existsSync, createReadStream, createWriteStream } from 'fs';\nimport * as path from 'path';\nimport { pipeline } from 'stream/promises';\nimport { createLogger } from '../../../logger';\n\nimport type {\n IStorageProvider,\n StorageConfig,\n LocalStorageConfig,\n StorageResult,\n UploadFileInfo,\n StorageType,\n} from '../types';\n\nimport { StorageProviderError } from '../types';\n\nconst logger = createLogger('LocalStorageProvider');\n\n/**\n * 本地文件系统存储提供者\n */\nexport class LocalStorageProvider implements IStorageProvider {\n readonly type: StorageType = 'local';\n\n private config: LocalStorageConfig | null = null;\n private isInitialized = false;\n\n /**\n * 初始化存储提供者\n */\n async initialize(config: StorageConfig): Promise<void> {\n if (config.type !== 'local') {\n throw new StorageProviderError('配置类型不匹配:期望 local');\n }\n\n this.config = config as LocalStorageConfig;\n\n logger.info('📂 [LocalStorageProvider] 初始化本地存储,根目录: ' + (this.config.rootPath));\n\n try {\n // 确保根目录存在\n await this.ensureDirectoryExists(this.config.rootPath);\n\n // 验证目录访问权限\n await this.validateDirectoryAccess(this.config.rootPath);\n\n this.isInitialized = true;\n logger.info('✅ [LocalStorageProvider] 本地存储初始化完成');\n } catch (error) {\n logger.error('❌ [LocalStorageProvider] 本地存储初始化失败:', error);\n throw new StorageProviderError(`本地存储初始化失败`);\n }\n }\n\n /**\n * 上传文件\n */\n async upload(fileInfo: UploadFileInfo, filePath: string): Promise<StorageResult> {\n this.ensureInitialized();\n\n const startTime = Date.now();\n logger.info('📤 [LocalStorageProvider] 开始上传文件: ' + (filePath));\n\n try {\n // 生成完整文件路径\n const fullPath = this.getFullPath(filePath);\n\n // 确保父目录存在\n await this.ensureDirectoryExists(path.dirname(fullPath));\n\n // 将File对象转换为Buffer\n const buffer = Buffer.from(await fileInfo.file.arrayBuffer());\n\n // 写入文件\n await fs.writeFile(fullPath, buffer);\n\n // 验证文件写入\n const stats = await fs.stat(fullPath);\n\n if (stats.size !== fileInfo.file.size) {\n throw new StorageProviderError(\n '文件大小不匹配: 期望 ' + (fileInfo.file.size) + ', 实际 ' + (stats.size)\n );\n }\n\n // 生成访问URL\n const accessUrl = this.generateAccessUrl(filePath);\n\n const uploadTime = Date.now() - startTime;\n logger.info('✅ [LocalStorageProvider] 文件上传完成: ' + (filePath) + ', 耗时: ' + (uploadTime) + 'ms');\n\n return {\n success: true,\n path: filePath,\n url: accessUrl,\n size: stats.size,\n data: {\n fullPath,\n uploadTime,\n },\n };\n } catch (error) {\n logger.error('❌ [LocalStorageProvider] 文件上传失败: ' + (filePath) + ':', error);\n\n return {\n success: false,\n error: error instanceof Error ? error.message : '上传失败',\n };\n }\n }\n\n /**\n * 下载文件\n */\n async download(path: string): Promise<Buffer> {\n this.ensureInitialized();\n\n logger.info('📥 [LocalStorageProvider] 开始下载文件: ' + (path));\n\n try {\n const fullPath = this.getFullPath(path);\n\n // 检查文件是否存在\n if (!existsSync(fullPath)) {\n throw new StorageProviderError('文件不存在: ' + (path));\n }\n\n // 读取文件\n const buffer = await fs.readFile(fullPath);\n\n logger.info('✅ [LocalStorageProvider] 文件下载完成: ' + (path) + ', 大小: ' + (buffer.length));\n\n return buffer;\n } catch (error) {\n logger.error('❌ [LocalStorageProvider] 文件下载失败: ' + (path) + ':', error);\n throw new StorageProviderError(\n '文件下载失败: ' + (error instanceof Error ? error.message : '未知错误')\n );\n }\n }\n\n /**\n * 删除文件\n */\n async delete(path: string): Promise<StorageResult> {\n this.ensureInitialized();\n\n logger.info('🗑️ [LocalStorageProvider] 开始删除文件: ' + (path));\n\n try {\n const fullPath = this.getFullPath(path);\n\n // 检查文件是否存在\n if (!existsSync(fullPath)) {\n logger.warn('⚠️ [LocalStorageProvider] 文件不存在: ' + (path));\n return {\n success: true, // 文件不存在也视为删除成功\n data: { reason: 'file_not_exists' },\n };\n }\n\n // 删除文件\n await fs.unlink(fullPath);\n\n logger.info('✅ [LocalStorageProvider] 文件删除完成: ' + (path));\n\n return {\n success: true,\n data: { deletedPath: fullPath },\n };\n } catch (error) {\n logger.error('❌ [LocalStorageProvider] 文件删除失败: ' + (path) + ':', error);\n\n return {\n success: false,\n error: error instanceof Error ? error.message : '删除失败',\n };\n }\n }\n\n /**\n * 获取文件信息\n */\n async getFileInfo(path: string): Promise<StorageResult> {\n this.ensureInitialized();\n\n try {\n const fullPath = this.getFullPath(path);\n\n if (!existsSync(fullPath)) {\n return {\n success: false,\n error: '文件不存在',\n };\n }\n\n const stats = await fs.stat(fullPath);\n\n return {\n success: true,\n size: stats.size,\n data: {\n fullPath,\n size: stats.size,\n mtime: stats.mtime,\n ctime: stats.ctime,\n isFile: stats.isFile(),\n isDirectory: stats.isDirectory(),\n },\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : '获取文件信息失败',\n };\n }\n }\n\n /**\n * 生成访问URL\n */\n async getAccessUrl(path: string, _expiresIn?: number): Promise<string> {\n this.ensureInitialized();\n\n // 本地存储不支持过期时间,忽略expiresIn参数\n return this.generateAccessUrl(path);\n }\n\n /**\n * 生成预签名上传URL\n */\n async getUploadUrl(path: string, _expiresIn?: number): Promise<string> {\n this.ensureInitialized();\n\n // 本地存储不支持预签名上传,返回普通访问URL\n logger.warn(`⚠️ [LocalStorageProvider] 本地存储不支持预签名上传URL`);\n return this.generateAccessUrl(path);\n }\n\n /**\n * 检查文件是否存在\n */\n async exists(path: string): Promise<boolean> {\n this.ensureInitialized();\n\n try {\n const fullPath = this.getFullPath(path);\n return existsSync(fullPath);\n } catch {\n return false;\n }\n }\n\n /**\n * 列出文件\n */\n async list(prefix: string, maxKeys?: number): Promise<string[]> {\n this.ensureInitialized();\n\n try {\n const fullPrefix = this.getFullPath(prefix);\n const baseDir = path.dirname(fullPrefix);\n const filePattern = path.basename(fullPrefix);\n\n if (!existsSync(baseDir)) {\n return [];\n }\n\n const entries = await fs.readdir(baseDir, { withFileTypes: true });\n let files = entries\n .filter((entry) => entry.isFile())\n .map((entry) => entry.name)\n .filter((name) => name.startsWith(filePattern))\n .map((name) => path.join(path.dirname(prefix), name));\n\n // 限制返回数量\n if (maxKeys && maxKeys > 0) {\n files = files.slice(0, maxKeys);\n }\n\n return files;\n } catch (error) {\n logger.error('❌ [LocalStorageProvider] 列出文件失败: ' + (prefix) + ':', error);\n return [];\n }\n }\n\n // ============= 私有方法 =============\n\n /**\n * 确保已初始化\n */\n private ensureInitialized(): void {\n if (!this.isInitialized || !this.config) {\n throw new StorageProviderError('存储提供者未初始化');\n }\n }\n\n /**\n * 获取完整文件路径\n */\n private getFullPath(relativePath: string): string {\n if (!this.config) {\n throw new StorageProviderError('存储提供者未初始化');\n }\n\n // 防止路径遍历攻击\n const normalizedPath = path.normalize(relativePath);\n if (normalizedPath.includes('..')) {\n throw new StorageProviderError('非法路径:不允许使用父目录引用');\n }\n\n return path.join(this.config.rootPath, normalizedPath);\n }\n\n /**\n * 生成访问URL\n */\n private generateAccessUrl(relativePath: string): string {\n if (!this.config) {\n throw new StorageProviderError('存储提供者未初始化');\n }\n\n // 规范化路径分隔符为URL格式\n const urlPath = relativePath.replace(/\\\\/g, '/');\n\n // 确保URL路径以/开头\n const normalizedUrlPath = urlPath.startsWith('/') ? urlPath : '/' + (urlPath);\n\n return (this.config.baseUrl) + (normalizedUrlPath);\n }\n\n /**\n * 确保目录存在\n */\n private async ensureDirectoryExists(dirPath: string): Promise<void> {\n try {\n await fs.mkdir(dirPath, { recursive: true });\n } catch (error) {\n // 如果目录已存在,忽略错误\n if (error instanceof Error && 'code' in error && error.code !== 'EEXIST') {\n throw error;\n }\n }\n }\n\n /**\n * 验证目录访问权限\n */\n private async validateDirectoryAccess(dirPath: string): Promise<void> {\n try {\n // 检查读写权限\n await fs.access(dirPath, fs.constants.R_OK | fs.constants.W_OK);\n } catch (error) {\n throw new StorageProviderError(\n '目录访问权限不足: ' + (dirPath) + ', ' + (error instanceof Error ? error.message : '未知错误')\n );\n }\n }\n\n /**\n * 流式上传大文件(可选实现)\n */\n async uploadStream(\n readableStream: NodeJS.ReadableStream,\n filePath: string\n ): Promise<StorageResult> {\n this.ensureInitialized();\n\n const startTime = Date.now();\n logger.info('📤 [LocalStorageProvider] 开始流式上传文件: ' + (filePath));\n\n try {\n const fullPath = this.getFullPath(filePath);\n\n // 确保父目录存在\n await this.ensureDirectoryExists(path.dirname(fullPath));\n\n // 创建写入流\n const writeStream = createWriteStream(fullPath);\n\n // 使用pipeline进行流式传输\n await pipeline(readableStream, writeStream);\n\n // 获取文件信息\n const stats = await fs.stat(fullPath);\n\n // 生成访问URL\n const accessUrl = this.generateAccessUrl(filePath);\n\n const uploadTime = Date.now() - startTime;\n logger.info(\n '✅ [LocalStorageProvider] 流式上传完成: ' + (filePath) + ', 大小: ' + (stats.size) + ', 耗时: ' + (uploadTime) + 'ms'\n );\n\n return {\n success: true,\n path: filePath,\n url: accessUrl,\n size: stats.size,\n data: {\n fullPath,\n uploadTime,\n },\n };\n } catch (error) {\n logger.error('❌ [LocalStorageProvider] 流式上传失败: ' + (filePath) + ':', error);\n\n return {\n success: false,\n error: error instanceof Error ? error.message : '流式上传失败',\n };\n }\n }\n\n /**\n * 流式下载大文件(可选实现)\n */\n createDownloadStream(path: string): NodeJS.ReadableStream {\n this.ensureInitialized();\n\n const fullPath = this.getFullPath(path);\n\n if (!existsSync(fullPath)) {\n throw new StorageProviderError('文件不存在: ' + (path));\n }\n\n return createReadStream(fullPath);\n }\n}\n\n"]}
@@ -0,0 +1,25 @@
1
+ // src/universalFile/server/types.ts
2
+ var FileServiceError = class extends Error {
3
+ constructor(message, code, details) {
4
+ super(message);
5
+ this.code = code;
6
+ this.details = details;
7
+ this.name = "FileServiceError";
8
+ }
9
+ };
10
+ var StorageProviderError = class extends FileServiceError {
11
+ constructor(message, details) {
12
+ super(message, "STORAGE_PROVIDER_ERROR", details);
13
+ this.name = "StorageProviderError";
14
+ }
15
+ };
16
+ var CDNProviderError = class extends FileServiceError {
17
+ constructor(message, details) {
18
+ super(message, "CDN_PROVIDER_ERROR", details);
19
+ this.name = "CDNProviderError";
20
+ }
21
+ };
22
+
23
+ export { CDNProviderError, StorageProviderError };
24
+ //# sourceMappingURL=chunk-ZGVB35L2.mjs.map
25
+ //# sourceMappingURL=chunk-ZGVB35L2.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/universalFile/server/types.ts"],"names":[],"mappings":";AA8cO,IAAM,gBAAA,GAAN,cAA+B,KAAA,CAAM;AAAA,EAC1C,WAAA,CACE,OAAA,EACgB,IAAA,EACA,OAAA,EAChB;AACA,IAAA,KAAA,CAAM,OAAO,CAAA;AAHG,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AACA,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAGhB,IAAA,IAAA,CAAK,IAAA,GAAO,kBAAA;AAAA,EACd;AACF,CAAA;AAmBO,IAAM,oBAAA,GAAN,cAAmC,gBAAA,CAAiB;AAAA,EACzD,WAAA,CAAY,SAAiB,OAAA,EAA+B;AAC1D,IAAA,KAAA,CAAM,OAAA,EAAS,0BAA0B,OAAO,CAAA;AAChD,IAAA,IAAA,CAAK,IAAA,GAAO,sBAAA;AAAA,EACd;AACF;AAGO,IAAM,gBAAA,GAAN,cAA+B,gBAAA,CAAiB;AAAA,EACrD,WAAA,CAAY,SAAiB,OAAA,EAA+B;AAC1D,IAAA,KAAA,CAAM,OAAA,EAAS,sBAAsB,OAAO,CAAA;AAC5C,IAAA,IAAA,CAAK,IAAA,GAAO,kBAAA;AAAA,EACd;AACF","file":"chunk-ZGVB35L2.mjs","sourcesContent":["/**\n * UniversalFile Server 端类型定义\n */\n\nimport type {\n StorageType as _StorageType,\n CDNType as _CDNType,\n ProcessorType as _ProcessorType,\n FileMetadata,\n UploadStatus,\n AccessPermission,\n UploadFileInfo as _UploadFileInfo,\n ProcessingOptions as _ProcessingOptions,\n} from '../types';\n\n// Re-export client types for server use\nexport type StorageType = _StorageType;\nexport type CDNType = _CDNType;\nexport type ProcessorType = _ProcessorType;\nexport type UploadFileInfo = _UploadFileInfo;\nexport type ProcessingOptions = _ProcessingOptions;\n\n// ============= Provider 接口 =============\n\n/** 存储提供者接口 */\nexport interface IStorageProvider {\n /** 提供者类型 */\n readonly type: StorageType;\n\n /** 初始化 */\n initialize(config: StorageConfig): Promise<void>;\n\n /** 上传文件 */\n upload(fileInfo: UploadFileInfo, path: string): Promise<StorageResult>;\n\n /** 下载文件 */\n download(path: string): Promise<Buffer>;\n\n /** 删除文件 */\n delete(path: string): Promise<StorageResult>;\n\n /** 获取文件信息 */\n getFileInfo(path: string): Promise<StorageResult>;\n\n /** 生成访问URL */\n getAccessUrl(path: string, expiresIn?: number): Promise<string>;\n\n /** 生成预签名上传URL */\n getUploadUrl(path: string, expiresIn?: number): Promise<string>;\n\n /** 检查文件是否存在 */\n exists(path: string): Promise<boolean>;\n\n /** 列出文件 */\n list(prefix: string, maxKeys?: number): Promise<string[]>;\n}\n\n/** CDN 提供者接口 */\nexport interface ICDNProvider {\n /** 提供者类型 */\n readonly type: CDNType;\n\n /** 初始化 */\n initialize(config: CDNConfig): Promise<void>;\n\n /** 生成CDN URL */\n generateUrl(originalUrl: string): Promise<string>;\n\n /** 刷新缓存 */\n refreshCache(urls: string[]): Promise<CDNResult>;\n\n /** 预热缓存 */\n preheatCache(urls: string[]): Promise<CDNResult>;\n\n /** 获取访问统计 */\n getAccessStats(startTime: Date, endTime: Date): Promise<CDNResult>;\n}\n\n/** 文件处理器接口 */\nexport interface IFileProcessor {\n /** 处理器类型 */\n readonly type: ProcessorType;\n\n /** 初始化 */\n initialize(): Promise<void>;\n\n /** 处理文件 */\n process(\n inputPath: string,\n outputPath: string,\n options: ProcessingOptions\n ): Promise<ProcessingResult>;\n\n /** 检查文件是否支持处理 */\n supports(mimeType: string): boolean;\n\n /** 获取文件信息 */\n getFileInfo(filePath: string): Promise<Record<string, any>>;\n}\n\n// ============= 配置接口 =============\n\n/** 存储配置基础接口 */\nexport interface StorageConfig {\n /** 存储类型 */\n type: StorageType;\n /** 是否启用 */\n enabled: boolean;\n}\n\n/** 本地存储配置 */\nexport interface LocalStorageConfig extends StorageConfig {\n type: 'local';\n /** 存储根目录 */\n rootPath: string;\n /** 基础URL */\n baseUrl: string;\n}\n\n/** 阿里云 OSS 配置 */\nexport interface AliyunOSSConfig extends StorageConfig {\n type: 'aliyun-oss';\n /** 地域 */\n region: string;\n /** 存储桶名称 */\n bucket: string;\n /** 访问密钥ID */\n accessKeyId: string;\n /** 访问密钥密码 */\n accessKeySecret: string;\n /** 自定义域名 */\n customDomain?: string;\n /** 是否使用HTTPS */\n secure?: boolean;\n /** 是否使用内网访问 */\n internal?: boolean;\n}\n\n/** CDN配置基础接口 */\nexport interface CDNConfig {\n /** CDN类型 */\n type: CDNType;\n /** 是否启用 */\n enabled: boolean;\n}\n\n/** 阿里云 CDN 配置 */\nexport interface AliyunCDNConfig extends CDNConfig {\n type: 'aliyun-cdn';\n /** CDN域名 */\n domain: string;\n /** 访问密钥ID */\n accessKeyId: string;\n /** 访问密钥密码 */\n accessKeySecret: string;\n /** 地域 */\n region?: string;\n}\n\n/** 缓存配置 */\nexport interface CacheConfig {\n /** 是否启用缓存 */\n enabled: boolean;\n /** 最大缓存大小 */\n maxSize?: number;\n /** 缓存 TTL(秒) */\n ttl?: number;\n /** 是否使用 Redis */\n useRedis?: boolean;\n /** Redis 配置 */\n redisConfig?: {\n host: string;\n port: number;\n password?: string;\n db?: number;\n };\n}\n\n/** 文件服务配置 */\n/** 缓存配置扩展 */\nexport interface CacheConfig {\n /** 是否启用缓存 */\n enabled: boolean;\n /** 元数据缓存TTL(秒) */\n metadataTTL?: number;\n /** URL缓存TTL(秒) */\n urlTTL?: number;\n /** 最大缓存条目数 */\n maxSize?: number;\n}\n\nexport interface UniversalFileServiceConfig {\n /** 存储配置 */\n storage: StorageConfig;\n /** CDN 配置(可选) */\n cdn?: CDNConfig;\n /** 缓存配置(可选) */\n cache?: CacheConfig;\n /** 数据库持久化配置(可选) */\n persistence?: FileServicePersistenceConfig;\n /** 启用的处理器 */\n processors?: ProcessorType[];\n /** 数据库连接(可选) @deprecated 使用 persistence.repository 代替 */\n db?: any;\n /** 最大文件大小(字节) */\n maxFileSize?: number;\n /** 允许的文件类型 */\n allowedMimeTypes?: string[];\n /** 是否启用监控 */\n enableMonitoring?: boolean;\n\n // 运行时字段(由服务类内部管理)\n /** 存储提供者映射(内部使用) */\n storageProviders?: Map<StorageType, IStorageProvider>;\n /** 默认存储类型 */\n defaultStorage?: StorageType;\n /** 默认CDN类型 */\n defaultCDN?: CDNType;\n}\n\n// ============= 结果类型 =============\n\n/** 存储结果 */\n/** 存储操作结果 */\nexport interface StorageResult {\n /** 是否成功 */\n success: boolean;\n /** 存储路径 */\n path?: string;\n /** 访问URL */\n url?: string;\n /** 文件大小 */\n size?: number;\n /** 错误信息 */\n error?: string;\n /** 额外数据 */\n data?: Record<string, any>;\n}\n\n/** 存储元数据 */\nexport interface StorageMetadata {\n /** 文件大小 */\n size: number;\n /** MIME 类型 */\n mimeType: string;\n /** 最后修改时间 */\n lastModified: Date;\n /** 自定义元数据 */\n metadata?: Record<string, any>;\n}\n\n/** CDN 结果 */\n/** CDN操作结果 */\nexport interface CDNResult {\n /** 是否成功 */\n success: boolean;\n /** CDN URL */\n url?: string;\n /** 错误信息 */\n error?: string;\n /** 额外数据 */\n data?: Record<string, any>;\n}\n\n/** CDN 统计信息 */\nexport interface CDNStats {\n /** 带宽(字节/秒) */\n bandwidth: number;\n /** 请求数 */\n requests: number;\n /** 流量(字节) */\n traffic: number;\n /** 统计时间范围 */\n timeRange: {\n start: Date;\n end: Date;\n };\n}\n\n/** 处理结果 */\nexport interface ProcessingResult {\n /** 是否成功 */\n success: boolean;\n /** 处理后的文件路径 */\n processedPath?: string;\n /** 处理后的文件大小 */\n processedSize?: number;\n /** 缩略图路径 */\n thumbnailPath?: string;\n /** 错误信息 */\n error?: string;\n /** 处理耗时(毫秒) */\n processingTime?: number;\n /** 额外数据 */\n data?: Record<string, any>;\n}\n\n/** 处理器信息 */\nexport interface ProcessorInfo {\n /** 处理器名称 */\n name: string;\n /** 处理器版本 */\n version: string;\n /** 支持的格式 */\n supportedFormats: string[];\n /** 支持的操作 */\n supportedOperations: string[];\n}\n\n// ============= 数据库相关类型 =============\n\n/** 文件数据库记录 */\nexport interface FileRecord extends FileMetadata {\n /** 创建时间 */\n createdAt: Date | string;\n /** 更新时间 */\n updatedAt: Date | string;\n}\n\n/** 文件查询选项 */\nexport interface FileQueryOptions {\n /** 模块 ID */\n moduleId?: string;\n /** 业务 ID */\n businessId?: string;\n /** 上传者 ID */\n uploaderId?: string;\n /** 文件类型 */\n mimeType?: string;\n /** 访问权限 */\n permission?: AccessPermission;\n /** 状态 */\n status?: UploadStatus;\n /** 分页 */\n page?: number;\n pageSize?: number;\n /** 排序 */\n orderBy?: string;\n orderDirection?: 'asc' | 'desc';\n}\n\n/** 分页结果 */\nexport interface PaginatedResult<T> {\n /** 数据列表 */\n items: T[];\n /** 总数 */\n total: number;\n /** 当前页 */\n page: number;\n /** 每页大小 */\n pageSize: number;\n /** 总页数 */\n totalPages: number;\n}\n\n// ============= 事件类型 =============\n\n/** 文件事件类型 */\nexport type FileEventType =\n | 'upload:start'\n | 'upload:progress'\n | 'upload:complete'\n | 'upload:error'\n | 'download:start'\n | 'download:complete'\n | 'download:error'\n | 'delete:complete'\n | 'delete:error'\n | 'process:start'\n | 'process:complete'\n | 'process:error';\n\n/** 文件事件 */\nexport interface FileEvent {\n /** 事件类型 */\n type: FileEventType;\n /** 文件 ID */\n fileId: string;\n /** 事件数据 */\n data?: any;\n /** 时间戳 */\n timestamp: Date;\n}\n\n/** 事件监听器 */\nexport type FileEventListener = (event: FileEvent) => void | Promise<void>;\n\n// ============= 数据库持久化接口 =============\n\n/**\n * 文件元数据数据库持久化接口\n *\n * 实现此接口以提供自定义的数据库持久化支持\n *\n * @example\n * ```typescript\n * // Drizzle ORM 实现\n * class DrizzleFileRepository implements IFileMetadataRepository {\n * async save(metadata: FileMetadata): Promise<void> {\n * await db.insert(fileMetadata).values(metadata);\n * }\n * // ... 其他方法\n * }\n * ```\n */\nexport interface IFileMetadataRepository {\n /**\n * 保存文件元数据到数据库\n */\n save(metadata: FileMetadata): Promise<void>;\n\n /**\n * 从数据库获取文件元数据\n */\n get(fileId: string): Promise<FileMetadata | null>;\n\n /**\n * 查询文件列表\n */\n query(options: FileQueryOptions): Promise<PaginatedResult<FileMetadata>>;\n\n /**\n * 从数据库删除文件元数据\n */\n delete(fileId: string): Promise<void>;\n\n /**\n * 批量删除文件元数据\n */\n batchDelete(fileIds: string[]): Promise<void>;\n}\n\n/**\n * 数据库持久化配置\n */\nexport interface FileServicePersistenceConfig {\n /**\n * 是否启用持久化\n */\n enabled: boolean;\n\n /**\n * 持久化仓储实现\n */\n repository: IFileMetadataRepository;\n\n /**\n * 是否自动持久化(默认 true)\n * 如果为 true,文件上传完成后自动保存到数据库\n */\n autoPersist?: boolean;\n\n /**\n * 是否优先使用缓存(默认 false)\n * 如果为 true,查询时优先从缓存获取\n */\n cacheFirst?: boolean;\n}\n\n// ============= 异常类型定义 =============\n\n/** 文件服务异常基类 */\nexport class FileServiceError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly details?: Record<string, any>\n ) {\n super(message);\n this.name = 'FileServiceError';\n }\n}\n\n/** 文件上传异常 */\nexport class FileUploadError extends FileServiceError {\n constructor(message: string, details?: Record<string, any>) {\n super(message, 'FILE_UPLOAD_ERROR', details);\n this.name = 'FileUploadError';\n }\n}\n\n/** 文件处理异常 */\nexport class FileProcessingError extends FileServiceError {\n constructor(message: string, details?: Record<string, any>) {\n super(message, 'FILE_PROCESSING_ERROR', details);\n this.name = 'FileProcessingError';\n }\n}\n\n/** 存储提供者异常 */\nexport class StorageProviderError extends FileServiceError {\n constructor(message: string, details?: Record<string, any>) {\n super(message, 'STORAGE_PROVIDER_ERROR', details);\n this.name = 'StorageProviderError';\n }\n}\n\n/** CDN提供者异常 */\nexport class CDNProviderError extends FileServiceError {\n constructor(message: string, details?: Record<string, any>) {\n super(message, 'CDN_PROVIDER_ERROR', details);\n this.name = 'CDNProviderError';\n }\n}\n"]}
@@ -0,0 +1,43 @@
1
+ 'use strict';
2
+
3
+ // src/universalFile/types.ts
4
+ var FileServiceError = class extends Error {
5
+ constructor(message, code, details) {
6
+ super(message);
7
+ this.code = code;
8
+ this.details = details;
9
+ this.name = "FileServiceError";
10
+ }
11
+ };
12
+ var FileUploadError = class extends FileServiceError {
13
+ constructor(message, details) {
14
+ super(message, "FILE_UPLOAD_ERROR", details);
15
+ this.name = "FileUploadError";
16
+ }
17
+ };
18
+ var FileProcessingError = class extends FileServiceError {
19
+ constructor(message, details) {
20
+ super(message, "FILE_PROCESSING_ERROR", details);
21
+ this.name = "FileProcessingError";
22
+ }
23
+ };
24
+ var StorageProviderError = class extends FileServiceError {
25
+ constructor(message, details) {
26
+ super(message, "STORAGE_PROVIDER_ERROR", details);
27
+ this.name = "StorageProviderError";
28
+ }
29
+ };
30
+ var CDNProviderError = class extends FileServiceError {
31
+ constructor(message, details) {
32
+ super(message, "CDN_PROVIDER_ERROR", details);
33
+ this.name = "CDNProviderError";
34
+ }
35
+ };
36
+
37
+ exports.CDNProviderError = CDNProviderError;
38
+ exports.FileProcessingError = FileProcessingError;
39
+ exports.FileServiceError = FileServiceError;
40
+ exports.FileUploadError = FileUploadError;
41
+ exports.StorageProviderError = StorageProviderError;
42
+ //# sourceMappingURL=chunk-ZRAW3HXA.js.map
43
+ //# sourceMappingURL=chunk-ZRAW3HXA.js.map