@be-link/cos 1.11.5-beta.0 → 1.12.0-beta.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/README.md CHANGED
@@ -25,6 +25,8 @@ npm install @be-link/cos cos-js-sdk-v5 crypto-js
25
25
 
26
26
  ### Vue 项目
27
27
 
28
+ **方式一:立即初始化**
29
+
28
30
  ```vue
29
31
  <template>
30
32
  <div>
@@ -70,6 +72,28 @@ const handleUpload = async () => {
70
72
  </script>
71
73
  ```
72
74
 
75
+ **方式二:延迟初始化(支持异步配置)**
76
+
77
+ ```vue
78
+ <script setup>
79
+ import { ref, onMounted } from 'vue';
80
+ import { BeLinkCOS } from '@be-link/cos';
81
+
82
+ const uploader = new BeLinkCOS(); // 先创建实例
83
+
84
+ onMounted(async () => {
85
+ // 从服务器获取配置
86
+ const config = await fetchConfigFromServer();
87
+ uploader.init({ mode: config.mode }); // 稍后初始化
88
+ });
89
+
90
+ const handleUpload = async () => {
91
+ const result = await uploader.uploadFile(file.value);
92
+ console.log('上传成功:', result.url);
93
+ };
94
+ </script>
95
+ ```
96
+
73
97
  ### React 项目
74
98
 
75
99
  ```jsx
@@ -165,31 +189,59 @@ await Promise.all([devUploader.uploadFile(file), prodUploader.uploadFile(file)])
165
189
 
166
190
  ## API 文档
167
191
 
168
- ### `new BeLinkCOS(config)`
192
+ ### `new BeLinkCOS(config?)`
169
193
 
170
194
  创建 COS 上传器实例
171
195
 
196
+ **支持两种使用方式:**
197
+
198
+ 1. **立即初始化**:传入配置对象,构造函数中自动调用 `init()`
199
+ 2. **延迟初始化**:不传配置,稍后调用 `init()` 方法(支持异步配置)
200
+
172
201
  **参数:**
173
202
 
174
- - `config.mode` - **必填,无默认值**
175
- - 环境模式:`'development'` | `'testing'` | `'production'`
176
- - 设计上强制必填,避免误传到错误环境
203
+ - `config.mode` - **必填** 环境模式:`'development'` | `'test'` | `'production'`
177
204
  - `config.headers` - 可选,自定义请求头
178
205
  - `config.ScopeLimit` - 可选,是否限制临时密钥范围(默认 `false`)
206
+ - `config.debug` - 可选,是否开启调试模式(默认 `false`)
179
207
 
180
208
  **示例:**
181
209
 
182
210
  ```typescript
183
- // 基础使用
211
+ // 方式一:立即初始化
184
212
  const uploader = new BeLinkCOS({ mode: 'production' });
185
213
 
214
+ // 方式二:延迟初始化(支持异步配置)
215
+ const uploader = new BeLinkCOS();
216
+ const config = await fetchConfig(); // 从服务器获取配置
217
+ uploader.init({ mode: config.mode });
218
+
186
219
  // 带自定义请求头
187
220
  const uploader = new BeLinkCOS({
188
221
  mode: 'production',
189
222
  headers: { 'x-custom': 'value' },
223
+ debug: true, // 开启调试日志
190
224
  });
191
225
  ```
192
226
 
227
+ ### `uploader.init(config)`
228
+
229
+ 初始化 COS 实例(用于延迟初始化场景)
230
+
231
+ **参数:**
232
+
233
+ - `config.mode` - **必填** 环境模式
234
+ - `config.headers` - 可选,自定义请求头
235
+ - `config.ScopeLimit` - 可选,是否限制临时密钥范围
236
+ - `config.debug` - 可选,是否开启调试模式
237
+
238
+ **示例:**
239
+
240
+ ```typescript
241
+ const uploader = new BeLinkCOS();
242
+ uploader.init({ mode: 'production' });
243
+ ```
244
+
193
245
  ### `uploader.uploadFile(file, config)`
194
246
 
195
247
  上传文件到 COS
@@ -239,6 +291,23 @@ const url = await uploader.getSourceUrl(file);
239
291
  const md5 = await uploader.createFileMd5(file, 2 * 1024 * 1024); // 默认 2MB 分片
240
292
  ```
241
293
 
294
+ ### `uploader.getConfig()`
295
+
296
+ 获取当前实例的配置信息
297
+
298
+ ```typescript
299
+ const config = uploader.getConfig();
300
+ console.log(config); // { mode: 'production', headers: {}, scopeLimit: false }
301
+ ```
302
+
303
+ ### `uploader.destroy()`
304
+
305
+ 销毁实例,清理资源
306
+
307
+ ```typescript
308
+ uploader.destroy();
309
+ ```
310
+
242
311
  ---
243
312
 
244
313
  ## 环境配置
@@ -246,7 +315,7 @@ const md5 = await uploader.createFileMd5(file, 2 * 1024 * 1024); // 默认 2MB
246
315
  | 环境 | Bucket | 区域 |
247
316
  | ----------- | ------------------ | ---------- |
248
317
  | development | dev-1304510571 | ap-nanjing |
249
- | testing | dev-1304510571 | ap-nanjing |
318
+ | test | dev-1304510571 | ap-nanjing |
250
319
  | production | release-1304510571 | ap-nanjing |
251
320
 
252
321
  ---
@@ -256,7 +325,7 @@ const md5 = await uploader.createFileMd5(file, 2 * 1024 * 1024); // 默认 2MB
256
325
  ```typescript
257
326
  import { BeLinkCOS } from '@be-link/cos';
258
327
  import type {
259
- EnvMode, // 'development' | 'testing' | 'production'
328
+ EnvMode, // 'development' | 'test' | 'production'
260
329
  BucketConfig, // Bucket 配置
261
330
  InitConfig, // 初始化配置
262
331
  UploadConfig, // 上传配置
@@ -268,7 +337,27 @@ import type {
268
337
 
269
338
  ## 常见问题
270
339
 
271
- ### 1. 为什么 mode 必须传?没有默认值?
340
+ ### 1. 两种初始化方式有什么区别?
341
+
342
+ **立即初始化**:配置在编译时已知,直接传入构造函数
343
+
344
+ ```typescript
345
+ const uploader = new BeLinkCOS({ mode: 'production' });
346
+ ```
347
+
348
+ **延迟初始化**:配置需要异步获取(如从服务器获取),先创建实例再初始化
349
+
350
+ ```typescript
351
+ const uploader = new BeLinkCOS();
352
+
353
+ // 稍后(可以是异步)
354
+ const config = await fetchConfigFromServer();
355
+ uploader.init({ mode: config.mode });
356
+ ```
357
+
358
+ **设计理念:** 参考了 `BeLinkLogDot` 的设计模式,支持更灵活的配置方式。
359
+
360
+ ### 2. 为什么 mode 必须传?
272
361
 
273
362
  **设计理念:强制显式配置,避免默认值陷阱**
274
363
 
@@ -283,31 +372,33 @@ import type {
283
372
  // ✅ 正确:明确指定环境,不会搞错
284
373
  const uploader = new BeLinkCOS({ mode: 'production' });
285
374
 
286
- // 错误:TypeScript 编译错误,强制必须传 mode
375
+ // 也可以延迟初始化
287
376
  const uploader = new BeLinkCOS();
377
+ uploader.init({ mode: 'production' });
288
378
  ```
289
379
 
290
380
  这样设计更安全,用户必须思考"我要上传到哪个环境"。
291
381
 
292
- ### 2. 上传失败怎么办?
382
+ ### 3. 上传失败怎么办?
293
383
 
294
384
  检查:
295
385
 
296
386
  - `mode` 参数是否正确
387
+ - 实例是否已初始化(调用了 `init()` 或构造函数传入了配置)
297
388
  - 网络是否正常
298
- - 浏览器控制台是否有错误信息
389
+ - 浏览器控制台是否有错误信息(可以开启 `debug: true` 查看详细日志)
299
390
 
300
- ### 3. 文件存储路径是什么?
391
+ ### 4. 文件存储路径是什么?
301
392
 
302
393
  文件会自动存储到:`/beLinkAllSource/static/{文件类型}/{文件名}_{时间戳}.{扩展名}`
303
394
 
304
395
  例如:`/beLinkAllSource/static/image/avatar_1699999999999.png`
305
396
 
306
- ### 4. 支持哪些文件类型?
397
+ ### 5. 支持哪些文件类型?
307
398
 
308
399
  支持所有文件类型,会根据文件的 MIME 类型自动分类存储(image、video、audio、application、text、other)。
309
400
 
310
- ### 5. 如何切换环境?
401
+ ### 6. 如何切换环境?
311
402
 
312
403
  创建不同环境的实例:
313
404
 
@@ -8,8 +8,15 @@ import type { InitConfig, UploadConfig, UploadResult } from './types';
8
8
  * @example
9
9
  * import { BeLinkCOS } from '@be-link/cos';
10
10
  *
11
+ * // 方式一:构造函数传入配置,立即初始化
11
12
  * const uploader = new BeLinkCOS({ mode: 'production' });
12
13
  * await uploader.uploadFile(file);
14
+ *
15
+ * // 方式二:先创建实例,稍后初始化(支持异步配置)
16
+ * const uploader = new BeLinkCOS();
17
+ * const config = await fetchConfig(); // 从服务器获取配置
18
+ * uploader.init({ mode: 'production' });
19
+ * await uploader.uploadFile(file);
13
20
  */
