{"version":3,"file":"cli.cjs","sources":["../src/cli.ts","../src/providers/huawei/HuaweiObsClient.ts","../src/core/StorageFactory.ts","../src/core/filters.ts","../src/core/UploadFlowTemplate.ts","../src/core/urlHelper.ts","../src/core/DirectoryUploadFlow.ts","../src/middleware/OssService.ts","../src/config/EnvConfigResolverImpl.ts","../src/config/ProviderConfigResolverImpl.ts","../src/core/reporter.ts","../src/config/loadObsCredentialsFromUrl.ts"],"sourcesContent":["/**\r\n * CLI 入口：oss-upload 命令。\r\n * 使用动态 import 加载依赖，避免启动时加载全部模块。\r\n * .env 在打包时已注入 dist/cli.cjs，运行时不再读取。\r\n */\r\n(async () => {\r\n  const [{ Command }, { OssService }, { ProviderConfigResolverImpl }, { ConsoleReporter }] = await Promise.all([\r\n    import('commander'),\r\n    import('./middleware/OssService'),\r\n    import('./config/ProviderConfigResolverImpl'),\r\n    import('./core/reporter'),\r\n  ]);\r\n\r\n  const program = new Command();\r\n\r\n  program\r\n    .name('oss-upload')\r\n    .description('上传本地目录到 OSS（当前为华为 OBS）')\r\n    .argument('<localDir>', '本地目录')\r\n    .requiredOption('-b, --bucket <bucket>', 'Bucket 名称','hr-uat')\r\n    .option('-e, --env <env>', '环境标识，如 dev/test/prod')\r\n    .option('--path-prefix <pathPrefix>', '业务路径前缀，将拼在 base/env 后面')\r\n    .option('--include <pattern...>', '包含的文件模式（可多次）')\r\n    .option('--exclude <pattern...>', '排除的文件模式（可多次）')\r\n    .action(async (localDir: string, options: any) => {\r\n      const { loadObsCredentialsFromUrlIfNeeded } = await import('./config/loadObsCredentialsFromUrl');\r\n      await loadObsCredentialsFromUrlIfNeeded();\r\n\r\n      const service = new OssService(new ProviderConfigResolverImpl());\r\n      const reporter = new ConsoleReporter();\r\n\r\n      try {\r\n        const summary = await service.uploadDirectory({\r\n          env: options.env,\r\n          bucket: options.bucket,\r\n          localDir,\r\n          pathPrefix: options.pathPrefix,\r\n          include: options.include,\r\n          exclude: options.exclude,\r\n          reporter,\r\n        });\r\n\r\n        if (summary.failed > 0) {\r\n          process.exitCode = 1;\r\n        }\r\n      } catch (err: any) {\r\n        // eslint-disable-next-line no-console\r\n        console.error('上传过程中发生错误:', err?.message || err);\r\n        process.exitCode = 1;\r\n      }\r\n    });\r\n\r\n  program.parse(process.argv);\r\n})();\r\n\r\n","import { StorageClient, PutObjectOptions, HeadObjectResult } from '../../core/StorageClient';\r\nimport { HuaweiObsConfig } from '../../config/types';\r\n\r\n// 华为 OBS Node.js SDK（CommonJS）\r\nconst ObsClient = require('esdk-obs-nodejs');\r\n\r\n/**\r\n * 华为 OBS 的 StorageClient 实现（Adapter）。\r\n * 通过 SDK 的 getObjectMetadata 查元数据判断是否存在，putObject 上传对象。\r\n */\r\nexport class HuaweiObsClient implements StorageClient {\r\n  private readonly client: InstanceType<typeof ObsClient>;\r\n\r\n  constructor(private readonly config: HuaweiObsConfig) {\r\n    this.client = new ObsClient({\r\n      access_key_id: config.accessKey,\r\n      secret_access_key: config.secretKey,\r\n      server: config.endpoint,\r\n    });\r\n  }\r\n\r\n  /**\r\n   * 调用 OBS getObjectMetadata 查元数据，判断对象是否存在（同路径即跳过上传）。\r\n   */\r\n  async headObject(bucket: string, key: string): Promise<HeadObjectResult> {\r\n    try {\r\n      const result = await this.client.getObjectMetadata({\r\n        Bucket: bucket,\r\n        Key: key,\r\n      });\r\n\r\n      if (result.CommonMsg.Status <= 300) {\r\n        return { exists: true };\r\n      }\r\n\r\n      // 对象不存在\r\n      if (result.CommonMsg.Status === 404 || result.CommonMsg.Code === 'NoSuchKey' || result.CommonMsg.Code === 'NotFound') {\r\n        return { exists: false };\r\n      }\r\n\r\n      throw new Error(`OBS getObjectMetadata 失败: ${result.CommonMsg.Status} ${result.CommonMsg.Code} ${result.CommonMsg.Message}`);\r\n    } catch (err: unknown) {\r\n      const msg = err && typeof (err as any).message === 'string' ? (err as Error).message : String(err);\r\n      const code = (err as any)?.Code ?? (err as any)?.code;\r\n      if (code === 'NoSuchKey' || code === 'NotFound' || msg.includes('404') || msg.includes('NoSuchKey')) {\r\n        return { exists: false };\r\n      }\r\n      throw err;\r\n    }\r\n  }\r\n\r\n  /** 调用 OBS putObject 上传对象 */\r\n  async putObject(options: PutObjectOptions): Promise<void> {\r\n    const { bucket, key, body, contentType } = options;\r\n    // console.log('putObject', { bucket, key, endpoint: this.config.endpoint, accessKey: this.config.accessKey, secretKey: this.config.secretKey })\r\n    const result = await this.client.putObject({\r\n      Bucket: bucket,\r\n      Key: key,\r\n      Body: body,\r\n      // ContentType: contentType,\r\n    });\r\n\r\n    if (result.CommonMsg.Status > 300) {\r\n      const { Status, Code, Message, RequestId } = result.CommonMsg;\r\n      const detail = [Status, Code, Message, RequestId].filter(Boolean).join(' ');\r\n      throw new Error(\r\n        `OBS putObject 失败 (${detail || '无详情'}). ` +\r\n          '请检查: 1) 桶名是否正确且已创建 2) OBS_ENDPOINT 是否与该桶所在区域一致，如 https://obs.xx-xx-1.myhuaweicloud.com'\r\n      );\r\n    }\r\n  }\r\n}\r\n","import { StorageClient } from './StorageClient';\r\nimport { ProviderConfig } from '../config/types';\r\nimport { HuaweiObsClient } from '../providers/huawei/HuaweiObsClient';\r\n\r\n/**\r\n * 根据 Provider 类型创建对应的 StorageClient（简单工厂）。\r\n * 后续扩展阿里 OSS、AWS S3 时在此增加 case 即可。\r\n */\r\nexport function createStorageClient(config: ProviderConfig): StorageClient {\r\n  switch (config.type) {\r\n    case 'huawei':\r\n      return new HuaweiObsClient(config.options);\r\n    default:\r\n      throw new Error(`Unsupported provider type: ${config.type}`);\r\n  }\r\n}\r\n\r\n","import micromatch from 'micromatch';\r\n\r\n/**\r\n * 根据 include/exclude 规则判断相对路径是否应参与上传。\r\n * 使用 micromatch 支持 glob（如 **\\/*.js）。\r\n * @param relativePath 相对路径\r\n * @param include 包含模式，不传则默认全部包含\r\n * @param exclude 排除模式\r\n * @returns 是否应包含该文件\r\n */\r\nexport function shouldInclude(\r\n  relativePath: string,\r\n  include?: string[],\r\n  exclude?: string[],\r\n): boolean {\r\n  let included = true;\r\n\r\n  if (include && include.length > 0) {\r\n    included = micromatch.isMatch(relativePath, include);\r\n  }\r\n  if (!included) return false;\r\n\r\n  if (exclude && exclude.length > 0) {\r\n    if (micromatch.isMatch(relativePath, exclude)) {\r\n      return false;\r\n    }\r\n  }\r\n\r\n  return true;\r\n}\r\n\r\n","import fs from 'fs/promises';\r\nimport path from 'path';\r\nimport { Reporter, UploadSummary, UploadFileResult } from './reporter';\r\nimport { StorageClient } from './StorageClient';\r\nimport { shouldInclude } from './filters';\r\nimport type { FileProcessor } from './fileProcessor';\r\n\r\n/** 上传流程的上下文：环境、bucket、前缀、本地目录、存储客户端、Reporter、CDN 根地址、上传前处理器等 */\r\nexport interface UploadContext {\r\n  env?: string;\r\n  bucket: string;\r\n  basePrefix: string;\r\n  pathPrefix?: string;\r\n  localDir: string;\r\n  include?: string[];\r\n  exclude?: string[];\r\n  storageClient: StorageClient;\r\n  reporter?: Reporter;\r\n  /** CDN 加速根地址，配置后可为每个文件生成 accessUrl */\r\n  cdnBaseUrl?: string;\r\n  /** 上传前对文件内容的处理器（如图片压缩），未配置则直接上传原内容 */\r\n  fileProcessor?: FileProcessor;\r\n}\r\n\r\n/** 本地文件信息：绝对路径与相对路径 */\r\nexport interface LocalFile {\r\n  absolutePath: string;\r\n  relativePath: string;\r\n}\r\n\r\n/**\r\n * 上传流程模板（Template Method）。\r\n * 定义固定步骤：onStart -> collectFiles -> filterFiles -> uploadFiles -> onComplete，\r\n * 子类实现 collectFiles 与 uploadFiles，其余步骤可复用或重写。\r\n */\r\nexport abstract class UploadFlowTemplate {\r\n  protected constructor(protected readonly context: UploadContext) {}\r\n\r\n  /** 执行完整上传流程 */\r\n  async execute(): Promise<UploadSummary> {\r\n    const { reporter } = this.context;\r\n\r\n    if (reporter?.onStart) {\r\n      await reporter.onStart({\r\n        env: this.context.env,\r\n        bucket: this.context.bucket,\r\n        basePrefix: this.context.basePrefix,\r\n        pathPrefix: this.context.pathPrefix,\r\n        localDir: this.context.localDir,\r\n        cdnBaseUrl: this.context.cdnBaseUrl,\r\n      });\r\n    }\r\n\r\n    const files = await this.collectFiles();\r\n    const filtered = this.filterFiles(files);\r\n    const summary = await this.uploadFiles(filtered);\r\n\r\n    if (reporter?.onComplete) {\r\n      await reporter.onComplete(summary);\r\n    }\r\n\r\n    return summary;\r\n  }\r\n\r\n  protected abstract collectFiles(): Promise<LocalFile[]>;\r\n  protected abstract uploadFiles(files: LocalFile[]): Promise<UploadSummary>;\r\n\r\n  /** 使用 include/exclude 过滤文件列表 */\r\n  protected filterFiles(files: LocalFile[]): LocalFile[] {\r\n    const { include, exclude } = this.context;\r\n    return files.filter((f) => shouldInclude(f.relativePath, include, exclude));\r\n  }\r\n\r\n  /**\r\n   * 构造远端 key：basePrefix / env / pathPrefix / relativePath。\r\n   * 保持目录结构，且 base 前缀来自 config，不对外暴露。\r\n   */\r\n  protected buildKey(relativePath: string): string {\r\n    const parts: string[] = [];\r\n    if (this.context.basePrefix) parts.push(this.context.basePrefix);\r\n    if (this.context.env) parts.push(this.context.env);\r\n    if (this.context.pathPrefix) parts.push(this.context.pathPrefix);\r\n\r\n    parts.push(relativePath.replace(/\\\\/g, '/'));\r\n    return parts.join('/');\r\n  }\r\n\r\n  /** 递归遍历目录，收集所有文件的绝对路径与相对路径 */\r\n  protected async walkDir(rootDir: string, currentDir = ''): Promise<LocalFile[]> {\r\n    const dirPath = path.join(rootDir, currentDir);\r\n    const entries = await fs.readdir(dirPath, { withFileTypes: true });\r\n    const files: LocalFile[] = [];\r\n\r\n    for (const entry of entries) {\r\n      const rel = path.join(currentDir, entry.name);\r\n      const abs = path.join(rootDir, rel);\r\n\r\n      if (entry.isDirectory()) {\r\n        files.push(...(await this.walkDir(rootDir, rel)));\r\n      } else if (entry.isFile()) {\r\n        files.push({\r\n          absolutePath: abs,\r\n          relativePath: rel.replace(/\\\\/g, '/'),\r\n        });\r\n      }\r\n    }\r\n\r\n    return files;\r\n  }\r\n\r\n  /** 将单个文件的上传结果交给 Reporter */\r\n  protected async reportFileResult(result: UploadFileResult): Promise<void> {\r\n    const { reporter } = this.context;\r\n    if (reporter?.onFileResult) {\r\n      await reporter.onFileResult(result);\r\n    }\r\n  }\r\n}\r\n\r\n","/**\r\n * 根据 CDN 加速域名与对象 key 拼接完整的访问地址。\r\n * @param cdnBaseUrl CDN 根地址（如 https://cdn.example.com），可带或不带末尾斜杠\r\n * @param key 对象在桶内的 key（如 basePrefix/path/file.js）\r\n * @returns 完整访问 URL，如 https://cdn.example.com/basePrefix/path/file.js\r\n */\r\nexport function buildCdnAccessUrl(cdnBaseUrl: string, key: string): string {\r\n  const base = cdnBaseUrl.replace(/\\/+$/, '');\r\n  const pathPart = key.replace(/^\\/+/, '');\r\n  return pathPart ? `${base}/${pathPart}` : base;\r\n}\r\n","import fs from 'fs/promises';\r\nimport { UploadFlowTemplate, UploadContext, LocalFile } from './UploadFlowTemplate';\r\nimport { UploadSummary } from './reporter';\r\nimport { buildCdnAccessUrl } from './urlHelper';\r\n\r\n/**\r\n * 目录上传流程的具体实现：遍历本地目录，按 key 规则上传，云端同名则跳过。\r\n * 规则：先 headObject，exists 则 skipped，否则 putObject。\r\n */\r\nexport class DirectoryUploadFlow extends UploadFlowTemplate {\r\n  constructor(context: UploadContext) {\r\n    super(context);\r\n  }\r\n\r\n  /** 递归收集 localDir 下所有文件 */\r\n  protected async collectFiles(): Promise<LocalFile[]> {\r\n    return this.walkDir(this.context.localDir);\r\n  }\r\n\r\n  /**\r\n   * 逐个文件上传：先 head 判断是否存在，存在则跳过，否则读取本地文件并 putObject。\r\n   * 每个文件的结果通过 reportFileResult 交给 Reporter。\r\n   */\r\n  protected async uploadFiles(files: LocalFile[]): Promise<UploadSummary> {\r\n    const { bucket, storageClient, cdnBaseUrl } = this.context;\r\n\r\n    const summary: UploadSummary = {\r\n      total: files.length,\r\n      success: 0,\r\n      failed: 0,\r\n      skipped: 0,\r\n    };\r\n\r\n    for (const file of files) {\r\n      const key = this.buildKey(file.relativePath);\r\n\r\n      try {\r\n        const head = await storageClient.headObject(bucket, key);\r\n\r\n        // 云端已有同名对象则跳过，不比较内容\r\n        if (head.exists) {\r\n          summary.skipped += 1;\r\n          await this.reportFileResult({\r\n            localPath: file.absolutePath,\r\n            relativePath: file.relativePath,\r\n            bucket,\r\n            key,\r\n            status: 'skipped',\r\n            ...(cdnBaseUrl && { accessUrl: buildCdnAccessUrl(cdnBaseUrl, key) }),\r\n          });\r\n          continue;\r\n        }\r\n\r\n        const data = await fs.readFile(file.absolutePath);\r\n\r\n        const { buffer, contentType } = this.context.fileProcessor\r\n          ? await this.context.fileProcessor.process({\r\n              localPath: file.absolutePath,\r\n              relativePath: file.relativePath,\r\n              buffer: data,\r\n            })\r\n          : { buffer: data, contentType: undefined as string | undefined };\r\n\r\n        await storageClient.putObject({\r\n          bucket,\r\n          key,\r\n          body: buffer,\r\n          contentType,\r\n        });\r\n\r\n        summary.success += 1;\r\n        await this.reportFileResult({\r\n          localPath: file.absolutePath,\r\n          relativePath: file.relativePath,\r\n          bucket,\r\n          key,\r\n          status: 'success',\r\n          ...(cdnBaseUrl && { accessUrl: buildCdnAccessUrl(cdnBaseUrl, key) }),\r\n        });\r\n      } catch (err: any) {\r\n        summary.failed += 1;\r\n        await this.reportFileResult({\r\n          localPath: file.absolutePath,\r\n          relativePath: file.relativePath,\r\n          bucket,\r\n          key,\r\n          status: 'failed',\r\n          error: err instanceof Error ? err : new Error(String(err)),\r\n        });\r\n      }\r\n    }\r\n\r\n    return summary;\r\n  }\r\n}\r\n\r\n","import { Reporter, UploadSummary } from '../core/reporter';\r\nimport { ProviderConfigResolver } from '../config/types';\r\nimport { createStorageClient } from '../core/StorageFactory';\r\nimport { DirectoryUploadFlow } from '../core/DirectoryUploadFlow';\r\nimport type { FileProcessor } from '../core/fileProcessor';\r\n\r\n/** 上传目录的入参：环境、bucket、本地目录、路径前缀、过滤规则、Reporter、上传前文件处理器 */\r\nexport interface UploadDirectoryInput {\r\n  env?: string;\r\n  bucket: string;\r\n  localDir: string;\r\n  pathPrefix?: string;\r\n  include?: string[];\r\n  exclude?: string[];\r\n  reporter?: Reporter;\r\n  /** 上传前对文件内容的处理器（如图片压缩），未配置则直接上传原内容 */\r\n  fileProcessor?: FileProcessor;\r\n}\r\n\r\n/**\r\n * 中间件：对主流程暴露统一 API（Facade）。\r\n * 内部只依赖 ProviderConfigResolver 得到当前 Provider 配置，再创建 StorageClient 与流程并执行。\r\n * 切换云厂商时只需改 ProviderConfigResolver 的【一个实现文件】。\r\n */\r\nexport class OssService {\r\n  constructor(private readonly providerConfigResolver: ProviderConfigResolver) {}\r\n\r\n  /** 上传指定本地目录到 OSS，key 规则为 basePrefix/env/pathPrefix/相对路径，同名则跳过 */\r\n  async uploadDirectory(input: UploadDirectoryInput): Promise<UploadSummary> {\r\n    const { env, bucket= 'hr-uat', localDir, pathPrefix, include, exclude, reporter, fileProcessor } = input;\r\n\r\n    const resolved = this.providerConfigResolver.resolve();\r\n    const { providerConfig, basePrefix, cdnBaseUrl } = resolved;\r\n\r\n    const client = createStorageClient(providerConfig);\r\n\r\n    const flow = new DirectoryUploadFlow({\r\n      env,\r\n      bucket,\r\n      localDir,\r\n      pathPrefix,\r\n      include,\r\n      exclude,\r\n      basePrefix,\r\n      storageClient: client,\r\n      reporter,\r\n      cdnBaseUrl,\r\n      fileProcessor,\r\n    });\r\n\r\n    return flow.execute();\r\n  }\r\n}\r\n\r\n","import { EnvConfigResolver, HuaweiObsConfig } from './types';\r\n\r\n/**\r\n * 从系统环境变量解析华为 OBS 配置的实现。\r\n * 只使用一套固定变量，不区分 dev/test/prod 等多环境前缀。\r\n */\r\nexport class EnvConfigResolverImpl implements EnvConfigResolver {\r\n  /**\r\n   * 解析华为 OBS 配置（endpoint、ak/sk、basePrefix 等）。\r\n   * 当前实现忽略 env 参数，统一使用以下环境变量：\r\n   * - OBS_ENDPOINT\r\n   * - OBS_ACCESS_KEY / OBS_SECRET_KEY（也可通过 OBS_CREDENTIALS_URL 拉取 YAML 获得）\r\n   * - OBS_REGION（可选）\r\n   * - OBS_BASE_PREFIX（可选，作为所有 key 的基础前缀）\r\n   * - OBS_CDN_BASE_URL（可选，CDN 加速根地址，上传完成后用于拼出访问 URL）\r\n   */\r\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\r\n  resolveHuaweiConfig(env?: string): HuaweiObsConfig {\r\n    // 通过环境变量解构出 OBS 访问配置（不依赖 .env 文件，直接读取进程环境）\r\n    const endpoint = process.env.OBS_ENDPOINT;\r\n    const accessKey = process.env.OBS_ACCESS_KEY;\r\n    const secretKey = process.env.OBS_SECRET_KEY;\r\n    const region = process.env.OBS_REGION;\r\n    // basePrefix 作为所有对象 key 的基础前缀，用于隔离项目/租户等\r\n    const basePrefix = process.env.OBS_BASE_PREFIX;\r\n    // CDN 加速根地址，配置后用于拼出上传完成后的访问 URL\r\n    const cdnBaseUrl = process.env.OBS_CDN_BASE_URL;\r\n\r\n    if (!endpoint || !accessKey || !secretKey) {\r\n      // 缺少关键配置时立即抛错，避免在后续真正上传时才暴露连接失败的问题\r\n      throw new Error('缺少华为 OBS 配置: OBS_ENDPOINT / OBS_ACCESS_KEY / OBS_SECRET_KEY');\r\n    }\r\n\r\n    return {\r\n      endpoint,\r\n      accessKey,\r\n      secretKey,\r\n      region,\r\n      basePrefix: basePrefix || '',\r\n      cdnBaseUrl,\r\n    };\r\n  }\r\n}\r\n\r\n","import { ProviderConfigResolver, ResolvedProviderConfig } from './types';\r\nimport { EnvConfigResolverImpl } from './EnvConfigResolverImpl';\r\n\r\n/**\r\n * 统一 Provider 配置解析的【唯一入口】。\r\n * 切换云厂商时只需改本文件：改 OSS_PROVIDER 环境变量或增加 case，无需改 OssService / CLI 等。\r\n *\r\n * 环境变量约定：\r\n * - OSS_PROVIDER：当前使用的存储，如 'huawei'（默认）\r\n * - 当 OSS_PROVIDER=huawei 时，使用 OBS_* 变量（见 EnvConfigResolverImpl）\r\n * - 后续接入阿里云等时，在此增加 case 并读取对应 env 即可。\r\n */\r\nexport class ProviderConfigResolverImpl implements ProviderConfigResolver {\r\n  private readonly huaweiResolver = new EnvConfigResolverImpl();\r\n\r\n  resolve(): ResolvedProviderConfig {\r\n    const provider = process.env.OSS_PROVIDER;\r\n\r\n    switch (provider) {\r\n      case 'huawei': {\r\n        const options = this.huaweiResolver.resolveHuaweiConfig();\r\n        return {\r\n          providerConfig: { type: 'huawei', options },\r\n          basePrefix: options.basePrefix,\r\n          cdnBaseUrl: options.cdnBaseUrl,\r\n        };\r\n      }\r\n      // 后续切换或新增云厂商时，在此增加 case，例如：\r\n      // case 'aliyun': { ... return { providerConfig: { type: 'aliyun', options }, basePrefix, cdnBaseUrl }; }\r\n      default:\r\n        throw new Error(`不支持的 OSS_PROVIDER: ${provider}，当前仅支持 huawei`);\r\n    }\r\n  }\r\n}\r\n","/**\r\n * 上传结果上报抽象（Reporter）。\r\n * 默认实现为控制台输出，可扩展为企业微信、钉钉等通知。\r\n */\r\n\r\nexport type UploadStatus = 'success' | 'failed' | 'skipped';\r\n\r\n/** 单个文件的上传结果，供 Reporter 使用 */\r\nexport interface UploadFileResult {\r\n  localPath: string;\r\n  relativePath: string;\r\n  bucket: string;\r\n  key: string;\r\n  status: UploadStatus;\r\n  error?: Error;\r\n  /** 配置了 CDN 时的完整访问地址，由 buildCdnAccessUrl 生成 */\r\n  accessUrl?: string;\r\n}\r\n\r\n/** 整次上传的汇总统计 */\r\nexport interface UploadSummary {\r\n  total: number;\r\n  success: number;\r\n  failed: number;\r\n  skipped: number;\r\n}\r\n\r\n/** Reporter 接口：上传开始、每个文件结果、全部完成时回调，便于接入不同通知方式 */\r\nexport interface Reporter {\r\n  onStart?(context: {\r\n    env?: string;\r\n    bucket: string;\r\n    basePrefix: string;\r\n    pathPrefix?: string;\r\n    localDir: string;\r\n    cdnBaseUrl?: string;\r\n  }): void | Promise<void>;\r\n\r\n  onFileResult?(result: UploadFileResult): void | Promise<void>;\r\n\r\n  onComplete?(summary: UploadSummary): void | Promise<void>;\r\n}\r\n\r\n/** 默认实现：将上传进度与结果输出到控制台 */\r\nexport class ConsoleReporter implements Reporter {\r\n  onStart(context: {\r\n    env?: string;\r\n    bucket: string;\r\n    basePrefix: string;\r\n    pathPrefix?: string;\r\n    localDir: string;\r\n    cdnBaseUrl?: string;\r\n  }): void {\r\n    const { env, bucket, basePrefix, pathPrefix, localDir, cdnBaseUrl } = context;\r\n    // console.log('开始上传目录:');\r\n    // console.log(`  环境: ${env ?? '未指定'}`);\r\n    // console.log(`  Bucket: ${bucket}`);\r\n    // console.log(`  Base 前缀: ${basePrefix || '(空)'}`);\r\n    // console.log(`  业务前缀(pathPrefix): ${pathPrefix || '(空)'}`);\r\n    // console.log(`  本地目录: ${localDir}`);\r\n    if (cdnBaseUrl) {\r\n      console.log(`  CDN 根地址: ${cdnBaseUrl}`);\r\n    }\r\n  }\r\n\r\n  onFileResult(result: UploadFileResult): void {\r\n    const { status, localPath, key, error, accessUrl } = result;\r\n    if (status === 'success') {\r\n      console.log(`[SUCCESS] ${localPath} -> ${key}`);\r\n      if (accessUrl) console.log(`  访问地址: ${accessUrl}`);\r\n    } else if (status === 'skipped') {\r\n      console.log(`[SKIPPED] ${localPath} -> ${key} (云端同名已存在)`);\r\n      if (accessUrl) console.log(`  访问地址: ${accessUrl}`);\r\n    } else {\r\n      console.error(`[FAILED]  ${localPath} -> ${key}`);\r\n      if (error) console.error(`  Error: ${error.message}`);\r\n    }\r\n  }\r\n\r\n  onComplete(summary: UploadSummary): void {\r\n    console.log('上传完成:');\r\n    console.log(`  总数: ${summary.total}`);\r\n    console.log(`  成功: ${summary.success}`);\r\n    console.log(`  失败: ${summary.failed}`);\r\n    console.log(`  跳过: ${summary.skipped}`);\r\n  }\r\n}\r\n\r\n","/**\r\n * 当配置了 OBS_CREDENTIALS_URL 且未配置 AK/SK 时，从该 URL 拉取 YAML 并解析出\r\n * OBS_ACCESS_KEY、OBS_SECRET_KEY 写入 process.env，供 EnvConfigResolverImpl 使用。\r\n */\r\nimport yaml from 'js-yaml';\r\n\r\nconst CREDENTIALS_URL_KEY = 'OBS_CREDENTIALS_URL';\r\n// const ACCESS_KEY_KEY = 'OBS_ACCESS_KEY';\r\n// const SECRET_KEY_KEY = 'OBS_SECRET_KEY';\r\n\r\n/**\r\n * 若设置了 OBS_CREDENTIALS_URL 且当前未设置 OBS_ACCESS_KEY 或 OBS_SECRET_KEY，\r\n * 则请求该 URL，解析 YAML，并将 OBS_ACCESS_KEY、OBS_SECRET_KEY 写入 process.env。\r\n */\r\nexport async function loadObsCredentialsFromUrlIfNeeded(): Promise<void> {\r\n  const url = process.env.OBS_CREDENTIALS_URL;\r\n  const hasAccessKey = process.env.OBS_ACCESS_KEY;\r\n  const hasSecretKey = process.env.OBS_SECRET_KEY;\r\n  \r\n  if (!url || (hasAccessKey && hasSecretKey)) {\r\n    return;\r\n  }\r\n\r\n  const res = await fetch(url);\r\n  \r\n  if (!res.ok) {\r\n    throw new Error(`拉取 OBS 凭证失败 (${res.status}): ${url}`);\r\n  }\r\n  const text = await res.text();\r\n  const parsed = yaml.load(text) as Record<string, unknown> | undefined;\r\n  if (!parsed || typeof parsed !== 'object') {\r\n    throw new Error(\r\n      `OBS 凭证 YAML 解析结果无效，请检查 ${CREDENTIALS_URL_KEY} 返回内容`\r\n    );\r\n  }\r\n  const accessKey = parsed.OBS_ACCESS_KEY;\r\n  const secretKey = parsed.OBS_SECRET_KEY;\r\n  if (typeof accessKey === 'string') process.env.OBS_ACCESS_KEY = accessKey;\r\n  if (typeof secretKey === 'string') process.env.OBS_SECRET_KEY = secretKey;\r\n  \r\n  if (!process.env.OBS_ACCESS_KEY || !process.env.OBS_SECRET_KEY) {\r\n    throw new Error(\r\n      `OBS 凭证 YAML 中未找到 OBS_ACCESS_KEY 或 OBS_SECRET_KEY，请检查 ${CREDENTIALS_URL_KEY} 返回内容`\r\n    );\r\n  }\r\n}\r\n"],"names":[],"mappings":"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"}