@data-loom/storage-js 0.4.4-alpha.5 → 0.4.4-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,7 +7,7 @@ Dataloom 存储服务 JavaScript SDK,基于 Supabase Storage 修改而来,
7
7
  - 📁 **文件上传和下载** - 支持多种文件格式的上传和下载
8
8
  - 🔗 **签名URL** - 创建具有时效性的安全文件访问链接
9
9
  - 🗑️ **文件管理** - 删除、列表等文件操作
10
- - 🖼️ **图片转换** - 支持图片尺寸调整、质量优化等转换功能
10
+ - 🌐 **URL复制** - 从公共URL复制文件到存储桶
11
11
  - 📊 **批量操作** - 支持批量创建签名URL等批量操作
12
12
  - 🔍 **文件搜索** - 支持文件搜索和分页
13
13
  - 🛡️ **错误处理** - 完善的错误处理机制
@@ -77,69 +77,183 @@ constructor(
77
77
  )
78
78
  ```
79
79
 
80
+ ---
81
+
80
82
  ### 文件上传
81
83
 
82
- #### `uploadFile(fileBody, fileOptions?)` **(推荐)**
84
+ #### `upload(path, fileBody, fileOptions?)` - 重载1
83
85
 
84
- 使用文件选项上传文件(推荐, 无需关注filePath)。
86
+ 上传文件到指定的存储桶路径。
85
87
 
86
- **参数:**
87
- - `fileBody` (FileBody): 文件内容
88
- - `fileOptions` (FileOptionsV2, 可选): 文件选项,可指定 filePath 等
88
+ **入参:**
89
+ ```typescript
90
+ function upload(
91
+ path: string, // 文件路径,格式为 `folder/subfolder/filename.png`
92
+ fileBody: FileBody, // 文件内容
93
+ fileOptions?: FileOptions // 上传选项
94
+ ): Promise<UploadResult>
95
+ ```
89
96
 
90
- **返回:** 同 `upload` 方法
97
+ **出参:**
98
+ ```typescript
99
+ type UploadResult =
100
+ | { data: UploadFileData; error: null }
101
+ | { data: null; error: StorageError }
102
+ ```
91
103
 
92
104
  **示例:**
93
105
  ```javascript
