@lark-apaas/file-service
v0.1.1
Published
File Service Core Package
Downloads
1,832
Readme
@lark-apaas/file-service
File Service Core Package - 一个基于 TypeScript 实现的 Node.js 文件服务 SDK,提供文件上传、下载、管理等完整功能。
特性
- TypeScript 编写,提供完整的类型定义
- 支持文件上传(支持 Buffer、Blob、File、Stream 等多种格式)
- 支持文件下载(Blob 和 Stream 两种模式,Blob 模式限制 50MB)
- 文件列表查询和搜索
- 文件元数据获取
- 文件删除
- 签名 URL 生成
- 获取当前应用对应的 bucket
环境要求
- Node.js >= 18.0.0
安装
npm install @lark-apaas/file-service或使用 yarn:
yarn add @lark-apaas/file-service快速开始
import { FileService } from '@lark-apaas/file-service';
// 创建 FileService 实例
const fileService = new FileService(fetchClient);
// 上传文件
const result = await fileService.upload({
appId: 'your-app-id',
bucketId: 'your-bucket-id',
fileBody: file,
options: {
fileName: 'example.txt',
contentType: 'text/plain'
}
});
// 下载文件
const { content, metadata } = await fileService.download({
appId: 'your-app-id',
bucketId: 'your-bucket-id',
filePath: 'path/to/file.txt'
});API 文档
初始化
new FileService(fetchClient: FetchClient)
创建 FileService 实例。
参数:
fetchClient: FetchClient- HTTP 客户端实例
interface FetchClient {
request(config: RequestInit): Promise<Response>;
}文件上传
upload(params: UploadParams): Promise<CallbackData | undefined>
上传文件到指定的 bucket。
参数:
interface UploadParams {
appId: string; // 应用 ID
bucketId: string; // 存储桶 ID
fileBody: FileBody; // 文件内容
options?: UploadOptions; // 上传选项
}
type FileBody =
| ArrayBuffer
| Blob
| Buffer
| File
| NodeJS.ArrayBufferView
| NodeJS.ReadableStream // Node.js 可读流
| ReadableStream<Uint8Array> // Web 可读流
| string;
interface UploadOptions {
filePath?: string; // 文件路径(可选)
fileName?: string; // 文件名(可选)
cacheControl?: string | number; // 缓存控制(可选)
contentType?: string; // 内容类型(可选)
upsert?: boolean; // 是否覆盖已存在的文件(可选)
contentDisposition?: string; // 内容处置(可选)
}返回值:
interface CallbackData {
bucketID: string; // 存储桶 ID
filePath: string; // 文件路径
downloadURL: string; // 下载 URL
fileName: string; // 文件名
}示例:
const result = await fileService.upload({
appId: 'app-123',
bucketId: 'bucket-456',
fileBody: fileBuffer,
options: {
fileName: 'document.pdf',
contentType: 'application/pdf',
upsert: true
}
});
console.log(result.downloadURL); // 文件下载地址文件下载
download(params: DownloadParams): FileDownloadBuilder
下载文件,返回 Builder 对象支持链式调用。
参数:
interface DownloadParams {
appId: string; // 应用 ID
bucketId: string; // 存储桶 ID
filePath: string; // 文件路径
}返回值:
返回 FileDownloadBuilder 实例,支持以下两种使用方式:
1. 作为 Promise 使用(默认返回 Blob)
Promise<DownloadResult<Blob>>
interface DownloadResult<T> {
content: T; // 文件内容
metadata: FileMeta | null; // 文件元数据
}限制:
- Blob 模式下文件大小不能超过 50MB,超过 50MB 请使用
asStream()方法
2. 使用 asStream() 方法获取流
download(params).asStream(): Promise<DownloadResult<ReadableStream>>FileMeta 类型定义:
interface FileMeta {
id: string; // 文件 ID
name: string; // 文件名
filePath: string; // 文件路径
metadata: {
contentLength: string; // 文件大小
mimeType: string; // MIME 类型
} & Record<string, string>;
downloadURL: string; // 下载 URL
createdAt: string; // 创建时间
createdBy: User; // 创建者
updatedAt: string; // 更新时间
updatedBy: User; // 更新者
bucketID: string; // 存储桶 ID
}
interface User {
avatar: string; // 用户头像
status: UserStatus; // 用户状态
userID: number; // 用户 ID
email: string; // 用户邮箱
name: string; // 用户名称
userType: string; // 用户类型
}
enum UserStatus {
active = 1,
inactive,
}示例:
// 方式 1: 下载为 Blob (文件大小需小于 50MB)
const { content, metadata } = await fileService.download({
appId: 'app-123',
bucketId: 'bucket-456',
filePath: 'documents/file.pdf'
});
console.log(metadata.name); // 文件名
console.log(metadata.metadata.contentLength); // 文件大小
// 方式 2: 下载为 Stream (推荐用于大文件)
const { content: stream, metadata } = await fileService.download({
appId: 'app-123',
bucketId: 'bucket-456',
filePath: 'documents/large-file.pdf'
}).asStream();
// 使用流
stream.pipeTo(writableStream);创建签名 URL
createSignedUrl(params: SignedUrlParams): Promise<string>
为文件创建临时访问的签名 URL。
参数:
interface SignedUrlParams {
appId: string; // 应用 ID
bucketId: string; // 存储桶 ID
filePath: string; // 文件路径
expiresIn: number; // 过期时间(秒)
}返回值:
string // 签名后的 URL示例:
const signedUrl = await fileService.createSignedUrl({
appId: 'app-123',
bucketId: 'bucket-456',
filePath: 'documents/file.pdf',
expiresIn: 3600 // 1小时后过期
});
console.log(signedUrl); // https://...文件列表
list(params: ListParams): Promise<ListResponse>
获取指定前缀的文件列表。
参数:
interface ListParams {
appId: string; // 应用 ID
bucketId: string; // 存储桶 ID
prefix: string; // 文件路径前缀
searchOptions?: SearchOptions; // 搜索选项(可选)
}
interface SearchOptions {
/**
* 返回的文件数量限制
* @default 100
*/
maxKeys?: number;
/**
* 分页标记,用于获取下一页
*/
continuationToken?: string;
/**
* 排序选项
*/
sortBy?: SortBy;
}
interface SortBy {
column?: string; // 排序列名
order?: string; // 排序顺序(asc/desc)
}返回值:
interface ListResponse {
attachments: FileMeta[]; // 文件列表
hasMore: boolean; // 是否还有更多文件
}示例:
// 基础查询
const result = await fileService.list({
appId: 'app-123',
bucketId: 'bucket-456',
prefix: 'documents/'
});
console.log(result.attachments); // 文件数组
console.log(result.hasMore); // 是否有更多
// 带分页和排序
const result = await fileService.list({
appId: 'app-123',
bucketId: 'bucket-456',
prefix: 'documents/',
searchOptions: {
maxKeys: 50,
sortBy: {
column: 'createdAt',
order: 'desc'
}
}
});删除文件
remove(params: RemoveParams): Promise<FileMeta[]>
删除指定的文件。
参数:
interface RemoveParams {
appId: string; // 应用 ID
bucketId: string; // 存储桶 ID
filePaths: string[]; // 要删除的文件路径数组
}返回值:
FileMeta[] // 已删除的文件元数据数组示例:
const deletedFiles = await fileService.remove({
appId: 'app-123',
bucketId: 'bucket-456',
filePaths: [
'documents/file1.pdf',
'documents/file2.pdf'
]
});
console.log(`已删除 ${deletedFiles.length} 个文件`);获取文件元数据
getFileMetadata(params: MetadataParams): Promise<FileMeta | null>
获取指定文件的元数据信息。
参数:
interface MetadataParams {
appId: string; // 应用 ID
bucketId: string; // 存储桶 ID
filePath: string; // 文件路径
}返回值:
FileMeta | null // 文件元数据,如果文件不存在则返回 null示例:
const metadata = await fileService.getFileMetadata({
appId: 'app-123',
bucketId: 'bucket-456',
filePath: 'documents/file.pdf'
});
if (metadata) {
console.log(metadata.name); // 文件名
console.log(metadata.metadata.contentLength); // 文件大小
console.log(metadata.metadata.mimeType); // MIME 类型
console.log(metadata.createdAt); // 创建时间
} else {
console.log('文件不存在');
}获取默认 Bucket
getDefaultBucket(appId: string): Promise<string>
获取应用的默认存储桶 ID。
参数:
appId: string // 应用 ID返回值:
string // 默认存储桶 ID示例:
const defaultBucketId = await fileService.getDefaultBucket('app-123');
console.log(defaultBucketId); // bucket-456类型定义
完整类型导出
export {
FileService,
FileDownloadBuilder,
StreamDownloadBuilder,
// 类型
FileBody,
ApiResponse,
User,
UserStatus,
FileMeta,
UploadOptions,
SortBy,
SearchOptions,
FetchClient,
RequestConfig,
CustomError,
DownloadResult,
PreUploadResponse,
CallbackResponse,
GetPublishedV2Response,
DownloadInnerResponse,
ListResponse,
RemoveResponse,
GetMetaResponse
};错误处理
SDK 可能抛出以下错误:
HttpError
HTTP 请求失败时抛出。
class HttpError extends Error {
status: string | number; // HTTP 状态码或错误代码
message: string; // 错误消息
body?: string; // 响应体内容(可选)
}常见错误
- Blob 下载超限:
Can't download file blob larger than 50MB, use asStream() instead. - 上传失败:
preUpload failed, uploadURL or uploadID is empty - 下载失败:
download failed, status: xxx - Bucket 不存在:
No bucket found from remote for appId xxx - 文件不存在: 返回
null而不抛出错误
示例:
try {
await fileService.upload({
appId: 'app-123',
bucketId: 'bucket-456',
fileBody: largeFile
});
} catch (error) {
if (error instanceof Error) {
console.error(error.message);
}
}高级用法
自定义 FetchClient
import { FileService } from '@lark-apaas/file-service';
const customFetchClient = {
async request(config: RequestInit): Promise<Response> {
// 自定义请求逻辑,例如添加认证头
const headers = {
...config.headers,
'Authorization': 'Bearer your-token'
};
return fetch(config.url, {
...config,
headers
});
}
};
const fileService = new FileService(customFetchClient);流式上传
支持使用 Node.js Readable Stream 或 Web ReadableStream 上传文件:
import { Readable } from 'stream';
// 方式 1: 使用 Node.js Readable Stream
const nodeStream = Readable.from(['Hello', ' ', 'World']);
await fileService.upload({
appId: 'app-123',
bucketId: 'bucket-456',
fileBody: nodeStream,
options: {
fileName: 'stream-file.txt',
contentType: 'text/plain'
}
});
// 方式 2: 使用自定义 Readable Stream
const customStream = new Readable({
read() {
this.push('custom data');
this.push(null); // 结束流
}
});
await fileService.upload({
appId: 'app-123',
bucketId: 'bucket-456',
fileBody: customStream,
options: { fileName: 'custom-stream.txt' }
});
// 方式 3: 使用生成器创建流
async function* dataGenerator() {
yield 'chunk1';
yield 'chunk2';
yield 'chunk3';
}
const generatorStream = Readable.from(dataGenerator());
await fileService.upload({
appId: 'app-123',
bucketId: 'bucket-456',
fileBody: generatorStream,
options: { fileName: 'generator-file.txt' }
});流式下载大文件
// 下载大文件并保存到磁盘
const { content: stream } = await fileService.download({
appId: 'app-123',
bucketId: 'bucket-456',
filePath: 'large-file.zip'
}).asStream();
// Node.js 环境
import { createWriteStream } from 'fs';
import { Readable } from 'stream';
const fileStream = createWriteStream('output.zip');
Readable.fromWeb(stream).pipe(fileStream);批量操作
// 批量上传
const files = [file1, file2, file3];
const uploadPromises = files.map(file =>
fileService.upload({
appId: 'app-123',
bucketId: 'bucket-456',
fileBody: file,
options: { fileName: file.name }
})
);
const results = await Promise.all(uploadPromises);
// 批量删除
const filePaths = results.map(r => r.filePath);
await fileService.remove({
appId: 'app-123',
bucketId: 'bucket-456',
filePaths
});许可证
MIT
更新日志
0.0.1-alpha.10
- 初始发布版本
- 支持文件上传、下载、列表、删除等核心功能
- 提供完整的 TypeScript 类型定义
