npm package: @shark-kit/minio-release
Description: A utility library for uploading files to MinIO
Author: daofan.hu
Latest version: 0.0.1

# MinIO Release

[![npm version](https://img.shields.io/npm/v/minio-release.svg)](https://www.npmjs.com/package/minio-release)
[![License](https://img.shields.io/npm/l/minio-release.svg)](https://github.com/yourusername/minio-release/blob/main/LICENSE)

一个简单易用的 MinIO/S3 文件上传工具，专为前端构建产物发布设计，支持单文件和目录上传，自动处理内容类型，并提供友好的进度显示。

## ✨ 特性

- 🚀 **简单易用**：提供简洁的 API，轻松实现文件上传
- 📁 **目录上传**：支持整个目录的递归上传
- 🔄 **自动重试**：内置错误处理和重试机制
- 📊 **进度显示**：实时显示上传进度和统计信息
- 🔍 **连接检测**：自动检测与 MinIO 服务的连通性
- 🧩 **类型支持**：完整的 TypeScript 类型定义
- 🎯 **灵活配置**：支持自定义元数据、内容类型映射等

## 📦 安装

```bash
npm install @shark-kit/minio-release
```

## 🚀 快速开始

### 基本用法

```typescript
import { createUploader } from '@shark-kit/minio-release';
import path from 'node:path';

// MinIO 配置信息
const MINIO_CONFIG = {
  endpoint: 'https://minio-api.example.com', // MinIO 服务地址
  region: 'us-east-1',                       // 区域（MinIO通常不验证区域）
  accessKey: 'your-access-key',              // 替换为你的 Access Key
  secretKey: 'your-secret-key',              // 替换为你的 Secret Key
  bucketName: 'your-bucket-name',            // 存储桶名称
  forcePathStyle: true                       // 使用路径样式
};

// 打包后的目录路径
const DIST_DIR = path.resolve('dist');

async function main() {
  try {
    // 创建上传器
    const uploader = createUploader(MINIO_CONFIG);

    // 开始上传（自动进行连通性检测）
    const result = await uploader.upload({
      sourcePath: DIST_DIR,
      // 不设置targetPrefix，则上传到存储桶根目录
      showProgress: true, // 启用进度显示，包括连接检测信息
      // 可选：添加自定义元数据
      metadata: {
        'x-amz-meta-deployed-by': 'minio-release',
        'x-amz-meta-deploy-time': new Date().toISOString()
      },
      // 可选：自定义内容类型映射
      contentTypeMap: {
        html: 'text/html; charset=utf-8',
        css: 'text/css; charset=utf-8',
        js: 'application/javascript; charset=utf-8',
        json: 'application/json; charset=utf-8',
        svg: 'image/svg+xml'
      }
    });

    // 检查上传结果
    if (!result.success) {
      process.exit(1);
    }
  } catch (error) {
    console.error('🚨 上传过程中发生错误:', error);
    process.exit(1);
  }
}

main();
```

### 显式连接检查

如果需要在上传前显式检查连接，可以使用 `checkConnection` 方法：

```typescript
import { createUploader } from '@shark-kit/minio-release';

async function main() {
  const uploader = createUploader({
    endpoint: 'https://minio-api.example.com',
    accessKey: 'your-access-key',
    secretKey: 'your-secret-key',
    bucketName: 'your-bucket-name',
    forcePathStyle: true
  });

  // 显式检查连接
  const isConnected = await uploader.checkConnection(true); // 传入 true 显示进度信息
  
  if (!isConnected) {
    console.error('无法连接到 MinIO 服务器');
    process.exit(1);
  }
  
  // 连接成功，继续上传
  const result = await uploader.upload({
    sourcePath: './dist',
    showProgress: true
  });
  
  console.log('上传完成:', result);
}
```

### 上传单个文件

```typescript
import { createUploader } from '@shark-kit/minio-release';

async function uploadSingleFile() {
  const uploader = createUploader({
    endpoint: 'https://minio-api.example.com',
    accessKey: 'your-access-key',
    secretKey: 'your-secret-key',
    bucketName: 'your-bucket-name'
  });
  
  // 上传单个文件
  const success = await uploader.uploadFile(
    './path/to/local/file.pdf',
    'remote/path/file.pdf',
    {
      contentType: 'application/pdf',
      metadata: { 'x-amz-meta-owner': 'user123' }
    }
  );
  
  console.log('文件上传' + (success ? '成功' : '失败'));
}
```

## 📚 API 参考

### `createUploader(config: MinioConfig): MinioUploader`

创建一个 MinioUploader 实例。

### `MinioConfig` 接口

| 属性 | 类型 | 必填 | 描述 |
|------|------|------|------|
| `endpoint` | `string` | ✅ | MinIO 服务地址 |
| `accessKey` | `string` | ✅ | 访问密钥 ID |
| `secretKey` | `string` | ✅ | 访问密钥 |
| `bucketName` | `string` | ✅ | 存储桶名称 |
| `region` | `string` | ❌ | 区域（默认：'us-east-1'） |
| `forcePathStyle` | `boolean` | ❌ | 是否使用路径样式（默认：true） |
| `clientOptions` | `Record<string, any>` | ❌ | 自定义 S3 客户端配置选项 |

### `MinioUploader` 类

#### `uploadFile(filePath: string, key: string, options?: object): Promise<boolean>`

上传单个文件。

- `filePath`: 本地文件路径
- `key`: 对象键（存储桶中的路径）
- `options`: 可选配置
  - `contentType`: 内容类型
  - `metadata`: 自定义元数据

返回：是否上传成功

#### `checkConnection(showProgress?: boolean): Promise<boolean>`

检测与 MinIO 节点的连通性。

- `showProgress`: 是否显示进度信息（默认：false）

返回：是否连通

#### `upload(options: UploadOptions): Promise<UploadResult>`

上传目录或文件。

- `options`: 上传选项

返回：上传结果

### `UploadOptions` 接口

| 属性 | 类型 | 必填 | 描述 |
|------|------|------|------|
| `sourcePath` | `string` | ✅ | 源目录或文件路径 |
| `targetPrefix` | `string` | ❌ | 目标路径前缀（在存储桶中的路径） |
| `showProgress` | `boolean` | ❌ | 是否显示上传进度（默认：true） |
| `onSuccess` | `(key: string) => void` | ❌ | 上传成功回调函数 |
| `onError` | `(key: string, error: Error) => void` | ❌ | 上传失败回调函数 |
| `fileFilter` | `(filePath: string) => boolean` | ❌ | 文件过滤函数 |
| `metadata` | `Record<string, string>` | ❌ | 自定义文件元数据 |
| `contentTypeMap` | `Record<string, string>` | ❌ | 自定义内容类型映射 |

### `UploadResult` 接口

| 属性 | 类型 | 描述 |
|------|------|------|
| `success` | `boolean` | 是否全部成功 |
| `successCount` | `number` | 成功上传的文件数量 |
| `failCount` | `number` | 失败上传的文件数量 |
| `timeMs` | `number` | 总耗时（毫秒） |
| `failedFiles` | `string[]` | 失败的文件列表 |
| `connectionError` | `string` | 连接错误信息（如果有） |

## 📄 许可证

[MIT](LICENSE)