94
- const { data, error } = await storage.uploadFile(file, {
95
- filePath: 'documents/report.pdf',
106
+ const { data, error } = await storage.upload('avatars/user-123.jpg', file, {
96
107
  cacheControl: 3600,
108
+ contentType: 'image/jpeg',
109
+ upsert: false
110
+ });
111
+ ```
112
+
113
+ ---
114
+
115
+ #### `upload(fileBody, fileOptions?)` - 重载2
116
+
117
+ 使用 FileOptionsV2 上传文件,路径通过 options.filePath 指定。
118
+
119
+ **入参:**
120
+ ```typescript
121
+ function upload(
122
+ fileBody: FileBody, // 文件内容
123
+ fileOptions?: FileOptionsV2 // 上传选项(包含 filePath)
124
+ ): Promise<UploadResult>
125
+ ```
126
+
127
+ **出参:**
128
+ ```typescript
129
+ type UploadResult =
130
+ | { data: UploadFileData; error: null }
131
+ | { data: null; error: StorageError }
132
+ ```
133
+
134
+ **示例:**
135
+ ```javascript
136
+ const { data, error } = await storage.upload(file, {
137
+ filePath: 'documents/report.pdf',
97
138
  contentType: 'application/pdf',
98
139
  contentDisposition: 'attachment; filename="report.pdf"'
99
140
  });
100
141
  ```
101
142
 
102
- #### `upload(path, fileBody, fileOptions?)`
143
+ ---
103
144
 
104
- 上传文件到指定的存储桶路径。
145
+ #### `uploadFile(fileBody, fileOptions?)`
105
146
 
106
- **参数:**
107
- - `path` (string): 文件路径,格式为 `folder/subfolder/filename.png`
108
- - `fileBody` (FileBody): 文件内容,支持多种格式
109
- - `fileOptions` (FileOptions, 可选): 文件选项
147
+ 使用文件选项上传文件(推荐,与 upload 重载2 功能相同)。
110
148
 
111
- **返回:**
149
+ **入参:**
112
150
  ```typescript
113
- {
114
- data: UploadFileData; // 包含文件ID、路径、存储桶ID和下载URL
115
- error: null;
116
- } | {
117
- data: null;
118
- error: StorageError;
119
- }
151
+ function uploadFile(
152
+ fileBody: FileBody, // 文件内容
153
+ fileOptions?: FileOptionsV2 // 上传选项
154
+ ): Promise<UploadResult>
155
+ ```
156
+
157
+ **出参:**
158
+ ```typescript
159
+ type UploadResult =
160
+ | { data: UploadFileData; error: null }
161
+ | { data: null; error: StorageError }
120
162
  ```
121
163
 
122
164
  **示例:**
123
165
  ```javascript
124
- const fileInput = document.getElementById('fileInput');
125
- const file = fileInput.files[0];
126
-
127
- const { data, error } = await storage.upload('avatars/user-123.jpg', file, {
128
- cacheControl: '3600',
129
- contentType: 'image/jpeg',
130
- upsert: false
166
+ const { data, error } = await storage.uploadFile(file, {
167
+ filePath: 'documents/report.pdf',
168
+ cacheControl: 3600,
169
+ contentType: 'application/pdf',
170
+ contentDisposition: 'attachment; filename="report.pdf"'
131
171
  });
132
172
  ```
133
173
 
174
+ ---
175
+
134
176
  ### 文件更新
135
177
 
136
178
  #### `update(path, fileBody, fileOptions?)`
137
179
 
138
180
  替换指定路径的现有文件。
139
181
 
140
- **参数:** 同 `upload` 方法
182
+ **入参:**
183
+ ```typescript
184
+ function update(
185
+ path: string, // 文件路径
186
+ fileBody: FileBody, // 文件内容
187
+ fileOptions?: FileOptions // 上传选项
188
+ ): Promise<UploadResult>
189
+ ```
190
+
191
+ **出参:**
192
+ ```typescript
193
+ type UploadResult =
194
+ | { data: UploadFileData; error: null }
195
+ | { data: null; error: StorageError }
196
+ ```
197
+
198
+ ---
199
+
200
+ ### 从URL复制文件
201
+
202
+ #### `copyFromUrl(url, fileOptions?)`
203
+
204
+ 从公共URL下载文件并上传到存储桶。自动透传响应头(content-type、content-disposition、cache-control)到上传请求。
205
+
206
+ **入参:**
207
+ ```typescript
208
+ function copyFromUrl(
209
+ url: string, // 公共文件URL(如 CDN 链接)
210
+ fileOptions?: CopyFileOptions // 上传选项
211
+ ): Promise<CopyFromUrlResult>
212
+ ```
213
+
214
+ **出参:**
215
+ ```typescript
216
+ type CopyFromUrlResult =
217
+ | { data: UploadFileData; error: null }
218
+ | { data: null; error: StorageError }
219
+ ```
141
220
 
142
- **返回:** 同 `upload` 方法
221
+ **功能特性:**
222
+ - ✅ 只允许 `http://` 和 `https://` 协议
223
+ - ✅ 自动透传响应头到上传请求(contentType、contentDisposition、cacheControl)
224
+ - ✅ 检测并拒绝空文件
225
+
226
+ **示例:**
227
+ ```javascript
228
+ // 基本用法
229
+ const { data, error } = await storage.copyFromUrl(
230
+ 'https://cdn.example.com/images/photo.jpg'
231
+ );
232
+
233
+ // 指定上传路径
234
+ const { data, error } = await storage.copyFromUrl(
235
+ 'https://cdn.example.com/images/photo.jpg',
236
+ {
237
+ filePath: 'backups/photo-copy.jpg'
238
+ }
239
+ );
240
+ ```
241
+
242
+ **错误处理:**
243
+ ```javascript
244
+ const { data, error } = await storage.copyFromUrl('https://example.com/file.pdf');
245
+
246
+ if (error) {
247
+ // 可能的错误类型:
248
+ // - 'Invalid URL provided' - URL格式无效
249
+ // - 'Only http and https protocols are supported' - 协议不支持
250
+ // - 'Failed to download file from URL: 404 Not Found' - 下载失败
251
+ // - 'Downloaded file is empty' - 下载的文件为空
252
+ console.error(error.message);
253
+ }
254
+ ```
255
+
256
+ ---
143
257
 
144
258
  ### 创建签名URL
145
259
 
@@ -147,22 +261,23 @@ const { data, error } = await storage.upload('avatars/user-123.jpg', file, {
147
261
 
148
262
  创建具有时效性的安全文件访问链接。
149
263
 
150
- **参数:**
151
- - `path` (string): 文件路径或上传接口返回的download_url
152
- - `expiresIn` (number): 过期时间(秒)
153
- - `options` (object, 可选): 选项
154
- - `download` (string | boolean): 是否触发下载,可指定文件名
155
- - `transform` (TransformOptions): 图片转换选项
156
-
157
- **返回:**
158
- ```typescript
159
- {
160
- data: { signedUrl: string };
161
- error: null;
162
- } | {
163
- data: null;
164
- error: StorageError;
165
- }
264
+ **入参:**
265
+ ```typescript
266
+ function createSignedUrl(
267
+ path: string, // 文件路径或 download_url
268
+ expiresIn: number, // 过期时间(秒)
269
+ options?: {
270
+ download?: string | boolean; // 是否触发下载
271
+ transform?: TransformOptions; // 图片转换选项
272
+ }
273
+ ): Promise<SignedUrlResult>
274
+ ```
275
+
276
+ **出参:**
277
+ ```typescript
278
+ type SignedUrlResult =
279
+ | { data: { signedUrl: string }; error: null }
280
+ | { data: null; error: StorageError }
166
281
  ```
167
282
 
168
283
  **示例:**
@@ -181,80 +296,99 @@ const { data, error } = await storage.createSignedUrl('images/photo.jpg', 3600,
181
296
  });
182
297
  ```
183
298
 
299
+ ---
300
+
184
301
  #### `createSignedUrls(paths, expiresIn, options?)`
185
302
 
186
303
  批量创建签名URL。
187
304
 
188
- **参数:**
189
- - `paths` (string[]): 文件路径或上传接口返回的download_url数组
190
- - `expiresIn` (number): 过期时间(秒)
191
- - `options` (object, 可选): 选项
192
-
193
- **返回:**
194
- ```typescript
195
- {
196
- data: Array<{
197
- error: string | null;
198
- path: string | null;
199
- signedUrl: string;
200
- }>;
201
- error: null;
202
- } | {
203
- data: null;
204
- error: StorageError;
205
- }
305
+ **入参:**
306
+ ```typescript
307
+ function createSignedUrls(
308
+ paths: string[], // 文件路径或 download_url 数组
309
+ expiresIn: number, // 过期时间(秒)
310
+ options?: {
311
+ download?: string | boolean;
312
+ }
313
+ ): Promise<SignedUrlsResult>
206
314
  ```
207
315
 
316
+ **出参:**
317
+ ```typescript
318
+ type SignedUrlsResult =
319
+ | {
320
+ data: Array<{
321
+ error: string | null;
322
+ path: string | null;
323
+ signedUrl: string;
324
+ }>;
325
+ error: null
326
+ }
327
+ | { data: null; error: StorageError }
328
+ ```
329
+
330
+ **示例:**
331
+ ```javascript
332
+ const { data, error } = await storage.createSignedUrls(
333
+ ['file1.pdf', 'file2.pdf', 'file3.pdf'],
334
+ 3600
335
+ );
336
+ ```
337
+
338
+ ---
339
+
208
340
  ### 文件下载
209
341
 
210
342
  #### `download(path, options?)`
211
343
 
212
344
  从私有存储桶下载文件。
213
345
 
214
- **参数:**
215
- - `path` (string): 文件路径
216
- - `options` (object, 可选): 选项
217
- - `transform` (TransformOptions): 图片转换选项
346
+ **入参:**
347
+ ```typescript
348
+ function download(
349
+ path: string, // 文件路径
350
+ options?: {
351
+ transform?: TransformOptions; // 图片转换选项
352
+ }
353
+ ): Promise<DownloadResult>
354
+ ```
218
355
 
219
- **返回:**
356
+ **出参:**
220
357
  ```typescript
221
- {
222
- data: Blob;
223
- error: null;
224
- } | {
225
- data: null;
226
- error: StorageError;
227
- }
358
+ type DownloadResult =
359
+ | { data: Blob; error: null }
360
+ | { data: null; error: StorageError }
228
361
  ```
229
362
 
230
363
  **示例:**
231
364
  ```javascript
232
365
  const { data, error } = await storage.download('documents/report.pdf');
233
366
  if (data) {
234
- // 处理下载的文件数据
235
367
  const url = URL.createObjectURL(data);
236
368
  window.open(url);
237
369
  }
238
370
  ```
239
371
 
372
+ ---
373
+
240
374
  ### 文件删除
241
375
 
242
376
  #### `remove(paths)`
243
377
 
244
378
  删除指定路径的文件。
245
379
 
246
- **参数:**
247
- - `paths` (string[]): 要删除的文件路径或上传接口返回的download_url数组
380
+ **入参:**
381
+ ```typescript
382
+ function remove(
383
+ paths: string[] // 文件路径或 download_url 数组
384
+ ): Promise<RemoveResult>
385
+ ```
248
386
 
249
- **返回:**
387
+ **出参:**
250
388
  ```typescript
251
- {
252
- data: FileObject[]; // 被删除的文件信息
253
- error: null;
254
- } | {
255
- data: null;
256
- error: StorageError;
257
- }
389
+ type RemoveResult =
390
+ | { data: FileObject[]; error: null }
391
+ | { data: null; error: StorageError }
258
392
  ```
259
393
 
260
394
  **示例:**
@@ -265,26 +399,28 @@ const { data, error } = await storage.remove([
265
399
  ]);
266
400
  ```
267
401
 
402
+ ---
403
+
268
404
  ### 文件列表
269
405
 
270
406
  #### `list(path?, options?, parameters?)`
271
407
 
272
408
  列出存储桶中的文件。
273
409
 
274
- **参数:**
275
- - `path` (string, 可选): 文件夹路径
276
- - `options` (SearchOptions, 可选): 搜索选项
277
- - `parameters` (FetchParameters, 可选): 请求参数
410
+ **入参:**
411
+ ```typescript
412
+ function list(
413
+ path?: string, // 文件夹路径
414
+ options?: SearchOptions, // 搜索选项
415
+ parameters?: FetchParameters // 请求参数
416
+ ): Promise<ListResult>
417
+ ```
278
418
 
279
- **返回:**
419
+ **出参:**
280
420
  ```typescript
281
- {
282
- data: FileObject[]; // 文件列表
283
- error: null;
284
- } | {
285
- data: null;
286
- error: StorageError;
287
- }
421
+ type ListResult =
422
+ | { data: FileObject[]; error: null }
423
+ | { data: null; error: StorageError }
288
424
  ```
289
425
 
290
426
  **示例:**
@@ -304,99 +440,217 @@ const { data, error } = await storage.list('documents', {
304
440
  });
305
441
  ```
306
442
 
443
+ ---
444
+
307
445
  ## 类型定义
308
446
 
309
447
  ### FileBody
448
+
310
449
  支持以下文件格式:
311
- - `ArrayBuffer`
312
- - `ArrayBufferView`
313
- - `Blob`
314
- - `Buffer`
315
- - `File`
316
- - `FormData`
317
- - `NodeJS.ReadableStream`
318
- - `ReadableStream<Uint8Array>`
319
- - `URLSearchParams`
320
- - `string`
450
+
451
+ ```typescript
452
+ type FileBody =
453
+ | ArrayBuffer
454
+ | ArrayBufferView
455
+ | Blob
456
+ | Buffer
457
+ | File
458
+ | FormData
459
+ | NodeJS.ReadableStream
460
+ | ReadableStream<Uint8Array>
461
+ | URLSearchParams
462
+ | string;
463
+ ```
321
464
 
322
465
  ### FileOptions
466
+
323
467
  ```typescript
324
468
  interface FileOptions {
325
- cacheControl?: string | number; // 缓存控制(秒)
326
- contentType?: string; // 内容类型
327
- upsert?: boolean; // 是否覆盖已存在文件
328
- duplex?: string; // 双工流选项
329
- metadata?: Record<string, any>; // 元数据
330
- headers?: Record<string, string>; // 额外请求头
469
+ /** 缓存控制时间(秒),设置 Cache-Control: max-age=<seconds> 头 */
470
+ cacheControl?: string | number;
471
+ /** Content-Type 头值 */
472
+ contentType?: string;
473
+ /** 是否覆盖已存在文件,默认 false */
474
+ upsert?: boolean;
475
+ /** 双工流选项 */
476
+ duplex?: string;
477
+ /** 文件元数据 */
478
+ metadata?: Record<string, any>;
479
+ /** 额外请求头 */
480
+ headers?: Record<string, string>;
331
481
  }
332
482
  ```
333
483
 
334
484
  ### FileOptionsV2
485
+
335
486
  ```typescript
336
487
  interface FileOptionsV2 {
337
- filePath?: string; // 文件路径(用于 uploadFile)
338
- cacheControl?: string | number; // 缓存控制(秒)
339
- contentType?: string; // 内容类型
340
- upsert?: boolean; // 是否覆盖已存在文件
341
- contentDisposition?: string; // 内容处置
488
+ /** 文件上传路径 */
489
+ filePath?: string;
490
+ /** 缓存控制时间(秒) */
491
+ cacheControl?: string | number;
492
+ /** Content-Type 头值 */
493
+ contentType?: string;
494
+ /** 是否覆盖已存在文件,默认 false */
495
+ upsert?: boolean;
496
+ /** Content-Disposition 响应头值 */
497
+ contentDisposition?: string;
342
498
  }
343
499
  ```
344
500
 
345
- ### TransformOptions
501
+ ### CopyFileOptions
502
+
346
503
  ```typescript
347
- interface TransformOptions {
348
- width?: number; // 宽度(像素)
349
- height?: number; // 高度(像素)
350
- resize?: 'cover' | 'contain' | 'fill'; // 调整大小模式
351
- quality?: number; // 质量(20-100)
352
- format?: 'origin'; // 格式
504
+ interface CopyFileOptions {
505
+ /** 文件上传路径 */
506
+ filePath?: string;
353
507
  }
354
508
  ```
355
509
 
356
510
  ### UploadFileData
511
+
357
512
  ```typescript
358
513
  interface UploadFileData {
359
- id: string; // 文件ID
360
- file_path: string; // 文件路径
361
- bucket_id: string; // 存储桶ID
362
- download_url: string; // 下载URL
514
+ /** 文件ID */
515
+ id: string;
516
+ /** 文件路径 */
517
+ file_path: string;
518
+ /** 存储桶ID */
519
+ bucket_id: string;
520
+ /** 下载URL */
521
+ download_url: string;
363
522
  }
364
523
  ```
365
524
 
366
525
  ### FileObject
526
+
367
527
  ```typescript
368
528
  interface FileObject {
369
- name: string; // 文件名
370
- bucket_id: string; // 存储桶ID
371
- owner: string; // 所有者
372
- id: string; // 文件ID
373
- updated_at: string; // 更新时间
374
- created_at: string; // 创建时间
375
- created_by: string; // 创建者
376
- updated_by: string; // 更新者
377
- last_accessed_at?: string; // 最后访问时间
378
- metadata: Record<string, any>; // 元数据
379
- buckets: Bucket; // 存储桶信息
529
+ /** 文件名 */
530
+ name: string;
531
+ /** 存储桶ID */
532
+ bucket_id: string;
533
+ /** 所有者 */
534
+ owner: string;
535
+ /** 文件ID */
536
+ id: string;
537
+ /** 更新时间 */
538
+ updated_at: string;
539
+ /** 创建时间 */
540
+ created_at: string;
541
+ /** 创建者 */
542
+ created_by: string;
543
+ /** 更新者 */
544
+ updated_by: string;
545
+ /** 最后访问时间 */
546
+ last_accessed_at?: string;
547
+ /** 元数据 */
548
+ metadata: Record<string, any>;
549
+ /** 存储桶信息 */
550
+ buckets: Bucket;
551
+ }
552
+ ```
553
+
554
+ ### Bucket
555
+
556
+ ```typescript
557
+ interface Bucket {
558
+ /** 存储桶ID */
559
+ id: string;
560
+ /** 存储桶类型 */
561
+ type?: 'STANDARD' | 'ANALYTICS';
562
+ /** 存储桶名称 */
563
+ name: string;
564
+ /** 所有者 */
565
+ owner: string;
566
+ /** 文件大小限制 */
567
+ file_size_limit?: number;
568
+ /** 允许的MIME类型 */
569
+ allowed_mime_types?: string[];
570
+ /** 创建时间 */
571
+ created_at: string;
572
+ /** 更新时间 */
573
+ updated_at: string;
574
+ /** 是否公开 */
575
+ public: boolean;
380
576
  }
381
577
  ```
382
578
 
383
579
  ### SearchOptions
580
+
384
581
  ```typescript
385
582
  interface SearchOptions {
386
- limit?: number; // 返回文件数量(默认100
387
- offset?: number; // 起始位置
388
- sortBy?: SortBy; // 排序选项
389
- search?: string; // 搜索字符串
583
+ /** 返回文件数量,默认 100 */
584
+ limit?: number;
585
+ /** 起始位置 */
586
+ offset?: number;
587
+ /** 排序选项 */
588
+ sortBy?: SortBy;
589
+ /** 搜索字符串 */
590
+ search?: string;
591
+ }
592
+ ```
593
+
594
+ ### SortBy
595
+
596
+ ```typescript
597
+ interface SortBy {
598
+ /** 排序列名 */
599
+ column?: string;
600
+ /** 排序顺序:'asc' | 'desc' */
601
+ order?: string;
602
+ }
603
+ ```
604
+
605
+ ### TransformOptions
606
+
607
+ ```typescript
608
+ interface TransformOptions {
609
+ /** 宽度(像素) */
610
+ width?: number;
611
+ /** 高度(像素) */
612
+ height?: number;
613
+ /** 调整大小模式 */
614
+ resize?: 'cover' | 'contain' | 'fill';
615
+ /** 质量(20-100) */
616
+ quality?: number;
617
+ /** 格式 */
618
+ format?: 'origin';
390
619
  }
391
620
  ```
392
621
 
393
622
  ### FetchParameters
623
+
394
624
  ```typescript
395
625
  interface FetchParameters {
396
- signal?: AbortSignal; // AbortController 信号
626
+ /** AbortController 信号,用于取消请求 */
627
+ signal?: AbortSignal;
628
+ }
629
+ ```
630
+
631
+ ### StorageError
632
+
633
+ ```typescript
634
+ class StorageError extends Error {
635
+ message: string;
397
636
  }
398
637
  ```
399
638
 
639
+ ### OnRequestErrorType
640
+
641
+ ```typescript
642
+ interface OnRequestErrorType {
643
+ code: number;
644
+ details: string;
645
+ hint: string | null;
646
+ message: string;
647
+ status: number;
648
+ statusText: string;
649
+ }
650
+ ```
651
+
652
+ ---
653
+
400
654
  ## 错误处理
401
655
 
402
656
  所有API方法都返回包含 `data` 和 `error` 的对象。当操作成功时,`error` 为 `null`,`data` 包含返回数据;当操作失败时,`data` 为 `null`,`error` 包含错误信息。
@@ -406,13 +660,13 @@ const { data, error } = await storage.upload('test.jpg', file);
406
660
 
407
661
  if (error) {
408
662
  console.error('操作失败:', error.message);
409
- // 错误处理
410
663
  } else {
411
664
  console.log('操作成功:', data);
412
- // 处理返回数据
413
665
  }
414
666
  ```
415
667
 
668
+ ---
669
+
416
670
  ## 高级用法
417
671
 
418
672
  ### 日志记录
@@ -444,7 +698,6 @@ const storage = new StorageFileApi(
444
698
  false,
445
699
  (error) => {
446
700
  console.error('请求错误:', error);
447
- // 自定义错误处理
448
701
  }
449
702
  );
450
703
  ```
@@ -468,6 +721,8 @@ const storage = new StorageFileApi(
468
721
  );
469
722
  ```
470
723
 
724
+ ---
725
+
471
726
  ## 许可证
472
727
 
473
728
  MIT License