Dataloom service, modified from supabase/storage-js
Dataloom 存储服务 JavaScript SDK,基于 Supabase Storage 修改而来,提供了强大的文件存储和管理功能。
- 📁 文件上传和下载 - 支持多种文件格式的上传和下载
- 🔗 签名URL - 创建具有时效性的安全文件访问链接
- 🗑️ 文件管理 - 删除、列表等文件操作
- 🌐 URL上传 - 从公共URL下载文件并上传到存储桶
- 📊 批量操作 - 支持批量创建签名URL等批量操作
- 🔍 文件搜索 - 支持文件搜索和分页
- 🛡️ 错误处理 - 完善的错误处理机制
``bash`
npm install @data-loom/storage-js
默认推荐使用挂载在 @data-loom/js 中的 storage 接口。
`javascript`
import { createClient } from '@data-loom/js';
const dataloom = createClient(url, key, workspace, {
global: {
brandName: 'your_brand_name',
appId: 'your_app_id',
enableDataloomLog: true,
requestRateLimit: 10,
onError: (error) => {
}
},
});
const { data, error } = await dataloom.storage.from('bucket_id').download('file_path');
或者可以独立使用 storage-js 包。
`javascript
import { StorageClient } from '@data-loom/storage-js'
// 独立初始化存储客户端
const storage = new StorageClient(
storageUrl,
customHeaders,
customFetch,
{
enableLogger: true,
appId: 'your-app-id',
onRequestError: (error) => console.error('请求错误:', error),
},
);
// 上传文件
const { data, error } = await storage.upload('folder/image.png', file);
if (error) {
console.error('上传失败:', error);
} else {
console.log('上传成功:', data);
}
`
`typescript`
constructor(
url: string, // 存储服务URL
headers: { [key: string]: string } = {}, // 请求头
bucketId?: string, // 存储桶ID
appId?: string, // 应用ID
fetch?: Fetch, // 自定义fetch函数
loggerEnabled?: boolean, // 是否启用日志
onRequestError?: (error: OnRequestErrorType) => void // 请求错误回调
)
---
#### upload(path, fileBody, fileOptions?) - 重载1
上传文件到指定的存储桶路径。
入参:
`typescriptfolder/subfolder/filename.png
function upload(
path: string, // 文件路径,格式为 `
fileBody: FileBody, // 文件内容
fileOptions?: FileOptions // 上传选项
): Promise
出参:
`typescript`
type UploadResult =
| { data: UploadFileData; error: null }
| { data: null; error: StorageError }
示例:
`javascript`
const { data, error } = await storage.upload('avatars/user-123.jpg', file, {
cacheControl: 3600,
contentType: 'image/jpeg',
upsert: false
});
---
#### upload(fileBody, fileOptions?) - 重载2
使用 FileOptionsV2 上传文件,路径通过 options.filePath 指定。
入参:
`typescript`
function upload(
fileBody: FileBody, // 文件内容
fileOptions?: FileOptionsV2 // 上传选项(包含 filePath)
): Promise
出参:
`typescript`
type UploadResult =
| { data: UploadFileData; error: null }
| { data: null; error: StorageError }
示例:
`javascript`
const { data, error } = await storage.upload(file, {
filePath: 'documents/report.pdf',
contentType: 'application/pdf',
contentDisposition: 'attachment; filename="report.pdf"'
});
---
#### uploadFile(fileBody, fileOptions?)
使用文件选项上传文件(推荐,与 upload 重载2 功能相同)。
入参:
`typescript`
function uploadFile(
fileBody: FileBody, // 文件内容
fileOptions?: FileOptionsV2 // 上传选项
): Promise
出参:
`typescript`
type UploadResult =
| { data: UploadFileData; error: null }
| { data: null; error: StorageError }
示例:
`javascript`
const { data, error } = await storage.uploadFile(file, {
filePath: 'documents/report.pdf',
cacheControl: 3600,
contentType: 'application/pdf',
contentDisposition: 'attachment; filename="report.pdf"'
});
---
#### update(path, fileBody, fileOptions?)
替换指定路径的现有文件。
入参:
`typescript`
function update(
path: string, // 文件路径
fileBody: FileBody, // 文件内容
fileOptions?: FileOptions // 上传选项
): Promise
出参:
`typescript`
type UploadResult =
| { data: UploadFileData; error: null }
| { data: null; error: StorageError }
---
#### uploadFromUrl(url)
从公共URL上传文件到存储桶。自动透传响应头(content-type、content-disposition、cache-control)到上传请求。对于火山引擎北京区域的 TOS URL,会使用服务端复制优化性能。
入参:
`typescript`
function uploadFromUrl(
url: string // 公共文件URL(如 CDN 链接)
): Promise
出参:
`typescript`
type UploadFromUrlResult =
| { data: UploadFileData; error: null }
| { data: null; error: StorageError }
功能特性:
- ✅ 只允许 http:// 和 https:// 协议
- ✅ 自动透传响应头到上传请求(contentType、contentDisposition、cacheControl)
- ✅ 检测并拒绝空文件
- ✅ 火山引擎北京区域 TOS URL 使用服务端复制优化
示例:
`javascript
// 基本用法
const { data, error } = await storage.uploadFromUrl(
'https://cdn.example.com/images/photo.jpg'
);
if (data) {
console.log('文件上传成功:', data.download_url);
}
`
错误处理:
`javascript
const { data, error } = await storage.uploadFromUrl('https://example.com/file.pdf');
if (error) {
// 可能的错误类型:
// - 'Invalid URL provided' - URL格式无效
// - 'Only http and https protocols are supported' - 协议不支持
// - 'Failed to download file from URL: 404 Not Found' - 下载失败
// - 'Downloaded file is empty' - 下载的文件为空
console.error(error.message);
}
`
---
#### createSignedUrl(path, expiresIn, options?)
创建具有时效性的安全文件访问链接。
入参:
`typescript`
function createSignedUrl(
path: string, // 文件路径或 download_url
expiresIn: number, // 过期时间(秒)
options?: {
download?: string | boolean; // 是否触发下载
transform?: TransformOptions; // 图片转换选项
}
): Promise
出参:
`typescript`
type SignedUrlResult =
| { data: { signedUrl: string }; error: null }
| { data: null; error: StorageError }
示例:
`javascript
// 创建1小时有效的签名URL
const { data, error } = await storage.createSignedUrl('documents/report.pdf', 3600);
// 创建带图片转换的签名URL
const { data, error } = await storage.createSignedUrl('images/photo.jpg', 3600, {
transform: {
width: 300,
height: 200,
resize: 'cover',
quality: 80
}
});
`
---
#### createSignedUrls(paths, expiresIn, options?)
批量创建签名URL。
入参:
`typescript`
function createSignedUrls(
paths: string[], // 文件路径或 download_url 数组
expiresIn: number, // 过期时间(秒)
options?: {
download?: string | boolean;
}
): Promise
出参:
`typescript`
type SignedUrlsResult =
| {
data: Array<{
error: string | null;
path: string | null;
signedUrl: string;
}>;
error: null
}
| { data: null; error: StorageError }
示例:
`javascript`
const { data, error } = await storage.createSignedUrls(
['file1.pdf', 'file2.pdf', 'file3.pdf'],
3600
);
---
#### download(path, options?)
从私有存储桶下载文件。
入参:
`typescript`
function download(
path: string, // 文件路径
options?: {
transform?: TransformOptions; // 图片转换选项
}
): Promise
出参:
`typescript`
type DownloadResult =
| { data: Blob; error: null }
| { data: null; error: StorageError }
示例:
`javascript`
const { data, error } = await storage.download('documents/report.pdf');
if (data) {
const url = URL.createObjectURL(data);
window.open(url);
}
---
#### remove(paths)
删除指定路径的文件。
入参:
`typescript`
function remove(
paths: string[] // 文件路径或 download_url 数组
): Promise
出参:
`typescript`
type RemoveResult =
| { data: FileObject[]; error: null }
| { data: null; error: StorageError }
示例:
`javascript`
const { data, error } = await storage.remove([
'temp/file1.txt',
'temp/file2.txt'
]);
---
#### list(path?, options?, parameters?)
列出存储桶中的文件。
入参:
`typescript`
function list(
path?: string, // 文件夹路径
options?: SearchOptions, // 搜索选项
parameters?: FetchParameters // 请求参数
): Promise
出参:
`typescript`
type ListResult =
| { data: FileObject[]; error: null }
| { data: null; error: StorageError }
示例:
`javascript
// 列出根目录文件
const { data, error } = await storage.list();
// 搜索特定文件夹的文件
const { data, error } = await storage.list('documents', {
limit: 50,
offset: 0,
sortBy: {
column: 'name',
order: 'asc'
},
search: 'report'
});
`
---
支持以下文件格式:
`typescript`
type FileBody =
| ArrayBuffer
| ArrayBufferView
| Blob
| Buffer
| File
| FormData
| NodeJS.ReadableStream
| ReadableStream
| URLSearchParams
| string;
`typescript`
interface FileOptions {
/* 缓存控制时间(秒),设置 Cache-Control: max-age=
cacheControl?: string | number;
/* Content-Type 头值 /
contentType?: string;
/* 是否覆盖已存在文件,默认 false /
upsert?: boolean;
/* 双工流选项 /
duplex?: string;
/* 文件元数据 /
metadata?: Record
/* 额外请求头 /
headers?: Record
}
`typescript`
interface FileOptionsV2 {
/* 文件上传路径 /
filePath?: string;
/* 缓存控制时间(秒) /
cacheControl?: string | number;
/* Content-Type 头值 /
contentType?: string;
/* 是否覆盖已存在文件,默认 false /
upsert?: boolean;
/* Content-Disposition 响应头值 /
contentDisposition?: string;
}
`typescript`
interface UploadFileData {
/* 文件ID /
id: string;
/* 文件路径 /
file_path: string;
/* 存储桶ID /
bucket_id: string;
/* 下载URL /
download_url: string;
}
`typescript`
interface FileObject {
/* 文件名 /
name: string;
/* 存储桶ID /
bucket_id: string;
/* 所有者 /
owner: string;
/* 文件ID /
id: string;
/* 更新时间 /
updated_at: string;
/* 创建时间 /
created_at: string;
/* 创建者 /
created_by: string;
/* 更新者 /
updated_by: string;
/* 最后访问时间 /
last_accessed_at?: string;
/* 元数据 /
metadata: Record
/* 存储桶信息 /
buckets: Bucket;
}
`typescript`
interface Bucket {
/* 存储桶ID /
id: string;
/* 存储桶类型 /
type?: 'STANDARD' | 'ANALYTICS';
/* 存储桶名称 /
name: string;
/* 所有者 /
owner: string;
/* 文件大小限制 /
file_size_limit?: number;
/* 允许的MIME类型 /
allowed_mime_types?: string[];
/* 创建时间 /
created_at: string;
/* 更新时间 /
updated_at: string;
/* 是否公开 /
public: boolean;
}
`typescript`
interface SearchOptions {
/* 返回文件数量,默认 100 /
limit?: number;
/* 起始位置 /
offset?: number;
/* 排序选项 /
sortBy?: SortBy;
/* 搜索字符串 /
search?: string;
}
`typescript`
interface SortBy {
/* 排序列名 /
column?: string;
/* 排序顺序:'asc' | 'desc' /
order?: string;
}
`typescript`
interface TransformOptions {
/* 宽度(像素) /
width?: number;
/* 高度(像素) /
height?: number;
/* 调整大小模式 /
resize?: 'cover' | 'contain' | 'fill';
/* 质量(20-100) /
quality?: number;
/* 格式 /
format?: 'origin';
}
`typescript`
interface FetchParameters {
/* AbortController 信号,用于取消请求 /
signal?: AbortSignal;
}
`typescript`
class StorageError extends Error {
message: string;
}
`typescript`
interface OnRequestErrorType {
code: number;
details: string;
hint: string | null;
message: string;
status: number;
statusText: string;
}
---
所有API方法都返回包含 data 和 error 的对象。当操作成功时,error 为 null,data 包含返回数据;当操作失败时,data 为 null,error 包含错误信息。
`javascript
const { data, error } = await storage.upload('test.jpg', file);
if (error) {
console.error('操作失败:', error.message);
} else {
console.log('操作成功:', data);
}
`
---
可以通过设置 loggerEnabled 参数启用请求日志记录:
`javascript`
const storage = new StorageFileApi(
'https://your-storage-service.com',
{ 'Authorization': 'Bearer your-token' },
'bucket-id',
'app-id',
undefined,
true // 启用日志
);
可以设置请求错误回调函数:
`javascript`
const storage = new StorageFileApi(
'https://your-storage-service.com',
{ 'Authorization': 'Bearer your-token' },
'bucket-id',
'app-id',
undefined,
false,
(error) => {
console.error('请求错误:', error);
}
);
可以传入自定义的 fetch 函数:
`javascript
const customFetch = (url, options) => {
// 自定义 fetch 逻辑
return fetch(url, options);
};
const storage = new StorageFileApi(
'https://your-storage-service.com',
{ 'Authorization': 'Bearer your-token' },
'bucket-id',
'app-id',
customFetch
);
``
---
MIT License