@cloudbase/storage 2.23.4-alpha.0 → 2.24.1

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/src/storage.ts ADDED
@@ -0,0 +1,683 @@
1
+ import { constants, utils, helpers } from '@cloudbase/utilities'
2
+
3
+ import {
4
+ ICloudbaseFileMetaDataRes,
5
+ ICloudbaseFileInfo,
6
+ ICloudbaseUploadFileParams,
7
+ ICloudbaseUploadFileResult,
8
+ ICloudbaseGetUploadMetadataParams,
9
+ ICloudbaseDeleteFileParams,
10
+ ICloudbaseDeleteFileResult,
11
+ ICloudbaseGetTempFileURLResult,
12
+ ICloudbaseGetTempFileURLParams,
13
+ ICloudbaseDownloadFileResult,
14
+ ICloudbaseDownloadFileParams,
15
+ ICloudbaseCopyFileParams,
16
+ ICloudbaseCopyFileResult,
17
+ } from '@cloudbase/types/storage'
18
+
19
+ enum EUploadMethod {
20
+ put = 'put',
21
+ post = 'post',
22
+ }
23
+
24
+ interface IUploadMetadata {
25
+ url: string
26
+ token: string
27
+ authorization: string
28
+ fileId: string
29
+ cosFileId: string
30
+ download_url?: string
31
+ }
32
+
33
+ const { getSdkName, ERRORS, COMMUNITY_SITE_URL } = constants
34
+ const { isArray, isString, isPalinObject, execCallback } = utils
35
+ const { catchErrorsDecorator } = helpers
36
+
37
+ export const COMPONENT_NAME = 'storage'
38
+
39
+ // function basename(path) {
40
+ // const lastSlashIndex = path.lastIndexOf('/')
41
+ // if (lastSlashIndex === -1) return path
42
+ // return path.slice(lastSlashIndex + 1)
43
+ // }
44
+
45
+ const storageGateWay = {
46
+ getUploadInfo: async (
47
+ request,
48
+ params: { path: string; headers?: Record<string, string> },
49
+ customReqOpts: ICloudbaseUploadFileParams['customReqOpts'],
50
+ ) => {
51
+ let res = await request.gateWay(
52
+ {
53
+ path: 'storages',
54
+ name: 'get-objects-upload-info',
55
+ data: [
56
+ {
57
+ objectId: params.path,
58
+ ...(params.headers ? { signedHeader: params.headers } : {}),
59
+ },
60
+ ],
61
+ },
62
+ customReqOpts,
63
+ )
64
+ const data = res.data?.[0] || {}
65
+
66
+ res = {
67
+ ...res,
68
+ data: {
69
+ ...(data.code ? { ...data } : {}),
70
+ authorization: data.authorization,
71
+ token: data.token,
72
+ url: data.uploadUrl,
73
+ fileId: data.cloudObjectId,
74
+ cosFileId: data.cloudObjectMeta,
75
+ download_url: data.downloadUrl,
76
+ },
77
+ }
78
+
79
+ return res
80
+ },
81
+ getDownLoadInfo: async (
82
+ request,
83
+ params: { convertedFileList: Array<{ fileid: string }> },
84
+ customReqOpts: ICloudbaseUploadFileParams['customReqOpts'],
85
+ ) => {
86
+ let res = await request.gateWay(
87
+ {
88
+ path: 'storages',
89
+ name: 'get-objects-download-info',
90
+ data: params.convertedFileList.map((v: any) => ({ cloudObjectId: v.fileid })),
91
+ },
92
+ customReqOpts,
93
+ )
94
+ res = {
95
+ ...res,
96
+ data: {
97
+ download_list: res.data?.map(v => ({
98
+ code: v.code || 'SUCCESS',
99
+ message: v.message,
100
+ fileid: v.cloudObjectId,
101
+ download_url: v.downloadUrl,
102
+ fileID: v.cloudObjectId,
103
+ tempFileURL: v.downloadUrl,
104
+ })),
105
+ },
106
+ }
107
+
108
+ return res
109
+ },
110
+ delete: async (
111
+ request,
112
+ params: { fileList: Array<string> },
113
+ customReqOpts: ICloudbaseUploadFileParams['customReqOpts'],
114
+ ) => {
115
+ let res = await request.gateWay(
116
+ {
117
+ path: 'storages',
118
+ name: 'delete-objects',
119
+ data: params.fileList.map(v => ({ cloudObjectId: v })),
120
+ },
121
+ customReqOpts,
122
+ )
123
+ res = {
124
+ ...res,
125
+ data: {
126
+ delete_list: res.data?.map(v => ({
127
+ code: v.code || 'SUCCESS',
128
+ fileID: v.cloudObjectId,
129
+ message: v.message,
130
+ })),
131
+ },
132
+ }
133
+
134
+ return res
135
+ },
136
+ copyFile: async (
137
+ request,
138
+ params: {
139
+ convertedFileList: Array<{ src_path: string; dst_path: string; overwrite: boolean; remove_original: boolean }>
140
+ },
141
+ customReqOpts: ICloudbaseUploadFileParams['customReqOpts'],
142
+ ) => {
143
+ let res = await request.gateWay(
144
+ {
145
+ path: 'storages',
146
+ name: 'copy-objects',
147
+ data: params.convertedFileList.map((v: any) => ({
148
+ srcPath: v.src_path,
149
+ dstPath: v.dst_path,
150
+ overwrite: v.overwrite,
151
+ removeOriginal: v.remove_original,
152
+ })),
153
+ },
154
+ customReqOpts,
155
+ )
156
+ res = {
157
+ ...res,
158
+ data: {
159
+ copy_list: res.data?.map(v => ({
160
+ code: v.code || 'SUCCESS',
161
+ fileID: v.cloudObjectId,
162
+ message: v.message,
163
+ })),
164
+ },
165
+ }
166
+
167
+ return res
168
+ },
169
+ }
170
+
171
+ export interface ICloudbaseContext {
172
+ config: any
173
+ request: any
174
+ }
175
+
176
+ export class CloudbaseStorage {
177
+ public isGateWay() {
178
+ // @ts-ignore
179
+ const { config } = this
180
+ const endPointMode = config.endPointMode || 'CLOUD_API'
181
+
182
+ return endPointMode === 'GATEWAY'
183
+ }
184
+
185
+ @catchErrorsDecorator({
186
+ customInfo: {
187
+ className: 'Cloudbase',
188
+ methodName: 'uploadFile',
189
+ },
190
+ title: '上传文件失败',
191
+ messages: [
192
+ '请确认以下各项:',
193
+ ' 1 - 调用 uploadFile() 的语法或参数是否正确',
194
+ ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',
195
+ ' 3 - 云存储安全规则是否限制了当前登录状态访问',
196
+ `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
197
+ ],
198
+ })
199
+ public async uploadFile(
200
+ params: Omit<ICloudbaseUploadFileParams, 'filePath'> & { filePath?: string },
201
+ callback?: Function,
202
+ ): Promise<ICloudbaseUploadFileResult> {
203
+ const { cloudPath, filePath, onUploadProgress, method = 'put', headers = {}, fileContent } = params
204
+ if (!isString(cloudPath) || (!filePath && !fileContent)) {
205
+ throw new Error(JSON.stringify({
206
+ code: ERRORS.INVALID_PARAMS,
207
+ msg: `[${COMPONENT_NAME}.uploadFile] invalid params`,
208
+ }),)
209
+ }
210
+ const uploadMethod = { put: EUploadMethod.put, post: EUploadMethod.post }[method.toLocaleLowerCase()] || EUploadMethod.put
211
+
212
+ // 调用 getUploadMetadata 获取上传元数据
213
+ const metadataResult = await this.getUploadMetadata({
214
+ cloudPath,
215
+ method: uploadMethod,
216
+ headers: uploadMethod === EUploadMethod.put ? headers : undefined,
217
+ customReqOpts: params.customReqOpts,
218
+ })
219
+
220
+ const { data: metadata, requestId } = metadataResult
221
+ const { url, authorization, token, fileId, cosFileId, download_url: downloadUrl } = metadata
222
+
223
+ const commonParams = {
224
+ url,
225
+ file: filePath,
226
+ name: cloudPath,
227
+ onUploadProgress,
228
+ fileContent,
229
+ fileId,
230
+ requestId,
231
+ }
232
+
233
+ const putParams = {
234
+ ...commonParams,
235
+ method: EUploadMethod.put,
236
+ headers: {
237
+ ...headers,
238
+ authorization,
239
+ 'x-cos-meta-fileid': cosFileId,
240
+ 'x-cos-security-token': token,
241
+ },
242
+ }
243
+
244
+ const postParams = {
245
+ ...commonParams,
246
+ method: EUploadMethod.post,
247
+ data: {
248
+ key: cloudPath,
249
+ signature: authorization,
250
+ 'x-cos-meta-fileid': cosFileId,
251
+ success_action_status: '201',
252
+ 'x-cos-security-token': token,
253
+ },
254
+ }
255
+
256
+ const uploadConfig = {
257
+ [EUploadMethod.put]: {
258
+ params: putParams,
259
+ isSuccess: (code: number) => code >= 200 && code < 300,
260
+ },
261
+ [EUploadMethod.post]: {
262
+ params: postParams,
263
+ isSuccess: (code: number) => code === 201,
264
+ },
265
+ }
266
+
267
+ // @ts-ignore
268
+ const res = await this.request.upload(uploadConfig[uploadMethod].params)
269
+
270
+ if (uploadConfig[uploadMethod].isSuccess(res.statusCode)) {
271
+ return execCallback(callback, null, {
272
+ fileID: fileId,
273
+ download_url: downloadUrl,
274
+ requestId,
275
+ })
276
+ }
277
+ return execCallback(
278
+ callback,
279
+ new Error(`[${getSdkName()}][${ERRORS.OPERATION_FAIL}][${COMPONENT_NAME}]:${res.data}`),
280
+ )
281
+ }
282
+ @catchErrorsDecorator({
283
+ customInfo: {
284
+ className: 'Cloudbase',
285
+ methodName: 'getUploadMetadata',
286
+ },
287
+ title: '获取上传元信息失败',
288
+ messages: [
289
+ '请确认以下各项:',
290
+ ' 1 - 调用 getUploadMetadata() 的语法或参数是否正确',
291
+ ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',
292
+ ' 3 - 云存储安全规则是否限制了当前登录状态访问',
293
+ `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
294
+ ],
295
+ })
296
+ public async getUploadMetadata(
297
+ params: ICloudbaseGetUploadMetadataParams & {
298
+ method?: EUploadMethod
299
+ headers?: Record<string, string>
300
+ },
301
+ callback?: Function,
302
+ ): Promise<{ data: IUploadMetadata; requestId: string }> {
303
+ const { cloudPath, method, headers } = params
304
+ if (!isString(cloudPath)) {
305
+ throw new Error(JSON.stringify({
306
+ code: ERRORS.INVALID_PARAMS,
307
+ msg: `[${COMPONENT_NAME}.getUploadMetadata] invalid cloudPath`,
308
+ }),)
309
+ }
310
+ // @ts-ignore
311
+ const { request } = this
312
+ const action = 'storage.getUploadMetadata'
313
+
314
+ try {
315
+ let metaData: ICloudbaseFileMetaDataRes
316
+
317
+ const metaDataParam: {
318
+ path: string
319
+ method?: EUploadMethod
320
+ headers?: Record<string, string>
321
+ } = { path: cloudPath }
322
+
323
+ if (method) {
324
+ metaDataParam.method = method
325
+ }
326
+ if (method === EUploadMethod.put && headers) {
327
+ metaDataParam.headers = headers
328
+ }
329
+
330
+ if (this.isGateWay()) {
331
+ metaData = await storageGateWay.getUploadInfo(request, metaDataParam, params.customReqOpts)
332
+ } else {
333
+ metaData = await request.send(action, metaDataParam, params.customReqOpts)
334
+ }
335
+ return execCallback(callback, null, metaData)
336
+ } catch (err) {
337
+ return execCallback(callback, err)
338
+ }
339
+ }
340
+ @catchErrorsDecorator({
341
+ customInfo: {
342
+ className: 'Cloudbase',
343
+ methodName: 'deleteFile',
344
+ },
345
+ title: '删除文件失败',
346
+ messages: [
347
+ '请确认以下各项:',
348
+ ' 1 - 调用 deleteFile() 的语法或参数是否正确',
349
+ ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',
350
+ ' 3 - 云存储安全规则是否限制了当前登录状态访问',
351
+ `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
352
+ ],
353
+ })
354
+ public async deleteFile(
355
+ params: ICloudbaseDeleteFileParams,
356
+ callback?: Function,
357
+ ): Promise<ICloudbaseDeleteFileResult> {
358
+ const { fileList } = params
359
+
360
+ if (!fileList || !isArray(fileList) || fileList.length === 0) {
361
+ throw new Error(JSON.stringify({
362
+ code: ERRORS.INVALID_PARAMS,
363
+ msg: `[${COMPONENT_NAME}.deleteFile] fileList must not be empty`,
364
+ }),)
365
+ }
366
+
367
+ for (const fileId of fileList) {
368
+ if (!fileId || !isString(fileId)) {
369
+ throw new Error(JSON.stringify({
370
+ code: ERRORS.INVALID_PARAMS,
371
+ msg: `[${COMPONENT_NAME}.deleteFile] fileID must be string`,
372
+ }),)
373
+ }
374
+ }
375
+
376
+ const action = 'storage.batchDeleteFile'
377
+ // @ts-ignore
378
+ const { request } = this
379
+ let res: any = {}
380
+
381
+ if (this.isGateWay()) {
382
+ res = await storageGateWay.delete(request, { fileList }, params.customReqOpts)
383
+ } else {
384
+ res = await request.send(
385
+ action,
386
+ {
387
+ fileid_list: fileList,
388
+ },
389
+ params.customReqOpts,
390
+ )
391
+ }
392
+
393
+ if (res.code) {
394
+ return execCallback(callback, null, res)
395
+ }
396
+ const data = {
397
+ fileList: res.data.delete_list,
398
+ requestId: res.requestId,
399
+ }
400
+ return execCallback(callback, null, data)
401
+ }
402
+ @catchErrorsDecorator({
403
+ customInfo: {
404
+ className: 'Cloudbase',
405
+ methodName: 'getTempFileURL',
406
+ },
407
+ title: '获取文件下载链接',
408
+ messages: [
409
+ '请确认以下各项:',
410
+ ' 1 - 调用 getTempFileURL() 的语法或参数是否正确',
411
+ ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',
412
+ ' 3 - 云存储安全规则是否限制了当前登录状态访问',
413
+ `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
414
+ ],
415
+ })
416
+ public async getTempFileURL(
417
+ params: ICloudbaseGetTempFileURLParams,
418
+ callback?: Function,
419
+ ): Promise<ICloudbaseGetTempFileURLResult> {
420
+ const { fileList } = params
421
+
422
+ if (!fileList || !isArray(fileList) || fileList.length === 0) {
423
+ throw new Error(JSON.stringify({
424
+ code: ERRORS.INVALID_PARAMS,
425
+ msg: `[${COMPONENT_NAME}.getTempFileURL] fileList must not be empty`,
426
+ }),)
427
+ }
428
+
429
+ const convertedFileList = []
430
+ for (const file of fileList) {
431
+ if (isPalinObject(file)) {
432
+ if (!Object.prototype.hasOwnProperty.call(file, 'fileID')) {
433
+ throw new Error(JSON.stringify({
434
+ code: ERRORS.INVALID_PARAMS,
435
+ msg: `[${COMPONENT_NAME}.getTempFileURL] file info must include fileID`,
436
+ }),)
437
+ }
438
+
439
+ convertedFileList.push({
440
+ fileid: (file as ICloudbaseFileInfo).fileID,
441
+ max_age: (file as ICloudbaseFileInfo).maxAge || 7200,
442
+ })
443
+ } else if (isString(file)) {
444
+ convertedFileList.push({
445
+ fileid: file,
446
+ })
447
+ } else {
448
+ throw new Error(JSON.stringify({
449
+ code: ERRORS.INVALID_PARAMS,
450
+ msg: `[${COMPONENT_NAME}.getTempFileURL] invalid fileList`,
451
+ }),)
452
+ }
453
+ }
454
+
455
+ const action = 'storage.batchGetDownloadUrl'
456
+ // @ts-ignore
457
+ const { request } = this
458
+ let res: any = {}
459
+
460
+ if (this.isGateWay()) {
461
+ res = await storageGateWay.getDownLoadInfo(request, { convertedFileList }, params.customReqOpts)
462
+ } else {
463
+ res = await request.send(action, { file_list: convertedFileList }, params.customReqOpts)
464
+ }
465
+
466
+ if (res.code) {
467
+ return execCallback(callback, null, res)
468
+ }
469
+
470
+ return execCallback(callback, null, {
471
+ fileList: res.data.download_list,
472
+ requestId: res.requestId,
473
+ })
474
+ }
475
+ @catchErrorsDecorator({
476
+ customInfo: {
477
+ className: 'Cloudbase',
478
+ methodName: 'downloadFile',
479
+ },
480
+ title: '下载文件失败',
481
+ messages: [
482
+ '请确认以下各项:',
483
+ ' 1 - 调用 downloadFile() 的语法或参数是否正确',
484
+ ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',
485
+ ' 3 - 云存储安全规则是否限制了当前登录状态访问',
486
+ `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
487
+ ],
488
+ })
489
+ public async downloadFile(
490
+ params: ICloudbaseDownloadFileParams,
491
+ callback?: Function,
492
+ ): Promise<ICloudbaseDownloadFileResult> {
493
+ const { fileID } = params
494
+ if (!isString(fileID)) {
495
+ throw new Error(JSON.stringify({
496
+ code: ERRORS.INVALID_PARAMS,
497
+ msg: `[${COMPONENT_NAME}.getTempFileURL] fileID must be string`,
498
+ }),)
499
+ }
500
+
501
+ const tmpUrlRes = await this.getTempFileURL.call(this, {
502
+ fileList: [
503
+ {
504
+ fileID,
505
+ maxAge: 600,
506
+ },
507
+ ],
508
+ customReqOpts: params.customReqOpts,
509
+ })
510
+
511
+ const res = tmpUrlRes.fileList[0]
512
+
513
+ if (res.code !== 'SUCCESS') {
514
+ return execCallback(callback, res)
515
+ }
516
+ // @ts-ignore
517
+ const { request } = this
518
+
519
+ const tmpUrl = encodeURI(res.download_url)
520
+
521
+ const result = await request.download({ url: tmpUrl, tempFilePath: params.tempFilePath })
522
+ return execCallback(callback, null, result)
523
+ }
524
+ @catchErrorsDecorator({
525
+ customInfo: {
526
+ className: 'Cloudbase',
527
+ methodName: 'copyFile',
528
+ },
529
+ title: '批量复制文件',
530
+ messages: [
531
+ '请确认以下各项:',
532
+ ' 1 - 调用 copyFile() 的语法或参数是否正确',
533
+ ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',
534
+ ' 3 - 云存储安全规则是否限制了当前登录状态访问',
535
+ `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,
536
+ ],
537
+ })
538
+ public async copyFile(params: ICloudbaseCopyFileParams, callback?: Function): Promise<ICloudbaseCopyFileResult> {
539
+ const { fileList } = params
540
+
541
+ if (!fileList || !isArray(fileList) || fileList.length === 0) {
542
+ throw new Error(JSON.stringify({
543
+ code: ERRORS.INVALID_PARAMS,
544
+ msg: `[${COMPONENT_NAME}.copyFile] fileList must not be empty`,
545
+ }),)
546
+ }
547
+
548
+ const convertedFileList = []
549
+
550
+ for (const file of fileList) {
551
+ const { srcPath, dstPath } = file
552
+ if (!srcPath || !dstPath || typeof srcPath !== 'string' || typeof dstPath !== 'string') {
553
+ throw new Error(JSON.stringify({
554
+ code: ERRORS.INVALID_PARAMS,
555
+ msg: `[${COMPONENT_NAME}.copyFile] srcPath and dstPath may not be empty`,
556
+ }),)
557
+ }
558
+ if (srcPath === dstPath) {
559
+ throw new Error(JSON.stringify({
560
+ code: ERRORS.INVALID_PARAMS,
561
+ msg: `[${COMPONENT_NAME}.copyFile] srcPath and dstPath can not be the same`,
562
+ }),)
563
+ }
564
+ // if (basename(srcPath) !== basename(dstPath)) {
565
+ // throw new Error(JSON.stringify({
566
+ // code: ERRORS.INVALID_PARAMS,
567
+ // msg: `[${COMPONENT_NAME}.copyFile] srcPath and dstPath file name must be the same`,
568
+ // }),)
569
+ // }
570
+ convertedFileList.push({
571
+ src_path: srcPath,
572
+ dst_path: dstPath,
573
+ overwrite: file.overwrite,
574
+ remove_original: file.removeOriginal,
575
+ })
576
+ }
577
+
578
+ // @ts-ignore
579
+ const { request } = this
580
+ let res: any = {}
581
+
582
+ if (this.isGateWay()) {
583
+ res = await storageGateWay.copyFile(request, { convertedFileList }, params.customReqOpts)
584
+ } else {
585
+ const action = 'storage.batchCopyFile'
586
+ res = await request.send(action, { file_list: convertedFileList }, params.customReqOpts)
587
+ }
588
+
589
+ if (res.code) {
590
+ return execCallback(callback, null, res)
591
+ }
592
+
593
+ return execCallback(callback, null, {
594
+ fileList: res.data.copy_list,
595
+ requestId: res.requestId,
596
+ })
597
+ }
598
+
599
+ public async getFileInfo(params: ICloudbaseGetTempFileURLParams): Promise<{
600
+ fileList: (Pick<ICloudbaseGetTempFileURLResult['fileList'][0], 'code' | 'fileID' | 'tempFileURL' | 'message'> & {
601
+ fileName?: string
602
+ cloudId?: ICloudbaseGetTempFileURLResult['fileList'][0]['fileID']
603
+ contentType?: string
604
+ mime?: string
605
+ size?: number
606
+ cacheControl?: string
607
+ lastModified?: string
608
+ etag?: string
609
+ })[]
610
+ requestId: string
611
+ }> {
612
+ const fileInfo = await this.getTempFileURL(params)
613
+
614
+ if (fileInfo?.fileList && fileInfo?.fileList?.length > 0) {
615
+ const fileList = await Promise.all(fileInfo.fileList.map(async (item: ICloudbaseGetTempFileURLResult['fileList'][0]) => {
616
+ if (item.code !== 'SUCCESS') {
617
+ return {
618
+ code: item.code,
619
+ fileID: item.fileID,
620
+ tempFileURL: item.tempFileURL,
621
+ message: item.message,
622
+ }
623
+ }
624
+
625
+ try {
626
+ // @ts-ignore
627
+ const { request } = this
628
+ const res = await request.fetch({ url: item.tempFileURL, method: 'HEAD' })
629
+ let { header } = res
630
+
631
+ if (Headers && header instanceof Headers) {
632
+ header = Object.fromEntries(res.header.entries())
633
+ }
634
+ // eslint-disable-next-line radix
635
+ const fileSize = parseInt(header['content-length']) || 0
636
+ const contentType = header['content-type'] || ''
637
+
638
+ if ([400, 404].includes(Number(res.statusCode))) {
639
+ return {
640
+ code: 'FILE_NOT_FOUND',
641
+ fileID: item.fileID,
642
+ tempFileURL: item.tempFileURL,
643
+ message: 'file not found',
644
+ }
645
+ }
646
+
647
+ const fileInfo = {
648
+ code: item.code,
649
+ fileID: item.fileID,
650
+ tempFileURL: item.tempFileURL,
651
+ cloudId: item.fileID,
652
+ fileName: item.fileID.split('/').pop(),
653
+ contentType,
654
+ mime: contentType.split(';')[0].trim(),
655
+ size: fileSize,
656
+ etag: header.etag || '',
657
+ lastModified: header['last-modified'] || '',
658
+ cacheControl: header['cache-control'] || '',
659
+ }
660
+
661
+ return fileInfo
662
+ } catch (e) {
663
+ return {
664
+ code: 'FETCH_FILE_INFO_ERROR',
665
+ fileID: item.fileID,
666
+ tempFileURL: item.tempFileURL,
667
+ message: e.message,
668
+ }
669
+ }
670
+ }),)
671
+
672
+ return {
673
+ fileList,
674
+ requestId: fileInfo.requestId,
675
+ }
676
+ }
677
+
678
+ return {
679
+ fileList: [],
680
+ requestId: fileInfo.requestId,
681
+ }
682
+ }
683
+ }