14
21
  export declare class BeLinkCOS {
15
22
  /** COS SDK 实例 */
@@ -19,40 +26,73 @@ export declare class BeLinkCOS {
19
26
  /** 自定义请求头 */
20
27
  headers: Record<string, any>;
21
28
  /** 当前环境模式 */
22
- mode: EnvMode;
29
+ mode: EnvMode | null;
23
30
  /** 是否限制临时密钥的使用范围 */
24
31
  private scopeLimit;
32
+ /** 生命周期状态 */
33
+ protected isInitialized: boolean;
34
+ protected isDestroyed: boolean;
35
+ /** 调试模式 */
36
+ private debug;
25
37
  /**
26
38
  * 构造函数
27
39
  *
28
- * 注意:mode 参数必填,没有默认值
29
- * 设计理念:强制显式配置环境,避免误传到错误的环境
40
+ * 支持两种使用方式:
41
+ * 1. 立即初始化:传入配置对象,构造函数中自动调用 init()
42
+ * 2. 延迟初始化:不传配置,稍后调用 init() 方法(支持异步配置)
30
43
  *
31
- * @param config - 初始化配置
32
- * @param config.mode - **必填** 环境模式:'development' | 'testing' | 'production'
44
+ * @param config - 可选的初始化配置
45
+ * @param config.mode - **必填** 环境模式:'development' | 'test' | 'production'
33
46
  * @param config.headers - 可选,自定义请求头
34
47
  * @param config.ScopeLimit - 可选,是否限制临时密钥的使用范围(默认 false)
48
+ * @param config.debug - 可选,是否开启调试模式(默认 false)
35
49
  *
36
50
  * @example
37
- * // 基础使用
51
+ * // 立即初始化
38
52
  * const uploader = new BeLinkCOS({ mode: 'production' });
39
53
  *
40
- * // 带自定义请求头
41
- * const uploader = new BeLinkCOS({
42
- * mode: 'production',
43
- * headers: { 'x-custom': 'value' }
44
- * });
54
+ * // 延迟初始化
55
+ * const uploader = new BeLinkCOS();
56
+ * // ... 稍后调用 uploader.init(config);
57
+ */
58
+ constructor(config?: InitConfig);
59
+ /**
60
+ * 初始化 COS 实例
61
+ * @param config 配置对象
62
+ * @description 可以在创建实例时通过构造函数传入配置,也可以稍后调用此方法初始化
45
63
  */
46
- constructor(config: InitConfig);
64
+ init(config: InitConfig): void;
47
65
  /**
48
66
  * 初始化 COS SDK 实例
49
67
  *
50
68
  * 内部方法,通过云函数获取临时密钥
51
- * 首次上传时会自动调用,也可以手动调用以重新初始化
69
+ * 首次上传时会自动调用
52
70
  *
53
71
  * @returns Promise<void>
54
72
  */
55
73
  private initCOS;
74
+ /**
75
+ * 检查实例状态
76
+ */
77
+ protected checkState(methodName: string): boolean;
78
+ /**
79
+ * 内部日志方法
80
+ */
81
+ protected log(...args: unknown[]): void;
82
+ protected warn(...args: unknown[]): void;
83
+ protected error(...args: unknown[]): void;
84
+ /**
85
+ * 验证配置
86
+ */
87
+ protected validateConfig(config: InitConfig): boolean;
88
+ /**
89
+ * 获取配置
90
+ */
91
+ getConfig(): {
92
+ mode: EnvMode | null;
93
+ headers: Record<string, any>;
94
+ scopeLimit: boolean;
95
+ } | null;
56
96
  /**
57
97
  * 计算文件的 MD5 哈希值
58
98
  *
@@ -76,7 +116,7 @@ export declare class BeLinkCOS {
76
116
  * 例如:/beLinkAllSource/static/image/avatar_1699999999999.png
77
117
  *
78
118
  * @param file - 文件对象
79
- * @returns Promise<string> COS 存储路径
119
+ * @returns string COS 存储路径
80
120
  */
81
121
  private getFilePath;
82
122
  /**
@@ -85,13 +125,13 @@ export declare class BeLinkCOS {
85
125
  * 用于在上传前预览文件的最终 URL
86
126
  *
87
127
  * @param file - 文件对象
88
- * @returns Promise<string> 文件的完整访问 URL
128
+ * @returns Promise<string | null> 文件的完整访问 URL,如果实例未初始化则返回 null
89
129
  *
90
130
  * @example
91
131
  * const url = await beLinkCOS.getSourceUrl(file);
92
132
  * console.log('文件将上传到:', url);
93
133
  */
94
- getSourceUrl(file: File): Promise<string>;
134
+ getSourceUrl(file: File): Promise<string | null>;
95
135
  /**
96
136
  * 上传文件到腾讯云 COS
97
137
  *
@@ -114,5 +154,9 @@ export declare class BeLinkCOS {
114
154
  * console.log('文件 URL:', result.url);
115
155
  */
116
156
  uploadFile(file: File, config?: UploadConfig): Promise<UploadResult>;
157
+ /**
158
+ * 销毁实例
159
+ */
160
+ destroy(): void;
117
161
  }
118
162
  //# sourceMappingURL=beLinkCos.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"beLinkCos.d.ts","sourceRoot":"","sources":["../src/beLinkCos.ts"],"names":[],"mappings":"AAGA,OAAO,EAA0B,KAAK,OAAO,EAAE,MAAM,UAAU,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEtE;;;;;;;;;;GAUG;AACH,qBAAa,SAAS;IACpB,iBAAiB;IACjB,OAAO,CAAC,GAAG,CAAa;IACxB,kBAAkB;IAClB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsC;IAC/D,aAAa;IACN,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACpC,aAAa;IACN,IAAI,EAAE,OAAO,CAAC;IACrB,oBAAoB;IACpB,OAAO,CAAC,UAAU,CAAU;IAE5B;;;;;;;;;;;;;;;;;;;;OAoBG;gBACS,MAAM,EAAE,UAAU;IAM9B;;;;;;;OAOG;YACW,OAAO;IAoCrB;;;;;;;;;;;;;;OAcG;IACI,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,GAAE,MAAwB,GAAG,OAAO,CAAC,MAAM,CAAC;IA+DtF;;;;;;;;OAQG;YACW,WAAW;IASzB;;;;;;;;;;;OAWG;IACU,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IAKtD;;;;;;;;;;;;;;;;;;;;OAoBG;IACU,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;CA6BlF"}
1
+ {"version":3,"file":"beLinkCos.d.ts","sourceRoot":"","sources":["../src/beLinkCos.ts"],"names":[],"mappings":"AAIA,OAAO,EAA0B,KAAK,OAAO,EAAE,MAAM,UAAU,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEtE;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,SAAS;IACpB,iBAAiB;IACjB,OAAO,CAAC,GAAG,CAAa;IACxB,kBAAkB;IAClB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsC;IAC/D,aAAa;IACN,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAM;IACzC,aAAa;IACN,IAAI,EAAE,OAAO,GAAG,IAAI,CAAQ;IACnC,oBAAoB;IACpB,OAAO,CAAC,UAAU,CAAkB;IACpC,aAAa;IACb,SAAS,CAAC,aAAa,EAAE,OAAO,CAAS;IACzC,SAAS,CAAC,WAAW,EAAE,OAAO,CAAS;IACvC,WAAW;IACX,OAAO,CAAC,KAAK,CAAkB;IAE/B;;;;;;;;;;;;;;;;;;;;OAoBG;gBACS,MAAM,CAAC,EAAE,UAAU;IAO/B;;;;OAIG;IACH,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAyB9B;;;;;;;OAOG;YACW,OAAO;IAqCrB;;OAEG;IACH,SAAS,CAAC,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAYjD;;OAEG;IACH,SAAS,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAMvC,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAMxC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAMzC;;OAEG;IACH,SAAS,CAAC,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO;IAmBrD;;OAEG;IACH,SAAS,IAAI;QAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI;IAY/F;;;;;;;;;;;;;;OAcG;IACI,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,GAAE,MAAwB,GAAG,OAAO,CAAC,MAAM,CAAC;IA+DtF;;;;;;;;OAQG;IACH,OAAO,CAAC,WAAW;IASnB;;;;;;;;;;;OAWG;IACU,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAS7D;;;;;;;;;;;;;;;;;;;;OAoBG;IACU,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAsCjF;;OAEG;IACH,OAAO,IAAI,IAAI;CAsBhB"}
package/dist/config.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * 环境模式类型
3
3
  * - development: 开发环境
4
- * - testing: 测试环境
4
+ * - test: 测试环境
5
5
  * - production: 生产环境
6
6
  */
7
- export type EnvMode = 'development' | 'testing' | 'production';
7
+ export type EnvMode = 'development' | 'test' | 'production';
8
8
  /**
9
9
  * COS 存储桶配置接口
10
10
  */
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,OAAO,GAAG,aAAa,GAAG,SAAS,GAAG,YAAY,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,YAAY;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,cAAc;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW;IACX,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,OAAO,EAAE,YAAY,CAgBxD,CAAC;AAEF,sBAAsB;AACtB,eAAO,MAAM,MAAM,EAAG,YAAqB,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,OAAO,GAAG,aAAa,GAAG,MAAM,GAAG,YAAY,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,YAAY;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,cAAc;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW;IACX,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,OAAO,EAAE,YAAY,CAgBxD,CAAC;AAEF,sBAAsB;AACtB,eAAO,MAAM,MAAM,EAAG,YAAqB,CAAC"}
@@ -0,0 +1,407 @@
1
+ 'use strict';
2
+
3
+ var CryptoJS = require('crypto-js');
4
+ var COS = require('cos-js-sdk-v5');
5
+
6
+ /**
7
+ * 各环境的 COS 存储桶配置
8
+ * 根据环境自动切换到对应的存储桶
9
+ */
10
+ const BUCKETS_CONFIG = {
11
+ development: {
12
+ name: 'dev-1304510571',
13
+ host: 'dev-1304510571.cos.ap-nanjing.myqcloud.com',
14
+ protocol: 'https',
15
+ },
16
+ test: {
17
+ name: 'dev-1304510571',
18
+ host: 'dev-1304510571.cos.ap-nanjing.myqcloud.com',
19
+ protocol: 'https',
20
+ },
21
+ production: {
22
+ name: 'release-1304510571',
23
+ host: 'release-1304510571.file.myqcloud.com',
24
+ protocol: 'https',
25
+ },
26
+ };
27
+ /** COS 存储桶所在地域(南京) */
28
+ const REGION = 'ap-nanjing';
29
+
30
+ /**
31
+ * BeLinkCOS 类 - 腾讯云 COS 文件上传工具
32
+ *
33
+ * 功能:文件上传、MD5 计算、临时密钥授权
34
+ *
35
+ * @example
36
+ * import { BeLinkCOS } from '@be-link/cos';
37
+ *
38
+ * // 方式一:构造函数传入配置,立即初始化
39
+ * const uploader = new BeLinkCOS({ mode: 'production' });
40
+ * await uploader.uploadFile(file);
41
+ *
42
+ * // 方式二:先创建实例,稍后初始化(支持异步配置)
43
+ * const uploader = new BeLinkCOS();
44
+ * const config = await fetchConfig(); // 从服务器获取配置
45
+ * uploader.init({ mode: 'production' });
46
+ * await uploader.uploadFile(file);
47
+ */
48
+ class BeLinkCOS {
49
+ /**
50
+ * 构造函数
51
+ *
52
+ * 支持两种使用方式:
53
+ * 1. 立即初始化:传入配置对象,构造函数中自动调用 init()
54
+ * 2. 延迟初始化:不传配置,稍后调用 init() 方法(支持异步配置)
55
+ *
56
+ * @param config - 可选的初始化配置
57
+ * @param config.mode - **必填** 环境模式:'development' | 'test' | 'production'
58
+ * @param config.headers - 可选,自定义请求头
59
+ * @param config.ScopeLimit - 可选,是否限制临时密钥的使用范围(默认 false)
60
+ * @param config.debug - 可选,是否开启调试模式(默认 false)
61
+ *
62
+ * @example
63
+ * // 立即初始化
64
+ * const uploader = new BeLinkCOS({ mode: 'production' });
65
+ *
66
+ * // 延迟初始化
67
+ * const uploader = new BeLinkCOS();
68
+ * // ... 稍后调用 uploader.init(config);
69
+ */
70
+ constructor(config) {
71
+ /** COS SDK 实例 */
72
+ this.cos = null;
73
+ /** COS 存储的基础路径 */
74
+ this.basePath = '/beLinkAllSource/static/';
75
+ /** 自定义请求头 */
76
+ this.headers = {};
77
+ /** 当前环境模式 */
78
+ this.mode = null;
79
+ /** 是否限制临时密钥的使用范围 */
80
+ this.scopeLimit = false;
81
+ /** 生命周期状态 */
82
+ this.isInitialized = false;
83
+ this.isDestroyed = false;
84
+ /** 调试模式 */
85
+ this.debug = false;
86
+ // 如果传入配置,立即初始化
87
+ if (config) {
88
+ this.init(config);
89
+ }
90
+ }
91
+ /**
92
+ * 初始化 COS 实例
93
+ * @param config 配置对象
94
+ * @description 可以在创建实例时通过构造函数传入配置,也可以稍后调用此方法初始化
95
+ */
96
+ init(config) {
97
+ if (this.isDestroyed) {
98
+ this.warn('实例已销毁,无法初始化');
99
+ return;
100
+ }
101
+ if (this.isInitialized) {
102
+ this.warn('实例已初始化,请勿重复调用');
103
+ return;
104
+ }
105
+ if (!this.validateConfig(config)) {
106
+ return;
107
+ }
108
+ // 保存配置
109
+ this.mode = config.mode;
110
+ this.headers = config.headers || {};
111
+ this.scopeLimit = config.ScopeLimit || false;
112
+ this.debug = config.debug || false;
113
+ this.isInitialized = true;
114
+ this.log('COS 实例初始化成功', { mode: this.mode });
115
+ }
116
+ /**
117
+ * 初始化 COS SDK 实例
118
+ *
119
+ * 内部方法,通过云函数获取临时密钥
120
+ * 首次上传时会自动调用
121
+ *
122
+ * @returns Promise<void>
123
+ */
124
+ async initCOS() {
125
+ if (this.cos) {
126
+ return; // 已初始化,直接返回
127
+ }
128
+ const cos = new COS({
129
+ getAuthorization: (_options, callback) => {
130
+ const url = this.mode === 'production'
131
+ ? 'https://shield-60660-10-1304510571.sh.run.tcloudbase.com/config/get-cos-temp-secret'
132
+ : 'https://shield-74680-5-1304510571.sh.run.tcloudbase.com/config/get-cos-temp-secret';
133
+ fetch(url, { method: 'POST' })
134
+ .then((response) => response.json())
135
+ .then((result) => {
136
+ const data = result?.data || {};
137
+ const credentials = data?.credentials;
138
+ callback({
139
+ TmpSecretId: credentials.tmpSecretId, // 临时密钥的 tmpSecretId
140
+ TmpSecretKey: credentials.tmpSecretKey, // 临时密钥的 tmpSecretKey
141
+ SecurityToken: credentials.sessionToken, // 临时密钥的 sessionToken
142
+ // 建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
143
+ StartTime: data.startTime, // 时间戳,单位秒,如:1580000000
144
+ ExpiredTime: data.expiredTime, // 临时密钥失效时间戳,是申请临时密钥时,时间戳加 durationSeconds
145
+ ScopeLimit: this.scopeLimit, // 细粒度控制权限需要设为 true,会限制密钥只在相同请求时重复使用
146
+ });
147
+ })
148
+ .catch((error) => {
149
+ this.error('获取临时密钥失败:', error);
150
+ callback(null);
151
+ });
152
+ },
153
+ });
154
+ this.cos = cos;
155
+ this.log('COS SDK 初始化成功');
156
+ }
157
+ /**
158
+ * 检查实例状态
159
+ */
160
+ checkState(methodName) {
161
+ if (this.isDestroyed) {
162
+ this.warn(`实例已销毁,无法调用 ${methodName}`);
163
+ return false;
164
+ }
165
+ if (!this.isInitialized) {
166
+ this.warn(`实例未初始化,请先调用 init 方法`);
167
+ return false;
168
+ }
169
+ return true;
170
+ }
171
+ /**
172
+ * 内部日志方法
173
+ */
174
+ log(...args) {
175
+ if (this.debug) {
176
+ console.log(`[${this.constructor.name}]`, ...args);
177
+ }
178
+ }
179
+ warn(...args) {
180
+ if (this.debug) {
181
+ console.warn(`[${this.constructor.name}]`, ...args);
182
+ }
183
+ }
184
+ error(...args) {
185
+ if (this.debug) {
186
+ console.error(`[${this.constructor.name}]`, ...args);
187
+ }
188
+ }
189
+ /**
190
+ * 验证配置
191
+ */
192
+ validateConfig(config) {
193
+ if (!config) {
194
+ this.error('配置对象不能为空');
195
+ return false;
196
+ }
197
+ if (!config.mode) {
198
+ this.error('mode 是必需的');
199
+ return false;
200
+ }
201
+ if (!['development', 'test', 'production'].includes(config.mode)) {
202
+ this.error('mode 必须是 development、test 或 production');
203
+ return false;
204
+ }
205
+ return true;
206
+ }
207
+ /**
208
+ * 获取配置
209
+ */
210
+ getConfig() {
211
+ if (!this.isInitialized) {
212
+ this.warn('实例未初始化');
213
+ return null;
214
+ }
215
+ return {
216
+ mode: this.mode,
217
+ headers: this.headers,
218
+ scopeLimit: this.scopeLimit,
219
+ };
220
+ }
221
+ /**
222
+ * 计算文件的 MD5 哈希值
223
+ *
224
+ * 性能优化:
225
+ * - 小文件(< 10MB):一次性读取,速度更快
226
+ * - 大文件:分片读取,避免内存溢出
227
+ *
228
+ * @param file - 要计算 MD5 的文件对象
229
+ * @param chunkSize - 分片大小(字节),默认 2MB
230
+ * @returns Promise<string> 文件的 MD5 哈希值
231
+ *
232
+ * @example
233
+ * const md5 = await beLinkCOS.createFileMd5(file);
234
+ * console.log('文件 MD5:', md5);
235
+ */
236
+ createFileMd5(file, chunkSize = 2 * 1024 * 1024) {
237
+ return new Promise((resolve, reject) => {
238
+ // 对于小文件(< 10MB),使用简单方法
239
+ if (file.size < 10 * 1024 * 1024) {
240
+ const reader = new FileReader();
241
+ reader.onload = (e) => {
242
+ const arrayBuffer = e.target?.result;
243
+ if (arrayBuffer) {
244
+ const wordArray = CryptoJS.lib.WordArray.create(arrayBuffer);
245
+ const hash = CryptoJS.MD5(wordArray).toString();
246
+ resolve(hash);
247
+ }
248
+ else {
249
+ reject(new Error('Failed to read file'));
250
+ }
251
+ };
252
+ reader.onerror = (error) => {
253
+ reject(error);
254
+ };
255
+ reader.readAsArrayBuffer(file);
256
+ return;
257
+ }
258
+ // 对于大文件,使用分片读取
259
+ let currentChunk = 0;
260
+ const chunks = Math.ceil(file.size / chunkSize);
261
+ const spark = CryptoJS.algo.MD5.create();
262
+ const reader = new FileReader();
263
+ reader.onload = (e) => {
264
+ const arrayBuffer = e.target?.result;
265
+ if (arrayBuffer) {
266
+ const wordArray = CryptoJS.lib.WordArray.create(arrayBuffer);
267
+ spark.update(wordArray);
268
+ currentChunk++;
269
+ if (currentChunk < chunks) {
270
+ loadNext();
271
+ }
272
+ else {
273
+ const hash = spark.finalize().toString();
274
+ resolve(hash);
275
+ }
276
+ }
277
+ };
278
+ reader.onerror = (error) => {
279
+ reject(error);
280
+ };
281
+ const loadNext = () => {
282
+ const start = currentChunk * chunkSize;
283
+ const end = Math.min(start + chunkSize, file.size);
284
+ const blob = file.slice(start, end);
285
+ reader.readAsArrayBuffer(blob);
286
+ };
287
+ loadNext();
288
+ });
289
+ }
290
+ /**
291
+ * 生成文件在 COS 中的存储路径
292
+ *
293
+ * 路径规则:/beLinkAllSource/static/{文件类型}/{文件名}_{时间戳}.{扩展名}
294
+ * 例如:/beLinkAllSource/static/image/avatar_1699999999999.png
295
+ *
296
+ * @param file - 文件对象
297
+ * @returns string COS 存储路径
298
+ */
299
+ getFilePath(file) {
300
+ const filename = file.name;
301
+ const fileType = file?.type ? file.type.split('/')[0] : 'other';
302
+ const fileExtension = filename.split('.').pop() || '';
303
+ const filenameDateNow = `${filename.split('.')[0]}_${Date.now()}`;
304
+ const newFileName = `${filenameDateNow}.${fileExtension}`;
305
+ return `${this.basePath}${fileType}/${newFileName}`;
306
+ }
307
+ /**
308
+ * 获取文件上传后的访问 URL(不执行实际上传)
309
+ *
310
+ * 用于在上传前预览文件的最终 URL
311
+ *
312
+ * @param file - 文件对象
313
+ * @returns Promise<string | null> 文件的完整访问 URL,如果实例未初始化则返回 null
314
+ *
315
+ * @example
316
+ * const url = await beLinkCOS.getSourceUrl(file);
317
+ * console.log('文件将上传到:', url);
318
+ */
319
+ async getSourceUrl(file) {
320
+ if (!this.checkState('getSourceUrl')) {
321
+ return null;
322
+ }
323
+ const path = this.getFilePath(file);
324
+ return `https://${BUCKETS_CONFIG[this.mode].host}${path}`;
325
+ }
326
+ /**
327
+ * 上传文件到腾讯云 COS
328
+ *
329
+ * 核心功能:将文件上传到对应环境的 COS 存储桶
330
+ * 支持上传进度回调、自定义请求头等配置
331
+ *
332
+ * @param file - 要上传的文件对象
333
+ * @param config - 上传配置(可选)
334
+ * @param config.Headers - 自定义请求头
335
+ * @param config.onProgressCallback - 上传进度回调函数
336
+ * @returns Promise<UploadResult> 上传结果,包含文件 URL、ETag 等信息
337
+ *
338
+ * @example
339
+ * const uploader = new BeLinkCOS({ mode: 'production' });
340
+ * const result = await uploader.uploadFile(file, {
341
+ * onProgressCallback: (progressData) => {
342
+ * console.log('进度:', progressData.percent * 100 + '%');
343
+ * }
344
+ * });
345
+ * console.log('文件 URL:', result.url);
346
+ */
347
+ async uploadFile(file, config) {
348
+ if (!this.checkState('uploadFile')) {
349
+ throw new Error('实例未初始化或已销毁');
350
+ }
351
+ // 首次上传时自动初始化 COS SDK
352
+ if (!this.cos) {
353
+ await this.initCOS();
354
+ }
355
+ const key = this.getFilePath(file);
356
+ this.log('开始上传文件:', { filename: file.name, key });
357
+ return new Promise((resolve, reject) => {
358
+ this.cos?.putObject({
359
+ Bucket: BUCKETS_CONFIG[this.mode].name,
360
+ Region: REGION,
361
+ Key: key,
362
+ Body: file,
363
+ onProgress: config?.onProgressCallback,
364
+ ...config,
365
+ Headers: { ...this.headers, ...(config?.Headers || {}) },
366
+ }, (err, data) => {
367
+ if (err) {
368
+ this.error('上传失败:', err);
369
+ reject(err);
370
+ }
371
+ else {
372
+ const url = `https://${data.Location}`;
373
+ this.log('上传成功:', url);
374
+ resolve({ ...data, url });
375
+ }
376
+ });
377
+ });
378
+ }
379
+ /**
380
+ * 销毁实例
381
+ */
382
+ destroy() {
383
+ if (this.isDestroyed) {
384
+ this.warn('实例已销毁');
385
+ return;
386
+ }
387
+ try {
388
+ // 清理 COS 实例
389
+ this.cos = null;
390
+ // 重置状态
391
+ this.isDestroyed = true;
392
+ this.isInitialized = false;
393
+ this.mode = null;
394
+ this.headers = {};
395
+ this.scopeLimit = false;
396
+ this.log('实例已销毁');
397
+ }
398
+ catch (error) {
399
+ this.error('销毁实例失败:', error);
400
+ }
401
+ }
402
+ }
403
+
404
+ exports.BUCKETS_CONFIG = BUCKETS_CONFIG;
405
+ exports.BeLinkCOS = BeLinkCOS;
406
+ exports.REGION = REGION;
407
+ //# sourceMappingURL=index.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/config.ts","../src/beLinkCos.ts"],"sourcesContent":["/**\n * 环境模式类型\n * - development: 开发环境\n * - test: 测试环境\n * - production: 生产环境\n */\nexport type EnvMode = 'development' | 'test' | 'production';\n\n/**\n * COS 存储桶配置接口\n */\nexport interface BucketConfig {\n /** 存储桶名称 */\n name: string;\n /** 存储桶访问域名 */\n host: string;\n /** 访问协议 */\n protocol: string;\n}\n\n/**\n * 各环境的 COS 存储桶配置\n * 根据环境自动切换到对应的存储桶\n */\nexport const BUCKETS_CONFIG: Record<EnvMode, BucketConfig> = {\n development: {\n name: 'dev-1304510571',\n host: 'dev-1304510571.cos.ap-nanjing.myqcloud.com',\n protocol: 'https',\n },\n test: {\n name: 'dev-1304510571',\n host: 'dev-1304510571.cos.ap-nanjing.myqcloud.com',\n protocol: 'https',\n },\n production: {\n name: 'release-1304510571',\n host: 'release-1304510571.file.myqcloud.com',\n protocol: 'https',\n },\n};\n\n/** COS 存储桶所在地域(南京) */\nexport const REGION = 'ap-nanjing' as const;\n","import CryptoJS from 'crypto-js';\n// @ts-ignore\nimport COS from 'cos-js-sdk-v5';\n\nimport { BUCKETS_CONFIG, REGION, type EnvMode } from './config';\nimport type { InitConfig, UploadConfig, UploadResult } from './types';\n\n/**\n * BeLinkCOS 类 - 腾讯云 COS 文件上传工具\n *\n * 功能:文件上传、MD5 计算、临时密钥授权\n *\n * @example\n * import { BeLinkCOS } from '@be-link/cos';\n *\n * // 方式一:构造函数传入配置,立即初始化\n * const uploader = new BeLinkCOS({ mode: 'production' });\n * await uploader.uploadFile(file);\n *\n * // 方式二:先创建实例,稍后初始化(支持异步配置)\n * const uploader = new BeLinkCOS();\n * const config = await fetchConfig(); // 从服务器获取配置\n * uploader.init({ mode: 'production' });\n * await uploader.uploadFile(file);\n */\nexport class BeLinkCOS {\n /** COS SDK 实例 */\n private cos: any = null;\n /** COS 存储的基础路径 */\n private readonly basePath: string = '/beLinkAllSource/static/';\n /** 自定义请求头 */\n public headers: Record<string, any> = {};\n /** 当前环境模式 */\n public mode: EnvMode | null = null;\n /** 是否限制临时密钥的使用范围 */\n private scopeLimit: boolean = false;\n /** 生命周期状态 */\n protected isInitialized: boolean = false;\n protected isDestroyed: boolean = false;\n /** 调试模式 */\n private debug: boolean = false;\n\n /**\n * 构造函数\n *\n * 支持两种使用方式:\n * 1. 立即初始化:传入配置对象,构造函数中自动调用 init()\n * 2. 延迟初始化:不传配置,稍后调用 init() 方法(支持异步配置)\n *\n * @param config - 可选的初始化配置\n * @param config.mode - **必填** 环境模式:'development' | 'test' | 'production'\n * @param config.headers - 可选,自定义请求头\n * @param config.ScopeLimit - 可选,是否限制临时密钥的使用范围(默认 false)\n * @param config.debug - 可选,是否开启调试模式(默认 false)\n *\n * @example\n * // 立即初始化\n * const uploader = new BeLinkCOS({ mode: 'production' });\n *\n * // 延迟初始化\n * const uploader = new BeLinkCOS();\n * // ... 稍后调用 uploader.init(config);\n */\n constructor(config?: InitConfig) {\n // 如果传入配置,立即初始化\n if (config) {\n this.init(config);\n }\n }\n\n /**\n * 初始化 COS 实例\n * @param config 配置对象\n * @description 可以在创建实例时通过构造函数传入配置,也可以稍后调用此方法初始化\n */\n init(config: InitConfig): void {\n if (this.isDestroyed) {\n this.warn('实例已销毁,无法初始化');\n return;\n }\n\n if (this.isInitialized) {\n this.warn('实例已初始化,请勿重复调用');\n return;\n }\n\n if (!this.validateConfig(config)) {\n return;\n }\n\n // 保存配置\n this.mode = config.mode;\n this.headers = config.headers || {};\n this.scopeLimit = config.ScopeLimit || false;\n this.debug = config.debug || false;\n this.isInitialized = true;\n\n this.log('COS 实例初始化成功', { mode: this.mode });\n }\n\n /**\n * 初始化 COS SDK 实例\n *\n * 内部方法,通过云函数获取临时密钥\n * 首次上传时会自动调用\n *\n * @returns Promise<void>\n */\n private async initCOS(): Promise<void> {\n if (this.cos) {\n return; // 已初始化,直接返回\n }\n\n const cos = new COS({\n getAuthorization: (_options: any, callback: (p: any) => void) => {\n const url =\n this.mode === 'production'\n ? 'https://shield-60660-10-1304510571.sh.run.tcloudbase.com/config/get-cos-temp-secret'\n : 'https://shield-74680-5-1304510571.sh.run.tcloudbase.com/config/get-cos-temp-secret';\n fetch(url, { method: 'POST' })\n .then((response) => response.json())\n .then((result: any) => {\n const data = result?.data || {};\n const credentials = data?.credentials;\n\n callback({\n TmpSecretId: credentials.tmpSecretId, // 临时密钥的 tmpSecretId\n TmpSecretKey: credentials.tmpSecretKey, // 临时密钥的 tmpSecretKey\n SecurityToken: credentials.sessionToken, // 临时密钥的 sessionToken\n // 建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误\n StartTime: data.startTime, // 时间戳,单位秒,如:1580000000\n ExpiredTime: data.expiredTime, // 临时密钥失效时间戳,是申请临时密钥时,时间戳加 durationSeconds\n ScopeLimit: this.scopeLimit, // 细粒度控制权限需要设为 true,会限制密钥只在相同请求时重复使用\n });\n })\n .catch((error) => {\n this.error('获取临时密钥失败:', error);\n callback(null);\n });\n },\n });\n this.cos = cos;\n this.log('COS SDK 初始化成功');\n }\n\n /**\n * 检查实例状态\n */\n protected checkState(methodName: string): boolean {\n if (this.isDestroyed) {\n this.warn(`实例已销毁,无法调用 ${methodName}`);\n return false;\n }\n if (!this.isInitialized) {\n this.warn(`实例未初始化,请先调用 init 方法`);\n return false;\n }\n return true;\n }\n\n /**\n * 内部日志方法\n */\n protected log(...args: unknown[]): void {\n if (this.debug) {\n console.log(`[${this.constructor.name}]`, ...args);\n }\n }\n\n protected warn(...args: unknown[]): void {\n if (this.debug) {\n console.warn(`[${this.constructor.name}]`, ...args);\n }\n }\n\n protected error(...args: unknown[]): void {\n if (this.debug) {\n console.error(`[${this.constructor.name}]`, ...args);\n }\n }\n\n /**\n * 验证配置\n */\n protected validateConfig(config: InitConfig): boolean {\n if (!config) {\n this.error('配置对象不能为空');\n return false;\n }\n\n if (!config.mode) {\n this.error('mode 是必需的');\n return false;\n }\n\n if (!['development', 'test', 'production'].includes(config.mode)) {\n this.error('mode 必须是 development、test 或 production');\n return false;\n }\n\n return true;\n }\n\n /**\n * 获取配置\n */\n getConfig(): { mode: EnvMode | null; headers: Record<string, any>; scopeLimit: boolean } | null {\n if (!this.isInitialized) {\n this.warn('实例未初始化');\n return null;\n }\n return {\n mode: this.mode,\n headers: this.headers,\n scopeLimit: this.scopeLimit,\n };\n }\n\n /**\n * 计算文件的 MD5 哈希值\n *\n * 性能优化:\n * - 小文件(< 10MB):一次性读取,速度更快\n * - 大文件:分片读取,避免内存溢出\n *\n * @param file - 要计算 MD5 的文件对象\n * @param chunkSize - 分片大小(字节),默认 2MB\n * @returns Promise<string> 文件的 MD5 哈希值\n *\n * @example\n * const md5 = await beLinkCOS.createFileMd5(file);\n * console.log('文件 MD5:', md5);\n */\n public createFileMd5(file: File, chunkSize: number = 2 * 1024 * 1024): Promise<string> {\n return new Promise((resolve, reject) => {\n // 对于小文件(< 10MB),使用简单方法\n if (file.size < 10 * 1024 * 1024) {\n const reader = new FileReader();\n\n reader.onload = (e: ProgressEvent<FileReader>) => {\n const arrayBuffer = e.target?.result as ArrayBuffer;\n if (arrayBuffer) {\n const wordArray = CryptoJS.lib.WordArray.create(arrayBuffer as any);\n const hash = CryptoJS.MD5(wordArray).toString();\n resolve(hash);\n } else {\n reject(new Error('Failed to read file'));\n }\n };\n\n reader.onerror = (error: ProgressEvent<FileReader>) => {\n reject(error);\n };\n\n reader.readAsArrayBuffer(file);\n return;\n }\n\n // 对于大文件,使用分片读取\n let currentChunk = 0;\n const chunks = Math.ceil(file.size / chunkSize);\n const spark = CryptoJS.algo.MD5.create();\n const reader = new FileReader();\n\n reader.onload = (e: ProgressEvent<FileReader>) => {\n const arrayBuffer = e.target?.result as ArrayBuffer;\n if (arrayBuffer) {\n const wordArray = CryptoJS.lib.WordArray.create(arrayBuffer as any);\n spark.update(wordArray);\n\n currentChunk++;\n\n if (currentChunk < chunks) {\n loadNext();\n } else {\n const hash = spark.finalize().toString();\n resolve(hash);\n }\n }\n };\n\n reader.onerror = (error: ProgressEvent<FileReader>) => {\n reject(error);\n };\n\n const loadNext = () => {\n const start = currentChunk * chunkSize;\n const end = Math.min(start + chunkSize, file.size);\n const blob = file.slice(start, end);\n reader.readAsArrayBuffer(blob);\n };\n\n loadNext();\n });\n }\n\n /**\n * 生成文件在 COS 中的存储路径\n *\n * 路径规则:/beLinkAllSource/static/{文件类型}/{文件名}_{时间戳}.{扩展名}\n * 例如:/beLinkAllSource/static/image/avatar_1699999999999.png\n *\n * @param file - 文件对象\n * @returns string COS 存储路径\n */\n private getFilePath(file: File): string {\n const filename = file.name;\n const fileType = file?.type ? file.type.split('/')[0] : 'other';\n const fileExtension = filename.split('.').pop() || '';\n const filenameDateNow = `${filename.split('.')[0]}_${Date.now()}`;\n const newFileName = `${filenameDateNow}.${fileExtension}`;\n return `${this.basePath}${fileType}/${newFileName}`;\n }\n\n /**\n * 获取文件上传后的访问 URL(不执行实际上传)\n *\n * 用于在上传前预览文件的最终 URL\n *\n * @param file - 文件对象\n * @returns Promise<string | null> 文件的完整访问 URL,如果实例未初始化则返回 null\n *\n * @example\n * const url = await beLinkCOS.getSourceUrl(file);\n * console.log('文件将上传到:', url);\n */\n public async getSourceUrl(file: File): Promise<string | null> {\n if (!this.checkState('getSourceUrl')) {\n return null;\n }\n\n const path = this.getFilePath(file);\n return `https://${BUCKETS_CONFIG[this.mode!].host}${path}`;\n }\n\n /**\n * 上传文件到腾讯云 COS\n *\n * 核心功能:将文件上传到对应环境的 COS 存储桶\n * 支持上传进度回调、自定义请求头等配置\n *\n * @param file - 要上传的文件对象\n * @param config - 上传配置(可选)\n * @param config.Headers - 自定义请求头\n * @param config.onProgressCallback - 上传进度回调函数\n * @returns Promise<UploadResult> 上传结果,包含文件 URL、ETag 等信息\n *\n * @example\n * const uploader = new BeLinkCOS({ mode: 'production' });\n * const result = await uploader.uploadFile(file, {\n * onProgressCallback: (progressData) => {\n * console.log('进度:', progressData.percent * 100 + '%');\n * }\n * });\n * console.log('文件 URL:', result.url);\n */\n public async uploadFile(file: File, config?: UploadConfig): Promise<UploadResult> {\n if (!this.checkState('uploadFile')) {\n throw new Error('实例未初始化或已销毁');\n }\n\n // 首次上传时自动初始化 COS SDK\n if (!this.cos) {\n await this.initCOS();\n }\n\n const key = this.getFilePath(file);\n this.log('开始上传文件:', { filename: file.name, key });\n\n return new Promise((resolve, reject) => {\n this.cos?.putObject(\n {\n Bucket: BUCKETS_CONFIG[this.mode!].name,\n Region: REGION,\n Key: key,\n Body: file,\n onProgress: config?.onProgressCallback,\n ...config,\n Headers: { ...this.headers, ...(config?.Headers || {}) },\n },\n (err: any, data: UploadResult) => {\n if (err) {\n this.error('上传失败:', err);\n reject(err);\n } else {\n const url = `https://${data.Location}`;\n this.log('上传成功:', url);\n resolve({ ...data, url });\n }\n },\n );\n });\n }\n\n /**\n * 销毁实例\n */\n destroy(): void {\n if (this.isDestroyed) {\n this.warn('实例已销毁');\n return;\n }\n\n try {\n // 清理 COS 实例\n this.cos = null;\n\n // 重置状态\n this.isDestroyed = true;\n this.isInitialized = false;\n this.mode = null;\n this.headers = {};\n this.scopeLimit = false;\n\n this.log('实例已销毁');\n } catch (error) {\n this.error('销毁实例失败:', error);\n }\n }\n}\n"],"names":[],"mappings":"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"}
@@ -11,7 +11,7 @@ const BUCKETS_CONFIG = {
11
11
  host: 'dev-1304510571.cos.ap-nanjing.myqcloud.com',
12
12
  protocol: 'https',
13
13
  },
14
- testing: {
14
+ test: {
15
15
  name: 'dev-1304510571',
16
16
  host: 'dev-1304510571.cos.ap-nanjing.myqcloud.com',
17
17
  protocol: 'https',
@@ -33,45 +33,89 @@ const REGION = 'ap-nanjing';
33
33
  * @example
34
34
  * import { BeLinkCOS } from '@be-link/cos';
35
35
  *
36
+ * // 方式一:构造函数传入配置,立即初始化
36
37
  * const uploader = new BeLinkCOS({ mode: 'production' });
37
38
  * await uploader.uploadFile(file);
39
+ *
40
+ * // 方式二:先创建实例,稍后初始化(支持异步配置)
41
+ * const uploader = new BeLinkCOS();
42
+ * const config = await fetchConfig(); // 从服务器获取配置
43
+ * uploader.init({ mode: 'production' });
44
+ * await uploader.uploadFile(file);
38
45
  */
39
46
  class BeLinkCOS {
40
47
  /**
41
48
  * 构造函数
42
49
  *
43
- * 注意:mode 参数必填,没有默认值
44
- * 设计理念:强制显式配置环境,避免误传到错误的环境
50
+ * 支持两种使用方式:
51
+ * 1. 立即初始化:传入配置对象,构造函数中自动调用 init()
52
+ * 2. 延迟初始化:不传配置,稍后调用 init() 方法(支持异步配置)
45
53
  *
46
- * @param config - 初始化配置
47
- * @param config.mode - **必填** 环境模式:'development' | 'testing' | 'production'
54
+ * @param config - 可选的初始化配置
55
+ * @param config.mode - **必填** 环境模式:'development' | 'test' | 'production'
48
56
  * @param config.headers - 可选,自定义请求头
49
57
  * @param config.ScopeLimit - 可选,是否限制临时密钥的使用范围(默认 false)
58
+ * @param config.debug - 可选,是否开启调试模式(默认 false)
50
59
  *
51
60
  * @example
52
- * // 基础使用
61
+ * // 立即初始化
53
62
  * const uploader = new BeLinkCOS({ mode: 'production' });
54
63
  *
55
- * // 带自定义请求头
56
- * const uploader = new BeLinkCOS({
57
- * mode: 'production',
58
- * headers: { 'x-custom': 'value' }
59
- * });
64
+ * // 延迟初始化
65
+ * const uploader = new BeLinkCOS();
66
+ * // ... 稍后调用 uploader.init(config);
60
67
  */
61
68
  constructor(config) {
62
69
  /** COS SDK 实例 */
63
70
  this.cos = null;
64
71
  /** COS 存储的基础路径 */
65
72
  this.basePath = '/beLinkAllSource/static/';
73
+ /** 自定义请求头 */
74
+ this.headers = {};
75
+ /** 当前环境模式 */
76
+ this.mode = null;
77
+ /** 是否限制临时密钥的使用范围 */
78
+ this.scopeLimit = false;
79
+ /** 生命周期状态 */
80
+ this.isInitialized = false;
81
+ this.isDestroyed = false;
82
+ /** 调试模式 */
83
+ this.debug = false;
84
+ // 如果传入配置,立即初始化
85
+ if (config) {
86
+ this.init(config);
87
+ }
88
+ }
89
+ /**
90
+ * 初始化 COS 实例
91
+ * @param config 配置对象
92
+ * @description 可以在创建实例时通过构造函数传入配置,也可以稍后调用此方法初始化
93
+ */
94
+ init(config) {
95
+ if (this.isDestroyed) {
96
+ this.warn('实例已销毁,无法初始化');
97
+ return;
98
+ }
99
+ if (this.isInitialized) {
100
+ this.warn('实例已初始化,请勿重复调用');
101
+ return;
102
+ }
103
+ if (!this.validateConfig(config)) {
104
+ return;
105
+ }
106
+ // 保存配置
66
107
  this.mode = config.mode;
67
108
  this.headers = config.headers || {};
68
109
  this.scopeLimit = config.ScopeLimit || false;
110
+ this.debug = config.debug || false;
111
+ this.isInitialized = true;
112
+ this.log('COS 实例初始化成功', { mode: this.mode });
69
113
  }
70
114
  /**
71
115
  * 初始化 COS SDK 实例
72
116
  *
73
117
  * 内部方法,通过云函数获取临时密钥
74
- * 首次上传时会自动调用,也可以手动调用以重新初始化
118
+ * 首次上传时会自动调用
75
119
  *
76
120
  * @returns Promise<void>
77
121
  */
@@ -100,12 +144,77 @@ class BeLinkCOS {
100
144
  });
101
145
  })
102
146
  .catch((error) => {
103
- console.error('Error fetching authorization:', error);
147
+ this.error('获取临时密钥失败:', error);
104
148
  callback(null);
105
149
  });
106
150
  },
