import { Reporter, UploadSummary, ConsoleReporter } from '../core/reporter'; import { createStorageClient } from '../core/StorageFactory'; import type { FileProcessor } from '../core/fileProcessor'; import { ProviderConfigResolverImpl } from '../config/ProviderConfigResolverImpl'; import { type UploadDirectoryOptions as BaseOptions } from '../core/UploadService'; import { DirectoryUploadFlow } from '../core/DirectoryUploadFlow'; export interface UploadDirectoryOptions extends BaseOptions { reporter?: Reporter; fileProcessor?: FileProcessor; } export async function uploadDirectory( options: UploadDirectoryOptions, ): Promise { return new OssService(options.env || 'dev').uploadDirectory(options); } export class OssService { private readonly resolver: ProviderConfigResolverImpl; constructor(readonly env: string) { this.resolver = new ProviderConfigResolverImpl(env); } async uploadDirectory(options: UploadDirectoryOptions): Promise { const resolved = this.resolver.resolve(); const client = createStorageClient(resolved.providerConfig); const reporter = options.reporter ?? new ConsoleReporter(); const flow = new DirectoryUploadFlow( client, resolved.cdnBaseUrl, reporter, options.fileProcessor, ); return flow.uploadDirectory({ bucket: options.bucket, localDir: options.localDir, env: options.env || 'dev', suffix: options.suffix, include: options.include, exclude: options.exclude, force: options.force, hash: options.hash, forceUploadPatterns: getForceUploadPatterns(), }); } /** 返回指定前缀下一层中名称最大的 yyyyMMddHHmmss 目录;不存在时返回 undefined。 */ async getLatestFolderName(bucket: string, prefix: string): Promise { const resolved = this.resolver.resolve(); const client = createStorageClient(resolved.providerConfig); if (typeof client.listFolderPrefixes !== 'function') { throw new Error('Current storage provider does not support listing folders'); } const normalizedPrefix = prefix.replace(/^\/+|\/+$/g, ''); const objectPrefix = normalizedPrefix ? `${normalizedPrefix}/` : ''; const folderPrefixes = await client.listFolderPrefixes(bucket, objectPrefix); let latest: string | undefined; for (const folderPrefix of folderPrefixes) { const folderName = folderPrefix.slice(objectPrefix.length).replace(/\/$/, ''); if (/^\d{14}$/.test(folderName) && (!latest || folderName > latest)) { latest = folderName; } } return latest; } } function getForceUploadPatterns(): string[] { try { const raw = process.env.FILE_RE_WHITE_LIST; if (!raw) return []; return JSON.parse(raw); } catch { return []; } }