feat(storage): storage port and minio adapter with forbid-overwrite semantics

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-17 20:25:18 +08:00
parent 59464bd73d
commit 37f4b3e11f
10 changed files with 748 additions and 3 deletions
+32
View File
@@ -0,0 +1,32 @@
// packages/storage/src/index.ts —— 存储包统一出口:端口类型 + MinIO 适配器 + 错误 +
// env 工厂。api(Task 18 presign/verify)与 worker(Task 20 variants put/get)经
// `createStorageFromEnv()` 构造实例,测试/本地指向 MinIO,生产指向 OSS。
// commonjs 包(消费方 api/worker 均为 CJS);@photo/contracts 为 ESM dist,运行时经
// Node require(esm) 消费(Node >= 22.12,见根 engines)。
import { MinioStorageAdapter, type MinioStorageConfig } from './minio.adapter';
export { MinioStorageAdapter } from './minio.adapter';
export type { MinioStorageConfig } from './minio.adapter';
export { StorageError, ErrorCodes } from './errors';
export type { StoragePort, UploadCredential } from './port';
/**
* 从 S3_* 环境变量构造 MinIO/S3 兼容适配器(仓库根 .env 经 dotenv-cli 或
* test/load-env.ts 注入)。任一变量缺失即抛错,禁止静默回退默认值。
*/
export function createStorageFromEnv(): MinioStorageAdapter {
const config = {
endpoint: process.env.S3_ENDPOINT,
region: process.env.S3_REGION,
accessKey: process.env.S3_ACCESS_KEY,
secretKey: process.env.S3_SECRET_KEY,
bucket: process.env.S3_BUCKET,
} satisfies Record<keyof MinioStorageConfig, string | undefined>;
const missing = Object.entries(config)
.filter(([, value]) => !value)
.map(([key]) => `S3_${key.toUpperCase()}`);
if (missing.length > 0) {
throw new Error(`createStorageFromEnv: 缺少环境变量 ${missing.join(', ')}(S3_* 配置见仓库根 .env)`);
}
return new MinioStorageAdapter(config as MinioStorageConfig);
}