107
151
  });
108
152
  this.cos = cos;
153
+ this.log('COS SDK 初始化成功');
154
+ }
155
+ /**
156
+ * 检查实例状态
157
+ */
158
+ checkState(methodName) {
159
+ if (this.isDestroyed) {
160
+ this.warn(`实例已销毁,无法调用 ${methodName}`);
161
+ return false;
162
+ }
163
+ if (!this.isInitialized) {
164
+ this.warn(`实例未初始化,请先调用 init 方法`);
165
+ return false;
166
+ }
167
+ return true;
168
+ }
169
+ /**
170
+ * 内部日志方法
171
+ */
172
+ log(...args) {
173
+ if (this.debug) {
174
+ console.log(`[${this.constructor.name}]`, ...args);
175
+ }
176
+ }
177
+ warn(...args) {
178
+ if (this.debug) {
179
+ console.warn(`[${this.constructor.name}]`, ...args);
180
+ }
181
+ }
182
+ error(...args) {
183
+ if (this.debug) {
184
+ console.error(`[${this.constructor.name}]`, ...args);
185
+ }
186
+ }
187
+ /**
188
+ * 验证配置
189
+ */
190
+ validateConfig(config) {
191
+ if (!config) {
192
+ this.error('配置对象不能为空');
193
+ return false;
194
+ }
195
+ if (!config.mode) {
196
+ this.error('mode 是必需的');
197
+ return false;
198
+ }
199
+ if (!['development', 'test', 'production'].includes(config.mode)) {
200
+ this.error('mode 必须是 development、test 或 production');
201
+ return false;
202
+ }
203
+ return true;
204
+ }
205
+ /**
206
+ * 获取配置
207
+ */
208
+ getConfig() {
209
+ if (!this.isInitialized) {
210
+ this.warn('实例未初始化');
211
+ return null;
212
+ }
213
+ return {
214
+ mode: this.mode,
215
+ headers: this.headers,
216
+ scopeLimit: this.scopeLimit,
217
+ };
109
218
  }
