storage-development
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseStorage Development Guide
存储开发指南
This skill provides guidance for developers working with the base package, including creating new storage adapters.
@rytass/storages本指南为使用基础包的开发者提供指导,包括如何创建新的存储adapter。
@rytass/storagesOverview
概述
The package defines the core interfaces and types that all storage adapters must implement. It follows the adapter pattern to provide a unified API across different storage providers.
@rytass/storagesPackage: (v0.2.5)
@rytass/storagesAdapters built on this base:
- - AWS S3
@rytass/storages-adapter-s3 - - Google Cloud Storage
@rytass/storages-adapter-gcs - - Cloudflare R2
@rytass/storages-adapter-r2 - - Azure Blob Storage
@rytass/storages-adapter-azure-blob - - Local File System
@rytass/storages-adapter-local
@rytass/storages包: (v0.2.5)
@rytass/storages基于此基础构建的Adapter:
- - AWS S3
@rytass/storages-adapter-s3 - - Google Cloud Storage
@rytass/storages-adapter-gcs - - Cloudflare R2
@rytass/storages-adapter-r2 - - Azure Blob Storage
@rytass/storages-adapter-azure-blob - - 本地文件系统
@rytass/storages-adapter-local
Architecture
架构
@rytass/storages (Base Package)
│
├── StorageInterface # Core interface all adapters must implement
├── Storage<O> # Base class with helper methods (not abstract)
├── ConverterManager # File converter pipeline system (from @rytass/file-converter)
├── Types & Interfaces # Shared type definitions
└── Error Handling # StorageError, ErrorCode enums
@rytass/storages-adapter-* # Provider implementations
│
├── [Provider]Storage # Extends Storage<ProviderOptions>
├── typings.ts # Provider-specific option types
└── index.ts # Package exports@rytass/storages (Base Package)
│
├── StorageInterface # Core interface all adapters must implement
├── Storage<O> # Base class with helper methods (not abstract)
├── ConverterManager # File converter pipeline system (from @rytass/file-converter)
├── Types & Interfaces # Shared type definitions
└── Error Handling # StorageError, ErrorCode enums
@rytass/storages-adapter-* # Provider implementations
│
├── [Provider]Storage # Extends Storage<ProviderOptions>
├── typings.ts # Provider-specific option types
└── index.ts # Package exportsCore Concepts
核心概念
- InputFile: - Files to upload can be either in-memory buffers or streams
Buffer | Readable - StorageFile: - Uploaded file reference containing the storage key/path
{ key: string } - Hash-Based Naming: Automatically generate unique filenames using SHA1 or SHA256 hash of file content
- File Converters: Transform or process files during upload (e.g., image resizing, watermarking)
- Unified Interface: All adapters implement the same methods for seamless provider switching
- InputFile:- 待上传的文件可以是内存缓冲区或流
Buffer | Readable - StorageFile:- 已上传文件的引用,包含存储键/路径
{ key: string } - 基于哈希的命名:通过文件内容的SHA1或SHA256哈希自动生成唯一文件名
- 文件转换器:在上传过程中转换或处理文件(例如图片缩放、添加水印)
- 统一接口:所有adapter实现相同的方法,实现存储提供商的无缝切换
Installation
安装
bash
npm install @rytass/storagesbash
npm install @rytass/storagesQuick Reference
快速参考
Core Interfaces
核心接口
StorageInterfacetypescript
interface StorageInterface {
// Upload operations (Note: options are NOT part of the interface)
write(file: InputFile): Promise<StorageFile>;
batchWrite(files: InputFile[]): Promise<StorageFile[]>;
// Download operations
read(key: string): Promise<Readable>;
read(key: string, options: ReadBufferFileOptions): Promise<Buffer>;
read(key: string, options: ReadStreamFileOptions): Promise<Readable>;
// File management
remove(key: string): Promise<void>;
// Note: isExists() is NOT part of the interface, it's in Storage class
}Storage<O>typescript
class Storage<O extends Record<string, unknown> = Record<string, unknown>>
implements StorageInterface {
// Provided by base class
readonly converterManager: ConverterManager;
readonly hashAlgorithm: FilenameHashAlgorithm;
constructor(options?: StorageOptions<O>);
// File type detection helpers
getExtension(file: InputFile): Promise<FileTypeResult | undefined>;
getBufferFilename(buffer: Buffer): Promise<[string, string | undefined]>;
getStreamFilename(stream: Readable): Promise<[string, string | undefined]>;
// Methods to override (throw Error by default, subclasses must override)
write(file: InputFile, options?: WriteFileOptions): Promise<StorageFile>;
batchWrite(files: InputFile[], options?: WriteFileOptions[]): Promise<StorageFile[]>;
read(key: string): Promise<Readable>;
read(key: string, options: ReadBufferFileOptions): Promise<Buffer>;
read(key: string, options: ReadStreamFileOptions): Promise<Readable>;
remove(key: string): Promise<void>;
// Additional method to override (NOT in StorageInterface)
isExists(key: string): Promise<boolean>;
}Note: Theclass is NOT abstract. Instead, methods throwStorageby default, requiring subclasses to override them. TheError('Method not implemented.')andwritemethods acceptbatchWriteparameter in the implementation but NOT inoptions.StorageInterface
StorageInterfacetypescript
interface StorageInterface {
// Upload operations (Note: options are NOT part of the interface)
write(file: InputFile): Promise<StorageFile>;
batchWrite(files: InputFile[]): Promise<StorageFile[]>;
// Download operations
read(key: string): Promise<Readable>;
read(key: string, options: ReadBufferFileOptions): Promise<Buffer>;
read(key: string, options: ReadStreamFileOptions): Promise<Readable>;
// File management
remove(key: string): Promise<void>;
// Note: isExists() is NOT part of the interface, it's in Storage class
}Storage<O>typescript
class Storage<O extends Record<string, unknown> = Record<string, unknown>>
implements StorageInterface {
// Provided by base class
readonly converterManager: ConverterManager;
readonly hashAlgorithm: FilenameHashAlgorithm;
constructor(options?: StorageOptions<O>);
// File type detection helpers
getExtension(file: InputFile): Promise<FileTypeResult | undefined>;
getBufferFilename(buffer: Buffer): Promise<[string, string | undefined]>;
getStreamFilename(stream: Readable): Promise<[string, string | undefined]>;
// Methods to override (throw Error by default, subclasses must override)
write(file: InputFile, options?: WriteFileOptions): Promise<StorageFile>;
batchWrite(files: InputFile[], options?: WriteFileOptions[]): Promise<StorageFile[]>;
read(key: string): Promise<Readable>;
read(key: string, options: ReadBufferFileOptions): Promise<Buffer>;
read(key: string, options: ReadStreamFileOptions): Promise<Readable>;
remove(key: string): Promise<void>;
// Additional method to override (NOT in StorageInterface)
isExists(key: string): Promise<boolean>;
}注意:类并非抽象类。默认情况下,其方法会抛出Storage,要求子类重写这些方法。Error('Method not implemented.')和write方法在实现中支持batchWrite参数,但该参数并未包含在options中。StorageInterface
Must Implement
必须实现的内容
All adapters extending MUST override these methods (not abstract, but throw by default):
Storage<O>| Method | Source | Description |
|---|---|---|
| Storage class (options not in interface) | Upload a single file and return storage key |
| Storage class (options not in interface) | Upload multiple files in parallel |
| StorageInterface | Download file as Buffer or Stream |
| StorageInterface | Delete a file |
| Storage class only | Check if file exists (not in interface) |
Note:is defined in theisExists()class but NOT inStorage. This means adapters must implement it, but code depending only onStorageInterfacecannot assume it exists. Similarly, theStorageInterfaceparameter foroptionsandwriteis only in thebatchWriteclass implementation.Storage
所有继承的adapter必须重写以下方法(这些方法并非抽象方法,但默认会抛出异常):
Storage<O>| 方法 | 来源 | 描述 |
|---|---|---|
| Storage类(options未在接口中定义) | 上传单个文件并返回存储键 |
| Storage类(options未在接口中定义) | 并行上传多个文件 |
| StorageInterface | 将文件下载为Buffer或Stream |
| StorageInterface | 删除文件 |
| 仅Storage类 | 检查文件是否存在(未在接口中定义) |
注意:定义在isExists()类中,但并未包含在Storage里。这意味着adapter必须实现该方法,但仅依赖StorageInterface的代码无法假定该方法存在。同样,StorageInterface和write的batchWrite参数仅在Storage类的实现中存在。options
Optional Features
可选功能
Adapters MAY implement these additional methods:
| Method | Description | Example |
|---|---|---|
| Generate presigned/signed URL for temporary access | Cloud adapters (S3, GCS, R2, Azure) |
| Custom helpers | Provider-specific utilities | |
Adapter可以实现以下额外方法:
| 方法 | 描述 | 示例 |
|---|---|---|
| 生成预签名/签名URL以提供临时访问权限 | 云adapter(S3、GCS、R2、Azure) |
| 自定义辅助方法 | 提供商特定的工具函数 | 本地adapter中的 |
Common Types
通用类型
typescript
// Input/Output Types (from @rytass/file-converter)
type ConvertableFile = Readable | Buffer;
type InputFile = ConvertableFile; // Re-exported alias
type FileKey = string;
interface StorageFile {
readonly key: FileKey;
}
// Options Types
interface StorageOptions<O extends Record<string, unknown>> {
converters?: FileConverter<O>[];
hashAlgorithm?: 'sha1' | 'sha256';
}
interface WriteFileOptions {
filename?: string; // Custom filename (overrides hash-based generation)
contentType?: string; // MIME type for the file
}
// Read Format Options
interface ReadBufferFileOptions {
format: 'buffer';
}
interface ReadStreamFileOptions {
format: 'stream';
}typescript
// Input/Output Types (from @rytass/file-converter)
type ConvertableFile = Readable | Buffer;
type InputFile = ConvertableFile; // Re-exported alias
type FileKey = string;
interface StorageFile {
readonly key: FileKey;
}
// Options Types
interface StorageOptions<O extends Record<string, unknown>> {
converters?: FileConverter<O>[];
hashAlgorithm?: 'sha1' | 'sha256';
}
interface WriteFileOptions {
filename?: string; // Custom filename (overrides hash-based generation)
contentType?: string; // MIME type for the file
}
// Read Format Options
interface ReadBufferFileOptions {
format: 'buffer';
}
interface ReadStreamFileOptions {
format: 'stream';
}Error Codes
错误码
typescript
enum ErrorCode {
WRITE_FILE_ERROR = '101', // Failed to upload file
READ_FILE_ERROR = '102', // Failed to download file
REMOVE_FILE_ERROR = '103', // Failed to delete file
UNRECOGNIZED_ERROR = '104', // Unknown error
DIRECTORY_NOT_FOUND = '201', // Directory doesn't exist (Local adapter)
FILE_NOT_FOUND = '202', // File doesn't exist
}typescript
enum ErrorCode {
WRITE_FILE_ERROR = '101', // Failed to upload file
READ_FILE_ERROR = '102', // Failed to download file
REMOVE_FILE_ERROR = '103', // Failed to delete file
UNRECOGNIZED_ERROR = '104', // Unknown error
DIRECTORY_NOT_FOUND = '201', // Directory doesn't exist (Local adapter)
FILE_NOT_FOUND = '202', // File doesn't exist
}Key Responsibilities
主要职责
When implementing a new storage adapter, you are responsible for:
- Extending - Inherit from the base class
Storage<YourOptions> - Defining Configuration Interface - Specify required and optional settings
- Overriding Required Methods - Override methods that throw by default
- Handling Buffers and Streams - Support both input formats
- Using Hash-Based Filenames - Leverage /
getBufferFilename()getStreamFilename() - Integrating File Converters - Apply before upload
converterManager.convert() - Throwing Appropriate Errors - Use with correct
StorageErrorErrorCode - Writing Tests - Ensure reliability and correctness
在实现新的存储adapter时,你需要负责以下内容:
- 继承- 从基础类继承
Storage<YourOptions> - 定义配置接口 - 指定必填和可选配置项
- 重写必需方法 - 重写默认会抛出异常的方法
- 处理缓冲区和流 - 支持两种输入格式
- 使用基于哈希的文件名 - 利用/
getBufferFilename()方法getStreamFilename() - 集成文件转换器 - 在上传前调用
converterManager.convert() - 抛出合适的错误 - 使用带有正确的
ErrorCodeStorageError - 编写测试 - 确保可靠性和正确性
File Converter System
文件转换器系统
The base package includes a converter system for processing files during upload:
typescript
// From @rytass/file-converter
type ConvertableFile = Readable | Buffer;
interface FileConverter<O = Record<string, unknown>> {
convert<Buffer>(file: ConvertableFile): Promise<Buffer>;
convert<Readable>(file: ConvertableFile): Promise<Readable>;
}
class ConverterManager {
constructor(converters: FileConverter[]);
convert<ConvertableFileFormat extends ConvertableFile>(file: ConvertableFile): Promise<ConvertableFileFormat>;
}
// Usage in adapter
const convertedFile = await this.converterManager.convert(inputFile);Example converters:
- Image resizing
- Image watermarking
- Format transcoding
- Compression
Converters are executed in sequence before the file is uploaded to the storage provider.
基础包包含一个转换器系统,用于在上传过程中处理文件:
typescript
// From @rytass/file-converter
type ConvertableFile = Readable | Buffer;
interface FileConverter<O = Record<string, unknown>> {
convert<Buffer>(file: ConvertableFile): Promise<Buffer>;
convert<Readable>(file: ConvertableFile): Promise<Readable>;
}
class ConverterManager {
constructor(converters: FileConverter[]);
convert<ConvertableFileFormat extends ConvertableFile>(file: ConvertableFile): Promise<ConvertableFileFormat>;
}
// Usage in adapter
const convertedFile = await this.converterManager.convert(inputFile);转换器示例:
- 图片缩放
- 图片添加水印
- 格式转码
- 压缩
转换器会在文件上传到存储提供商之前按顺序执行。
Detailed Documentation
详细文档
For complete interface specifications and step-by-step implementation guide:
- Base Interfaces Reference - Complete type definitions and interface specifications
- Creating an Adapter - Step-by-step guide to implementing a new storage adapter
如需完整的接口规范和分步实现指南:
- 基础接口参考 - 完整的类型定义和接口规范
- 创建Adapter - 实现新存储adapter的分步指南