110
219
  /**
111
220
  * 计算文件的 MD5 哈希值
@@ -183,9 +292,9 @@ class BeLinkCOS {
183
292
  * 例如:/beLinkAllSource/static/image/avatar_1699999999999.png
184
293
  *
185
294
  * @param file - 文件对象
186
- * @returns Promise<string> COS 存储路径
295
+ * @returns string COS 存储路径
187
296
  */
188
- async getFilePath(file) {
297
+ getFilePath(file) {
189
298
  const filename = file.name;
190
299
  const fileType = file?.type ? file.type.split('/')[0] : 'other';
191
300
  const fileExtension = filename.split('.').pop() || '';
@@ -199,14 +308,17 @@ class BeLinkCOS {
199
308
  * 用于在上传前预览文件的最终 URL
200
309
  *
201
310
  * @param file - 文件对象
202
- * @returns Promise<string> 文件的完整访问 URL
311
+ * @returns Promise<string | null> 文件的完整访问 URL,如果实例未初始化则返回 null
203
312
  *
204
313
  * @example
205
314
  * const url = await beLinkCOS.getSourceUrl(file);
206
315
  * console.log('文件将上传到:', url);
207
316
  */
208
317
  async getSourceUrl(file) {
209
- const path = await this.getFilePath(file);
318
+ if (!this.checkState('getSourceUrl')) {
319
+ return null;
320
+ }
321
+ const path = this.getFilePath(file);
210
322
  return `https://${BUCKETS_CONFIG[this.mode].host}${path}`;
211
323
  }
212
324
  /**
@@ -231,11 +343,15 @@ class BeLinkCOS {
231
343
  * console.log('文件 URL:', result.url);
232
344
  */
233
345
  async uploadFile(file, config) {
346
+ if (!this.checkState('uploadFile')) {
347
+ throw new Error('实例未初始化或已销毁');
348
+ }
234
349
  // 首次上传时自动初始化 COS SDK
235
350
  if (!this.cos) {
236
351
  await this.initCOS();
237
352
  }
238
- const key = await this.getFilePath(file);
353
+ const key = this.getFilePath(file);
354
+ this.log('开始上传文件:', { filename: file.name, key });
239
355
  return new Promise((resolve, reject) => {
240
356
  this.cos?.putObject({
241
357
  Bucket: BUCKETS_CONFIG[this.mode].name,
@@ -247,16 +363,41 @@ class BeLinkCOS {
247
363
  Headers: { ...this.headers, ...(config?.Headers || {}) },
248
364
  }, (err, data) => {
249
365
  if (err) {
366
+ this.error('上传失败:', err);
250
367
  reject(err);
251
368
  }
252
369
  else {
253
370
  const url = `https://${data.Location}`;
371
+ this.log('上传成功:', url);
254
372
  resolve({ ...data, url });
255
373
  }
256
374
  });
257
375
  });
258
376
  }
377
+ /**
378
+ * 销毁实例
379
+ */
380
+ destroy() {
381
+ if (this.isDestroyed) {
382
+ this.warn('实例已销毁');
383
+ return;
384
+ }
385
+ try {
386
+ // 清理 COS 实例
387
+ this.cos = null;
388
+ // 重置状态
389
+ this.isDestroyed = true;
390
+ this.isInitialized = false;
391
+ this.mode = null;
392
+ this.headers = {};
393
+ this.scopeLimit = false;
394
+ this.log('实例已销毁');
395
+ }
396
+ catch (error) {
397
+ this.error('销毁实例失败:', error);
398
+ }
399
+ }
259
400
  }
260
401
 
261
402
  export { BUCKETS_CONFIG, BeLinkCOS, REGION };
262
- //# sourceMappingURL=index.js.map
403
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":["../src/config.ts","../src/beLinkCos.ts"],"sourcesContent":["/**\n * 环境模式类型\n * - development: 开发环境\n * - test: 测试环境\n * - production: 生产环境\n */\nexport type EnvMode = 'development' | 'test' | 'production';\n\n/**\n * COS 存储桶配置接口\n */\nexport interface BucketConfig {\n /** 存储桶名称 */\n name: string;\n /** 存储桶访问域名 */\n host: string;\n /** 访问协议 */\n protocol: string;\n}\n\n/**\n * 各环境的 COS 存储桶配置\n * 根据环境自动切换到对应的存储桶\n */\nexport const BUCKETS_CONFIG: Record<EnvMode, BucketConfig> = {\n development: {\n name: 'dev-1304510571',\n host: 'dev-1304510571.cos.ap-nanjing.myqcloud.com',\n protocol: 'https',\n },\n test: {\n name: 'dev-1304510571',\n host: 'dev-1304510571.cos.ap-nanjing.myqcloud.com',\n protocol: 'https',\n },\n production: {\n name: 'release-1304510571',\n host: 'release-1304510571.file.myqcloud.com',\n protocol: 'https',\n },\n};\n\n/** COS 存储桶所在地域(南京) */\nexport const REGION = 'ap-nanjing' as const;\n","import CryptoJS from 'crypto-js';\n// @ts-ignore\nimport COS from 'cos-js-sdk-v5';\n\nimport { BUCKETS_CONFIG, REGION, type EnvMode } from './config';\nimport type { InitConfig, UploadConfig, UploadResult } from './types';\n\n/**\n * BeLinkCOS 类 - 腾讯云 COS 文件上传工具\n *\n * 功能:文件上传、MD5 计算、临时密钥授权\n *\n * @example\n * import { BeLinkCOS } from '@be-link/cos';\n *\n * // 方式一:构造函数传入配置,立即初始化\n * const uploader = new BeLinkCOS({ mode: 'production' });\n * await uploader.uploadFile(file);\n *\n * // 方式二:先创建实例,稍后初始化(支持异步配置)\n * const uploader = new BeLinkCOS();\n * const config = await fetchConfig(); // 从服务器获取配置\n * uploader.init({ mode: 'production' });\n * await uploader.uploadFile(file);\n */\nexport class BeLinkCOS {\n /** COS SDK 实例 */\n private cos: any = null;\n /** COS 存储的基础路径 */\n private readonly basePath: string = '/beLinkAllSource/static/';\n /** 自定义请求头 */\n public headers: Record<string, any> = {};\n /** 当前环境模式 */\n public mode: EnvMode | null = null;\n /** 是否限制临时密钥的使用范围 */\n private scopeLimit: boolean = false;\n /** 生命周期状态 */\n protected isInitialized: boolean = false;\n protected isDestroyed: boolean = false;\n /** 调试模式 */\n private debug: boolean = false;\n\n /**\n * 构造函数\n *\n * 支持两种使用方式:\n * 1. 立即初始化:传入配置对象,构造函数中自动调用 init()\n * 2. 延迟初始化:不传配置,稍后调用 init() 方法(支持异步配置)\n *\n * @param config - 可选的初始化配置\n * @param config.mode - **必填** 环境模式:'development' | 'test' | 'production'\n * @param config.headers - 可选,自定义请求头\n * @param config.ScopeLimit - 可选,是否限制临时密钥的使用范围(默认 false)\n * @param config.debug - 可选,是否开启调试模式(默认 false)\n *\n * @example\n * // 立即初始化\n * const uploader = new BeLinkCOS({ mode: 'production' });\n *\n * // 延迟初始化\n * const uploader = new BeLinkCOS();\n * // ... 稍后调用 uploader.init(config);\n */\n constructor(config?: InitConfig) {\n // 如果传入配置,立即初始化\n if (config) {\n this.init(config);\n }\n }\n\n /**\n * 初始化 COS 实例\n * @param config 配置对象\n * @description 可以在创建实例时通过构造函数传入配置,也可以稍后调用此方法初始化\n */\n init(config: InitConfig): void {\n if (this.isDestroyed) {\n this.warn('实例已销毁,无法初始化');\n return;\n }\n\n if (this.isInitialized) {\n this.warn('实例已初始化,请勿重复调用');\n return;\n }\n\n if (!this.validateConfig(config)) {\n return;\n }\n\n // 保存配置\n this.mode = config.mode;\n this.headers = config.headers || {};\n this.scopeLimit = config.ScopeLimit || false;\n this.debug = config.debug || false;\n this.isInitialized = true;\n\n this.log('COS 实例初始化成功', { mode: this.mode });\n }\n\n /**\n * 初始化 COS SDK 实例\n *\n * 内部方法,通过云函数获取临时密钥\n * 首次上传时会自动调用\n *\n * @returns Promise<void>\n */\n private async initCOS(): Promise<void> {\n if (this.cos) {\n return; // 已初始化,直接返回\n }\n\n const cos = new COS({\n getAuthorization: (_options: any, callback: (p: any) => void) => {\n const url =\n this.mode === 'production'\n ? 'https://shield-60660-10-1304510571.sh.run.tcloudbase.com/config/get-cos-temp-secret'\n : 'https://shield-74680-5-1304510571.sh.run.tcloudbase.com/config/get-cos-temp-secret';\n fetch(url, { method: 'POST' })\n .then((response) => response.json())\n .then((result: any) => {\n const data = result?.data || {};\n const credentials = data?.credentials;\n\n callback({\n TmpSecretId: credentials.tmpSecretId, // 临时密钥的 tmpSecretId\n TmpSecretKey: credentials.tmpSecretKey, // 临时密钥的 tmpSecretKey\n SecurityToken: credentials.sessionToken, // 临时密钥的 sessionToken\n // 建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误\n StartTime: data.startTime, // 时间戳,单位秒,如:1580000000\n ExpiredTime: data.expiredTime, // 临时密钥失效时间戳,是申请临时密钥时,时间戳加 durationSeconds\n ScopeLimit: this.scopeLimit, // 细粒度控制权限需要设为 true,会限制密钥只在相同请求时重复使用\n });\n })\n .catch((error) => {\n this.error('获取临时密钥失败:', error);\n callback(null);\n });\n },\n });\n this.cos = cos;\n this.log('COS SDK 初始化成功');\n }\n\n /**\n * 检查实例状态\n */\n protected checkState(methodName: string): boolean {\n if (this.isDestroyed) {\n this.warn(`实例已销毁,无法调用 ${methodName}`);\n return false;\n }\n if (!this.isInitialized) {\n this.warn(`实例未初始化,请先调用 init 方法`);\n return false;\n }\n return true;\n }\n\n /**\n * 内部日志方法\n */\n protected log(...args: unknown[]): void {\n if (this.debug) {\n console.log(`[${this.constructor.name}]`, ...args);\n }\n }\n\n protected warn(...args: unknown[]): void {\n if (this.debug) {\n console.warn(`[${this.constructor.name}]`, ...args);\n }\n }\n\n protected error(...args: unknown[]): void {\n if (this.debug) {\n console.error(`[${this.constructor.name}]`, ...args);\n }\n }\n\n /**\n * 验证配置\n */\n protected validateConfig(config: InitConfig): boolean {\n if (!config) {\n this.error('配置对象不能为空');\n return false;\n }\n\n if (!config.mode) {\n this.error('mode 是必需的');\n return false;\n }\n\n if (!['development', 'test', 'production'].includes(config.mode)) {\n this.error('mode 必须是 development、test 或 production');\n return false;\n }\n\n return true;\n }\n\n /**\n * 获取配置\n */\n getConfig(): { mode: EnvMode | null; headers: Record<string, any>; scopeLimit: boolean } | null {\n if (!this.isInitialized) {\n this.warn('实例未初始化');\n return null;\n }\n return {\n mode: this.mode,\n headers: this.headers,\n scopeLimit: this.scopeLimit,\n };\n }\n\n /**\n * 计算文件的 MD5 哈希值\n *\n * 性能优化:\n * - 小文件(< 10MB):一次性读取,速度更快\n * - 大文件:分片读取,避免内存溢出\n *\n * @param file - 要计算 MD5 的文件对象\n * @param chunkSize - 分片大小(字节),默认 2MB\n * @returns Promise<string> 文件的 MD5 哈希值\n *\n * @example\n * const md5 = await beLinkCOS.createFileMd5(file);\n * console.log('文件 MD5:', md5);\n */\n public createFileMd5(file: File, chunkSize: number = 2 * 1024 * 1024): Promise<string> {\n return new Promise((resolve, reject) => {\n // 对于小文件(< 10MB),使用简单方法\n if (file.size < 10 * 1024 * 1024) {\n const reader = new FileReader();\n\n reader.onload = (e: ProgressEvent<FileReader>) => {\n const arrayBuffer = e.target?.result as ArrayBuffer;\n if (arrayBuffer) {\n const wordArray = CryptoJS.lib.WordArray.create(arrayBuffer as any);\n const hash = CryptoJS.MD5(wordArray).toString();\n resolve(hash);\n } else {\n reject(new Error('Failed to read file'));\n }\n };\n\n reader.onerror = (error: ProgressEvent<FileReader>) => {\n reject(error);\n };\n\n reader.readAsArrayBuffer(file);\n return;\n }\n\n // 对于大文件,使用分片读取\n let currentChunk = 0;\n const chunks = Math.ceil(file.size / chunkSize);\n const spark = CryptoJS.algo.MD5.create();\n const reader = new FileReader();\n\n reader.onload = (e: ProgressEvent<FileReader>) => {\n const arrayBuffer = e.target?.result as ArrayBuffer;\n if (arrayBuffer) {\n const wordArray = CryptoJS.lib.WordArray.create(arrayBuffer as any);\n spark.update(wordArray);\n\n currentChunk++;\n\n if (currentChunk < chunks) {\n loadNext();\n } else {\n const hash = spark.finalize().toString();\n resolve(hash);\n }\n }\n };\n\n reader.onerror = (error: ProgressEvent<FileReader>) => {\n reject(error);\n };\n\n const loadNext = () => {\n const start = currentChunk * chunkSize;\n const end = Math.min(start + chunkSize, file.size);\n const blob = file.slice(start, end);\n reader.readAsArrayBuffer(blob);\n };\n\n loadNext();\n });\n }\n\n /**\n * 生成文件在 COS 中的存储路径\n *\n * 路径规则:/beLinkAllSource/static/{文件类型}/{文件名}_{时间戳}.{扩展名}\n * 例如:/beLinkAllSource/static/image/avatar_1699999999999.png\n *\n * @param file - 文件对象\n * @returns string COS 存储路径\n */\n private getFilePath(file: File): string {\n const filename = file.name;\n const fileType = file?.type ? file.type.split('/')[0] : 'other';\n const fileExtension = filename.split('.').pop() || '';\n const filenameDateNow = `${filename.split('.')[0]}_${Date.now()}`;\n const newFileName = `${filenameDateNow}.${fileExtension}`;\n return `${this.basePath}${fileType}/${newFileName}`;\n }\n\n /**\n * 获取文件上传后的访问 URL(不执行实际上传)\n *\n * 用于在上传前预览文件的最终 URL\n *\n * @param file - 文件对象\n * @returns Promise<string | null> 文件的完整访问 URL,如果实例未初始化则返回 null\n *\n * @example\n * const url = await beLinkCOS.getSourceUrl(file);\n * console.log('文件将上传到:', url);\n */\n public async getSourceUrl(file: File): Promise<string | null> {\n if (!this.checkState('getSourceUrl')) {\n return null;\n }\n\n const path = this.getFilePath(file);\n return `https://${BUCKETS_CONFIG[this.mode!].host}${path}`;\n }\n\n /**\n * 上传文件到腾讯云 COS\n *\n * 核心功能:将文件上传到对应环境的 COS 存储桶\n * 支持上传进度回调、自定义请求头等配置\n *\n * @param file - 要上传的文件对象\n * @param config - 上传配置(可选)\n * @param config.Headers - 自定义请求头\n * @param config.onProgressCallback - 上传进度回调函数\n * @returns Promise<UploadResult> 上传结果,包含文件 URL、ETag 等信息\n *\n * @example\n * const uploader = new BeLinkCOS({ mode: 'production' });\n * const result = await uploader.uploadFile(file, {\n * onProgressCallback: (progressData) => {\n * console.log('进度:', progressData.percent * 100 + '%');\n * }\n * });\n * console.log('文件 URL:', result.url);\n */\n public async uploadFile(file: File, config?: UploadConfig): Promise<UploadResult> {\n if (!this.checkState('uploadFile')) {\n throw new Error('实例未初始化或已销毁');\n }\n\n // 首次上传时自动初始化 COS SDK\n if (!this.cos) {\n await this.initCOS();\n }\n\n const key = this.getFilePath(file);\n this.log('开始上传文件:', { filename: file.name, key });\n\n return new Promise((resolve, reject) => {\n this.cos?.putObject(\n {\n Bucket: BUCKETS_CONFIG[this.mode!].name,\n Region: REGION,\n Key: key,\n Body: file,\n onProgress: config?.onProgressCallback,\n ...config,\n Headers: { ...this.headers, ...(config?.Headers || {}) },\n },\n (err: any, data: UploadResult) => {\n if (err) {\n this.error('上传失败:', err);\n reject(err);\n } else {\n const url = `https://${data.Location}`;\n this.log('上传成功:', url);\n resolve({ ...data, url });\n }\n },\n );\n });\n }\n\n /**\n * 销毁实例\n */\n destroy(): void {\n if (this.isDestroyed) {\n this.warn('实例已销毁');\n return;\n }\n\n try {\n // 清理 COS 实例\n this.cos = null;\n\n // 重置状态\n this.isDestroyed = true;\n this.isInitialized = false;\n this.mode = null;\n this.headers = {};\n this.scopeLimit = false;\n\n this.log('实例已销毁');\n } catch (error) {\n this.error('销毁实例失败:', error);\n }\n }\n}\n"],"names":[],"mappings":";;;AAoBA;;;AAGG;AACI,MAAM,cAAc,GAAkC;AAC3D,IAAA,WAAW,EAAE;AACX,QAAA,IAAI,EAAE,gBAAgB;AACtB,QAAA,IAAI,EAAE,4CAA4C;AAClD,QAAA,QAAQ,EAAE,OAAO;AAClB,KAAA;AACD,IAAA,IAAI,EAAE;AACJ,QAAA,IAAI,EAAE,gBAAgB;AACtB,QAAA,IAAI,EAAE,4CAA4C;AAClD,QAAA,QAAQ,EAAE,OAAO;AAClB,KAAA;AACD,IAAA,UAAU,EAAE;AACV,QAAA,IAAI,EAAE,oBAAoB;AAC1B,QAAA,IAAI,EAAE,sCAAsC;AAC5C,QAAA,QAAQ,EAAE,OAAO;AAClB,KAAA;;AAGH;AACO,MAAM,MAAM,GAAG;;ACpCtB;;;;;;;;;;;;;;;;;AAiBG;MACU,SAAS,CAAA;AAiBpB;;;;;;;;;;;;;;;;;;;;AAoBG;AACH,IAAA,WAAA,CAAY,MAAmB,EAAA;;QApCvB,IAAA,CAAA,GAAG,GAAQ,IAAI;;QAEN,IAAA,CAAA,QAAQ,GAAW,0BAA0B;;QAEvD,IAAA,CAAA,OAAO,GAAwB,EAAE;;QAEjC,IAAA,CAAA,IAAI,GAAmB,IAAI;;QAE1B,IAAA,CAAA,UAAU,GAAY,KAAK;;QAEzB,IAAA,CAAA,aAAa,GAAY,KAAK;QAC9B,IAAA,CAAA,WAAW,GAAY,KAAK;;QAE9B,IAAA,CAAA,KAAK,GAAY,KAAK;;QAyB5B,IAAI,MAAM,EAAE;AACV,YAAA,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;QACnB;IACF;AAEA;;;;AAIG;AACH,IAAA,IAAI,CAAC,MAAkB,EAAA;AACrB,QAAA,IAAI,IAAI,CAAC,WAAW,EAAE;AACpB,YAAA,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC;YACxB;QACF;AAEA,QAAA,IAAI,IAAI,CAAC,aAAa,EAAE;AACtB,YAAA,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC;YAC1B;QACF;QAEA,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE;YAChC;QACF;;AAGA,QAAA,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI;QACvB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,EAAE;QACnC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,KAAK;QAC5C,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,KAAK;AAClC,QAAA,IAAI,CAAC,aAAa,GAAG,IAAI;AAEzB,QAAA,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;IAC9C;AAEA;;;;;;;AAOG;AACK,IAAA,MAAM,OAAO,GAAA;AACnB,QAAA,IAAI,IAAI,CAAC,GAAG,EAAE;AACZ,YAAA,OAAO;QACT;AAEA,QAAA,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC;AAClB,YAAA,gBAAgB,EAAE,CAAC,QAAa,EAAE,QAA0B,KAAI;AAC9D,gBAAA,MAAM,GAAG,GACP,IAAI,CAAC,IAAI,KAAK;AACZ,sBAAE;sBACA,oFAAoF;gBAC1F,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE;qBAC1B,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,IAAI,EAAE;AAClC,qBAAA,IAAI,CAAC,CAAC,MAAW,KAAI;AACpB,oBAAA,MAAM,IAAI,GAAG,MAAM,EAAE,IAAI,IAAI,EAAE;AAC/B,oBAAA,MAAM,WAAW,GAAG,IAAI,EAAE,WAAW;AAErC,oBAAA,QAAQ,CAAC;AACP,wBAAA,WAAW,EAAE,WAAW,CAAC,WAAW;AACpC,wBAAA,YAAY,EAAE,WAAW,CAAC,YAAY;AACtC,wBAAA,aAAa,EAAE,WAAW,CAAC,YAAY;;AAEvC,wBAAA,SAAS,EAAE,IAAI,CAAC,SAAS;AACzB,wBAAA,WAAW,EAAE,IAAI,CAAC,WAAW;AAC7B,wBAAA,UAAU,EAAE,IAAI,CAAC,UAAU;AAC5B,qBAAA,CAAC;AACJ,gBAAA,CAAC;AACA,qBAAA,KAAK,CAAC,CAAC,KAAK,KAAI;AACf,oBAAA,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC;oBAC9B,QAAQ,CAAC,IAAI,CAAC;AAChB,gBAAA,CAAC,CAAC;YACN,CAAC;AACF,SAAA,CAAC;AACF,QAAA,IAAI,CAAC,GAAG,GAAG,GAAG;AACd,QAAA,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC;IAC3B;AAEA;;AAEG;AACO,IAAA,UAAU,CAAC,UAAkB,EAAA;AACrC,QAAA,IAAI,IAAI,CAAC,WAAW,EAAE;AACpB,YAAA,IAAI,CAAC,IAAI,CAAC,cAAc,UAAU,CAAA,CAAE,CAAC;AACrC,YAAA,OAAO,KAAK;QACd;AACA,QAAA,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;AACvB,YAAA,IAAI,CAAC,IAAI,CAAC,CAAA,mBAAA,CAAqB,CAAC;AAChC,YAAA,OAAO,KAAK;QACd;AACA,QAAA,OAAO,IAAI;IACb;AAEA;;AAEG;IACO,GAAG,CAAC,GAAG,IAAe,EAAA;AAC9B,QAAA,IAAI,IAAI,CAAC,KAAK,EAAE;AACd,YAAA,OAAO,CAAC,GAAG,CAAC,CAAA,CAAA,EAAI,IAAI,CAAC,WAAW,CAAC,IAAI,CAAA,CAAA,CAAG,EAAE,GAAG,IAAI,CAAC;QACpD;IACF;IAEU,IAAI,CAAC,GAAG,IAAe,EAAA;AAC/B,QAAA,IAAI,IAAI,CAAC,KAAK,EAAE;AACd,YAAA,OAAO,CAAC,IAAI,CAAC,CAAA,CAAA,EAAI,IAAI,CAAC,WAAW,CAAC,IAAI,CAAA,CAAA,CAAG,EAAE,GAAG,IAAI,CAAC;QACrD;IACF;IAEU,KAAK,CAAC,GAAG,IAAe,EAAA;AAChC,QAAA,IAAI,IAAI,CAAC,KAAK,EAAE;AACd,YAAA,OAAO,CAAC,KAAK,CAAC,CAAA,CAAA,EAAI,IAAI,CAAC,WAAW,CAAC,IAAI,CAAA,CAAA,CAAG,EAAE,GAAG,IAAI,CAAC;QACtD;IACF;AAEA;;AAEG;AACO,IAAA,cAAc,CAAC,MAAkB,EAAA;QACzC,IAAI,CAAC,MAAM,EAAE;AACX,YAAA,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;AACtB,YAAA,OAAO,KAAK;QACd;AAEA,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;AAChB,YAAA,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;AACvB,YAAA,OAAO,KAAK;QACd;AAEA,QAAA,IAAI,CAAC,CAAC,aAAa,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;AAChE,YAAA,IAAI,CAAC,KAAK,CAAC,wCAAwC,CAAC;AACpD,YAAA,OAAO,KAAK;QACd;AAEA,QAAA,OAAO,IAAI;IACb;AAEA;;AAEG;IACH,SAAS,GAAA;AACP,QAAA,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;AACvB,YAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;AACnB,YAAA,OAAO,IAAI;QACb;QACA,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,UAAU,EAAE,IAAI,CAAC,UAAU;SAC5B;IACH;AAEA;;;;;;;;;;;;;;AAcG;IACI,aAAa,CAAC,IAAU,EAAE,SAAA,GAAoB,CAAC,GAAG,IAAI,GAAG,IAAI,EAAA;QAClE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,KAAI;;YAErC,IAAI,IAAI,CAAC,IAAI,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE;AAChC,gBAAA,MAAM,MAAM,GAAG,IAAI,UAAU,EAAE;AAE/B,gBAAA,MAAM,CAAC,MAAM,GAAG,CAAC,CAA4B,KAAI;AAC/C,oBAAA,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,EAAE,MAAqB;oBACnD,IAAI,WAAW,EAAE;AACf,wBAAA,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,WAAkB,CAAC;wBACnE,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE;wBAC/C,OAAO,CAAC,IAAI,CAAC;oBACf;yBAAO;AACL,wBAAA,MAAM,CAAC,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;oBAC1C;AACF,gBAAA,CAAC;AAED,gBAAA,MAAM,CAAC,OAAO,GAAG,CAAC,KAAgC,KAAI;oBACpD,MAAM,CAAC,KAAK,CAAC;AACf,gBAAA,CAAC;AAED,gBAAA,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC;gBAC9B;YACF;;YAGA,IAAI,YAAY,GAAG,CAAC;AACpB,YAAA,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC;YAC/C,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE;AACxC,YAAA,MAAM,MAAM,GAAG,IAAI,UAAU,EAAE;AAE/B,YAAA,MAAM,CAAC,MAAM,GAAG,CAAC,CAA4B,KAAI;AAC/C,gBAAA,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,EAAE,MAAqB;gBACnD,IAAI,WAAW,EAAE;AACf,oBAAA,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,WAAkB,CAAC;AACnE,oBAAA,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC;AAEvB,oBAAA,YAAY,EAAE;AAEd,oBAAA,IAAI,YAAY,GAAG,MAAM,EAAE;AACzB,wBAAA,QAAQ,EAAE;oBACZ;yBAAO;wBACL,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;wBACxC,OAAO,CAAC,IAAI,CAAC;oBACf;gBACF;AACF,YAAA,CAAC;AAED,YAAA,MAAM,CAAC,OAAO,GAAG,CAAC,KAAgC,KAAI;gBACpD,MAAM,CAAC,KAAK,CAAC;AACf,YAAA,CAAC;YAED,MAAM,QAAQ,GAAG,MAAK;AACpB,gBAAA,MAAM,KAAK,GAAG,YAAY,GAAG,SAAS;AACtC,gBAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC;gBAClD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC;AACnC,gBAAA,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC;AAChC,YAAA,CAAC;AAED,YAAA,QAAQ,EAAE;AACZ,QAAA,CAAC,CAAC;IACJ;AAEA;;;;;;;;AAQG;AACK,IAAA,WAAW,CAAC,IAAU,EAAA;AAC5B,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI;QAC1B,MAAM,QAAQ,GAAG,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO;AAC/D,QAAA,MAAM,aAAa,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE;AACrD,QAAA,MAAM,eAAe,GAAG,CAAA,EAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA,CAAA,EAAI,IAAI,CAAC,GAAG,EAAE,EAAE;AACjE,QAAA,MAAM,WAAW,GAAG,CAAA,EAAG,eAAe,CAAA,CAAA,EAAI,aAAa,EAAE;QACzD,OAAO,CAAA,EAAG,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA,CAAA,EAAI,WAAW,CAAA,CAAE;IACrD;AAEA;;;;;;;;;;;AAWG;IACI,MAAM,YAAY,CAAC,IAAU,EAAA;QAClC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE;AACpC,YAAA,OAAO,IAAI;QACb;QAEA,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;AACnC,QAAA,OAAO,CAAA,QAAA,EAAW,cAAc,CAAC,IAAI,CAAC,IAAK,CAAC,CAAC,IAAI,CAAA,EAAG,IAAI,CAAA,CAAE;IAC5D;AAEA;;;;;;;;;;;;;;;;;;;;AAoBG;AACI,IAAA,MAAM,UAAU,CAAC,IAAU,EAAE,MAAqB,EAAA;QACvD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE;AAClC,YAAA,MAAM,IAAI,KAAK,CAAC,YAAY,CAAC;QAC/B;;AAGA,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;AACb,YAAA,MAAM,IAAI,CAAC,OAAO,EAAE;QACtB;QAEA,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;AAClC,QAAA,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC;QAEjD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,KAAI;AACrC,YAAA,IAAI,CAAC,GAAG,EAAE,SAAS,CACjB;gBACE,MAAM,EAAE,cAAc,CAAC,IAAI,CAAC,IAAK,CAAC,CAAC,IAAI;AACvC,gBAAA,MAAM,EAAE,MAAM;AACd,gBAAA,GAAG,EAAE,GAAG;AACR,gBAAA,IAAI,EAAE,IAAI;gBACV,UAAU,EAAE,MAAM,EAAE,kBAAkB;AACtC,gBAAA,GAAG,MAAM;AACT,gBAAA,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,MAAM,EAAE,OAAO,IAAI,EAAE,CAAC,EAAE;AACzD,aAAA,EACD,CAAC,GAAQ,EAAE,IAAkB,KAAI;gBAC/B,IAAI,GAAG,EAAE;AACP,oBAAA,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC;oBACxB,MAAM,CAAC,GAAG,CAAC;gBACb;qBAAO;AACL,oBAAA,MAAM,GAAG,GAAG,CAAA,QAAA,EAAW,IAAI,CAAC,QAAQ,EAAE;AACtC,oBAAA,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC;oBACtB,OAAO,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,CAAC;gBAC3B;AACF,YAAA,CAAC,CACF;AACH,QAAA,CAAC,CAAC;IACJ;AAEA;;AAEG;IACH,OAAO,GAAA;AACL,QAAA,IAAI,IAAI,CAAC,WAAW,EAAE;AACpB,YAAA,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;YAClB;QACF;AAEA,QAAA,IAAI;;AAEF,YAAA,IAAI,CAAC,GAAG,GAAG,IAAI;;AAGf,YAAA,IAAI,CAAC,WAAW,GAAG,IAAI;AACvB,YAAA,IAAI,CAAC,aAAa,GAAG,KAAK;AAC1B,YAAA,IAAI,CAAC,IAAI,GAAG,IAAI;AAChB,YAAA,IAAI,CAAC,OAAO,GAAG,EAAE;AACjB,YAAA,IAAI,CAAC,UAAU,GAAG,KAAK;AAEvB,YAAA,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;QACnB;QAAE,OAAO,KAAK,EAAE;AACd,YAAA,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC;QAC9B;IACF;AACD;;;;"}
package/dist/types.d.ts CHANGED
@@ -2,15 +2,16 @@ import type { EnvMode } from './config';
2
2
  /**
3
3
  * COS 初始化配置
4
4
  *
5
- * 注意:mode 参数必填,设计上不提供默认值
6
- * 原因:避免开发者忘记配置导致误传到错误环境
5
+ * 支持两种使用方式:
6
+ * 1. 构造函数传入配置,立即初始化
7
+ * 2. 稍后调用 init() 方法初始化(支持异步配置)
7
8
  */
8
9
  export interface InitConfig {
9
10
  /**
10
- * 环境模式(必填,无默认值)
11
+ * 环境模式(必填)
11
12
  *
12
13
  * - development: 开发环境
13
- * - testing: 测试环境
14
+ * - test: 测试环境
14
15
  * - production: 生产环境
15
16
  */
16
17
  mode: EnvMode;
@@ -18,6 +19,8 @@ export interface InitConfig {
18
19
  headers?: Record<string, any>;
19
20
  /** 是否限制临时密钥的使用范围(可选,默认 false) */
20
21
  ScopeLimit?: boolean;
22
+ /** 是否开启调试模式(可选,默认 false) */
23
+ debug?: boolean;
21
24
  }
22
25
  /**
23
26
  * 文件上传配置
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB;;;;;;OAMG;IACH,IAAI,EAAE,OAAO,CAAC;IAEd,iBAAiB;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAE9B,iCAAiC;IACjC,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,aAAa;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B,aAAa;IACb,kBAAkB,CAAC,EAAE,CAAC,YAAY,EAAE,GAAG,KAAK,IAAI,CAAC;IACjD,uBAAuB;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,eAAe;IACf,IAAI,EAAE,MAAM,CAAC;IACb,cAAc;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU;IACV,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,iBAAiB;IACjB,GAAG,EAAE,MAAM,CAAC;CACb"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB;;;;;;OAMG;IACH,IAAI,EAAE,OAAO,CAAC;IAEd,iBAAiB;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAE9B,iCAAiC;IACjC,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB,4BAA4B;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,aAAa;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B,aAAa;IACb,kBAAkB,CAAC,EAAE,CAAC,YAAY,EAAE,GAAG,KAAK,IAAI,CAAC;IACjD,uBAAuB;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,eAAe;IACf,IAAI,EAAE,MAAM,CAAC;IACb,cAAc;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU;IACV,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,iBAAiB;IACjB,GAAG,EAAE,MAAM,CAAC;CACb"}
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@be-link/cos",
3
- "version": "1.11.5-beta.0",
3
+ "version": "1.12.0-beta.1",
4
4
  "description": "前端项目产物上传cos",
5
5
  "author": "zhuifeng <yangyiboys@163.com>",
6
6
  "homepage": "https://github.com/snowmountain-top/be-link#readme",
7
7
  "license": "ISC",
8
- "main": "dist/index.js",
9
- "module": "dist/index.js",
8
+ "main": "dist/index.cjs.js",
9
+ "module": "dist/index.esm.js",
10
10
  "types": "dist/index.d.ts",
11
11
  "files": [
12
12
  "dist",
@@ -24,10 +24,6 @@
24
24
  "cos-js-sdk-v5": "^1.8.6",
25
25
  "crypto-js": "^4.2.0"
26
26
  },
27
- "dependencies": {
28
- "cos-js-sdk-v5": "^1.8.6",
29
- "crypto-js": "^4.2.0"
30
- },
31
27
  "devDependencies": {
32
28
  "@types/crypto-js": "^4.2.2"
33
29
  },
@@ -36,9 +32,9 @@
36
32
  },
37
33
  "gitHead": "76b71bb6850e5f57f1a1ba4bd17f2ae0f603b67e",
38
34
  "scripts": {
39
- "clean": "rimraf ./dist",
35
+ "clean": "rimraf ./dist && rimraf .rollup.cache",
40
36
  "build:js": "rollup --config rollup.config.ts --configPlugin typescript",
41
- "build:types": "tsc --project tsconfig.json --emitDeclarationOnly --declarationDir dist",
37
+ "build:types": "tsc --project tsconfig.json",
42
38
  "build": "pnpm clean && pnpm build:js && pnpm build:types"
43
39
  }
44
40
  }
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sources":["../src/config.ts","../src/beLinkCos.ts"],"sourcesContent":["/**\n * 环境模式类型\n * - development: 开发环境\n * - testing: 测试环境\n * - production: 生产环境\n */\nexport type EnvMode = 'development' | 'testing' | 'production';\n\n/**\n * COS 存储桶配置接口\n */\nexport interface BucketConfig {\n /** 存储桶名称 */\n name: string;\n /** 存储桶访问域名 */\n host: string;\n /** 访问协议 */\n protocol: string;\n}\n\n/**\n * 各环境的 COS 存储桶配置\n * 根据环境自动切换到对应的存储桶\n */\nexport const BUCKETS_CONFIG: Record<EnvMode, BucketConfig> = {\n development: {\n name: 'dev-1304510571',\n host: 'dev-1304510571.cos.ap-nanjing.myqcloud.com',\n protocol: 'https',\n },\n testing: {\n name: 'dev-1304510571',\n host: 'dev-1304510571.cos.ap-nanjing.myqcloud.com',\n protocol: 'https',\n },\n production: {\n name: 'release-1304510571',\n host: 'release-1304510571.file.myqcloud.com',\n protocol: 'https',\n },\n};\n\n/** COS 存储桶所在地域(南京) */\nexport const REGION = 'ap-nanjing' as const;\n","import CryptoJS from 'crypto-js';\n// @ts-ignore\nimport COS from 'cos-js-sdk-v5';\nimport { BUCKETS_CONFIG, REGION, type EnvMode } from './config';\nimport type { InitConfig, UploadConfig, UploadResult } from './types';\n\n/**\n * BeLinkCOS 类 - 腾讯云 COS 文件上传工具\n *\n * 功能:文件上传、MD5 计算、临时密钥授权\n *\n * @example\n * import { BeLinkCOS } from '@be-link/cos';\n *\n * const uploader = new BeLinkCOS({ mode: 'production' });\n * await uploader.uploadFile(file);\n */\nexport class BeLinkCOS {\n /** COS SDK 实例 */\n private cos: any = null;\n /** COS 存储的基础路径 */\n private readonly basePath: string = '/beLinkAllSource/static/';\n /** 自定义请求头 */\n public headers: Record<string, any>;\n /** 当前环境模式 */\n public mode: EnvMode;\n /** 是否限制临时密钥的使用范围 */\n private scopeLimit: boolean;\n\n /**\n * 构造函数\n *\n * 注意:mode 参数必填,没有默认值\n * 设计理念:强制显式配置环境,避免误传到错误的环境\n *\n * @param config - 初始化配置\n * @param config.mode - **必填** 环境模式:'development' | 'testing' | 'production'\n * @param config.headers - 可选,自定义请求头\n * @param config.ScopeLimit - 可选,是否限制临时密钥的使用范围(默认 false)\n *\n * @example\n * // 基础使用\n * const uploader = new BeLinkCOS({ mode: 'production' });\n *\n * // 带自定义请求头\n * const uploader = new BeLinkCOS({\n * mode: 'production',\n * headers: { 'x-custom': 'value' }\n * });\n */\n constructor(config: InitConfig) {\n this.mode = config.mode;\n this.headers = config.headers || {};\n this.scopeLimit = config.ScopeLimit || false;\n }\n\n /**\n * 初始化 COS SDK 实例\n *\n * 内部方法,通过云函数获取临时密钥\n * 首次上传时会自动调用,也可以手动调用以重新初始化\n *\n * @returns Promise<void>\n */\n private async initCOS(): Promise<void> {\n if (this.cos) {\n return; // 已初始化,直接返回\n }\n\n const cos = new COS({\n getAuthorization: (_options: any, callback: (p: any) => void) => {\n const url =\n this.mode === 'production'\n ? 'https://shield-60660-10-1304510571.sh.run.tcloudbase.com/config/get-cos-temp-secret'\n : 'https://shield-74680-5-1304510571.sh.run.tcloudbase.com/config/get-cos-temp-secret';\n fetch(url, { method: 'POST' })\n .then((response) => response.json())\n .then((result) => {\n const data = result?.data || {};\n const credentials = data?.credentials;\n\n callback({\n TmpSecretId: credentials.tmpSecretId, // 临时密钥的 tmpSecretId\n TmpSecretKey: credentials.tmpSecretKey, // 临时密钥的 tmpSecretKey\n SecurityToken: credentials.sessionToken, // 临时密钥的 sessionToken\n // 建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误\n StartTime: data.startTime, // 时间戳,单位秒,如:1580000000\n ExpiredTime: data.expiredTime, // 临时密钥失效时间戳,是申请临时密钥时,时间戳加 durationSeconds\n ScopeLimit: this.scopeLimit, // 细粒度控制权限需要设为 true,会限制密钥只在相同请求时重复使用\n });\n })\n .catch((error) => {\n console.error('Error fetching authorization:', error);\n callback(null);\n });\n },\n });\n this.cos = cos;\n }\n\n /**\n * 计算文件的 MD5 哈希值\n *\n * 性能优化:\n * - 小文件(< 10MB):一次性读取,速度更快\n * - 大文件:分片读取,避免内存溢出\n *\n * @param file - 要计算 MD5 的文件对象\n * @param chunkSize - 分片大小(字节),默认 2MB\n * @returns Promise<string> 文件的 MD5 哈希值\n *\n * @example\n * const md5 = await beLinkCOS.createFileMd5(file);\n * console.log('文件 MD5:', md5);\n */\n public createFileMd5(file: File, chunkSize: number = 2 * 1024 * 1024): Promise<string> {\n return new Promise((resolve, reject) => {\n // 对于小文件(< 10MB),使用简单方法\n if (file.size < 10 * 1024 * 1024) {\n const reader = new FileReader();\n\n reader.onload = (e: ProgressEvent<FileReader>) => {\n const arrayBuffer = e.target?.result as ArrayBuffer;\n if (arrayBuffer) {\n const wordArray = CryptoJS.lib.WordArray.create(arrayBuffer as any);\n const hash = CryptoJS.MD5(wordArray).toString();\n resolve(hash);\n } else {\n reject(new Error('Failed to read file'));\n }\n };\n\n reader.onerror = (error) => {\n reject(error);\n };\n\n reader.readAsArrayBuffer(file);\n return;\n }\n\n // 对于大文件,使用分片读取\n let currentChunk = 0;\n const chunks = Math.ceil(file.size / chunkSize);\n const spark = CryptoJS.algo.MD5.create();\n const reader = new FileReader();\n\n reader.onload = (e: ProgressEvent<FileReader>) => {\n const arrayBuffer = e.target?.result as ArrayBuffer;\n if (arrayBuffer) {\n const wordArray = CryptoJS.lib.WordArray.create(arrayBuffer as any);\n spark.update(wordArray);\n\n currentChunk++;\n\n if (currentChunk < chunks) {\n loadNext();\n } else {\n const hash = spark.finalize().toString();\n resolve(hash);\n }\n }\n };\n\n reader.onerror = (error) => {\n reject(error);\n };\n\n const loadNext = () => {\n const start = currentChunk * chunkSize;\n const end = Math.min(start + chunkSize, file.size);\n const blob = file.slice(start, end);\n reader.readAsArrayBuffer(blob);\n };\n\n loadNext();\n });\n }\n\n /**\n * 生成文件在 COS 中的存储路径\n *\n * 路径规则:/beLinkAllSource/static/{文件类型}/{文件名}_{时间戳}.{扩展名}\n * 例如:/beLinkAllSource/static/image/avatar_1699999999999.png\n *\n * @param file - 文件对象\n * @returns Promise<string> COS 存储路径\n */\n private async getFilePath(file: File): Promise<string> {\n const filename = file.name;\n const fileType = file?.type ? file.type.split('/')[0] : 'other';\n const fileExtension = filename.split('.').pop() || '';\n const filenameDateNow = `${filename.split('.')[0]}_${Date.now()}`;\n const newFileName = `${filenameDateNow}.${fileExtension}`;\n return `${this.basePath}${fileType}/${newFileName}`;\n }\n\n /**\n * 获取文件上传后的访问 URL(不执行实际上传)\n *\n * 用于在上传前预览文件的最终 URL\n *\n * @param file - 文件对象\n * @returns Promise<string> 文件的完整访问 URL\n *\n * @example\n * const url = await beLinkCOS.getSourceUrl(file);\n * console.log('文件将上传到:', url);\n */\n public async getSourceUrl(file: File): Promise<string> {\n const path = await this.getFilePath(file);\n return `https://${BUCKETS_CONFIG[this.mode].host}${path}`;\n }\n\n /**\n * 上传文件到腾讯云 COS\n *\n * 核心功能:将文件上传到对应环境的 COS 存储桶\n * 支持上传进度回调、自定义请求头等配置\n *\n * @param file - 要上传的文件对象\n * @param config - 上传配置(可选)\n * @param config.Headers - 自定义请求头\n * @param config.onProgressCallback - 上传进度回调函数\n * @returns Promise<UploadResult> 上传结果,包含文件 URL、ETag 等信息\n *\n * @example\n * const uploader = new BeLinkCOS({ mode: 'production' });\n * const result = await uploader.uploadFile(file, {\n * onProgressCallback: (progressData) => {\n * console.log('进度:', progressData.percent * 100 + '%');\n * }\n * });\n * console.log('文件 URL:', result.url);\n */\n public async uploadFile(file: File, config?: UploadConfig): Promise<UploadResult> {\n // 首次上传时自动初始化 COS SDK\n if (!this.cos) {\n await this.initCOS();\n }\n const key = await this.getFilePath(file);\n\n return new Promise((resolve, reject) => {\n this.cos?.putObject(\n {\n Bucket: BUCKETS_CONFIG[this.mode].name,\n Region: REGION,\n Key: key,\n Body: file,\n onProgress: config?.onProgressCallback,\n ...config,\n Headers: { ...this.headers, ...(config?.Headers || {}) },\n },\n (err: any, data: UploadResult) => {\n if (err) {\n reject(err);\n } else {\n const url = `https://${data.Location}`;\n resolve({ ...data, url });\n }\n },\n );\n });\n }\n}\n"],"names":[],"mappings":"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"}