@file-ud.js/core 0.1.0

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.
@@ -0,0 +1,1609 @@
1
+ 'use strict';
2
+
3
+ var SparkMD5 = require('spark-md5');
4
+
5
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
6
+
7
+ var SparkMD5__default = /*#__PURE__*/_interopDefault(SparkMD5);
8
+
9
+ var __defProp = Object.defineProperty;
10
+ var __getOwnPropNames = Object.getOwnPropertyNames;
11
+ var __esm = (fn, res) => function __init() {
12
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
13
+ };
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+
19
+ // src/utils/md5Worker.ts
20
+ var md5Worker_exports = {};
21
+ __export(md5Worker_exports, {
22
+ calculateFileMD5InWorker: () => calculateFileMD5InWorker,
23
+ disposeMD5Worker: () => disposeMD5Worker
24
+ });
25
+ function getWorkerBlobUrl() {
26
+ if (!_workerBlobUrl) {
27
+ const blob = new Blob([MD5_IMPL], { type: "text/javascript" });
28
+ _workerBlobUrl = URL.createObjectURL(blob);
29
+ }
30
+ return _workerBlobUrl;
31
+ }
32
+ async function calculateFileMD5InWorker(file, signal) {
33
+ const WORKER_TIMEOUT_MS = 6e4;
34
+ return new Promise((resolve, reject) => {
35
+ const reader = new FileReader();
36
+ const abortHandler = () => {
37
+ reader.abort();
38
+ reject(new Error("MD5 \u8BA1\u7B97\u5DF2\u53D6\u6D88"));
39
+ };
40
+ if (signal) {
41
+ signal.addEventListener("abort", abortHandler, { once: true });
42
+ }
43
+ reader.onload = () => {
44
+ if (signal) {
45
+ signal.removeEventListener("abort", abortHandler);
46
+ }
47
+ const fileBuffer = reader.result;
48
+ const workerUrl = getWorkerBlobUrl();
49
+ const worker = new Worker(workerUrl);
50
+ const timeout = setTimeout(() => {
51
+ worker.terminate();
52
+ reject(new Error("MD5 Worker \u8BA1\u7B97\u8D85\u65F6"));
53
+ }, WORKER_TIMEOUT_MS);
54
+ worker.onmessage = (e) => {
55
+ clearTimeout(timeout);
56
+ worker.terminate();
57
+ const { error, hash } = e.data;
58
+ if (error) {
59
+ reject(new Error(error));
60
+ } else {
61
+ resolve(hash);
62
+ }
63
+ };
64
+ worker.onerror = (err) => {
65
+ clearTimeout(timeout);
66
+ worker.terminate();
67
+ reject(new Error(err.message || "MD5 Worker \u5F02\u5E38"));
68
+ };
69
+ worker.postMessage({ fileBuffer }, [fileBuffer]);
70
+ };
71
+ reader.onerror = () => {
72
+ if (signal) {
73
+ signal.removeEventListener("abort", abortHandler);
74
+ }
75
+ reject(new Error("\u6587\u4EF6\u8BFB\u53D6\u5931\u8D25"));
76
+ };
77
+ reader.readAsArrayBuffer(file);
78
+ });
79
+ }
80
+ function disposeMD5Worker() {
81
+ if (_workerBlobUrl) {
82
+ URL.revokeObjectURL(_workerBlobUrl);
83
+ _workerBlobUrl = null;
84
+ }
85
+ }
86
+ var MD5_IMPL, _workerBlobUrl;
87
+ var init_md5Worker = __esm({
88
+ "src/utils/md5Worker.ts"() {
89
+ MD5_IMPL = `
90
+ function md5(data) {
91
+ function rotateLeft(v, n) { return (v << n) | (v >>> (32 - n)); }
92
+ function addUnsigned(x, y) { return ((x & 0x7fffffff) + (y & 0x7fffffff)) ^ (x & 0x80000000) ^ (y & 0x80000000); }
93
+
94
+ var F = function(x,y,z) { return (x & y) | ((~x) & z); };
95
+ var G = function(x,y,z) { return (x & z) | (y & (~z)); };
96
+ var H = function(x,y,z) { return x ^ y ^ z; };
97
+ var I = function(x,y,z) { return y ^ (x | (~z)); };
98
+
99
+ function transform(func, a, b, c, d, x, s, ac) {
100
+ a = addUnsigned(a, addUnsigned(addUnsigned(func(b, c, d), x), ac));
101
+ return addUnsigned(rotateLeft(a, s), b);
102
+ }
103
+
104
+ // Convert string/array to word array
105
+ var len = data.length;
106
+ var words = [];
107
+ for (var i = 0; i < len; i++) {
108
+ words[i >> 2] |= data[i] << ((i % 4) * 8);
109
+ }
110
+ words[len >> 2] |= 0x80 << ((len % 4) * 8);
111
+ words[(((len + 8) >>> 6) << 4) + 14] = len * 8;
112
+
113
+ var a = 0x67452301, b = 0xefcdab89, c = 0x98badcfe, d = 0x10325476;
114
+
115
+ for (var i = 0; i < words.length; i += 16) {
116
+ var oldA = a, oldB = b, oldC = c, oldD = d;
117
+ // Round 1
118
+ a = transform(F, a, b, c, d, words[i+0], 7, 0xd76aa478);
119
+ d = transform(F, d, a, b, c, words[i+1], 12, 0xe8c7b756);
120
+ c = transform(F, c, d, a, b, words[i+2], 17, 0x242070db);
121
+ b = transform(F, b, c, d, a, words[i+3], 22, 0xc1bdceee);
122
+ a = transform(F, a, b, c, d, words[i+4], 7, 0xf57c0faf);
123
+ d = transform(F, d, a, b, c, words[i+5], 12, 0x4787c62a);
124
+ c = transform(F, c, d, a, b, words[i+6], 17, 0xa8304613);
125
+ b = transform(F, b, c, d, a, words[i+7], 22, 0xfd469501);
126
+ a = transform(F, a, b, c, d, words[i+8], 7, 0x698098d8);
127
+ d = transform(F, d, a, b, c, words[i+9], 12, 0x8b44f7af);
128
+ c = transform(F, c, d, a, b, words[i+10],17, 0xffff5bb1);
129
+ b = transform(F, b, c, d, a, words[i+11],22, 0x895cd7be);
130
+ a = transform(F, a, b, c, d, words[i+12], 7, 0x6b901122);
131
+ d = transform(F, d, a, b, c, words[i+13],12, 0xfd987193);
132
+ c = transform(F, c, d, a, b, words[i+14],17, 0xa679438e);
133
+ b = transform(F, b, c, d, a, words[i+15],22, 0x49b40821);
134
+ // Round 2
135
+ a = transform(G, a, b, c, d, words[i+1], 5, 0xf61e2562);
136
+ d = transform(G, d, a, b, c, words[i+6], 9, 0xc040b340);
137
+ c = transform(G, c, d, a, b, words[i+11],14, 0x265e5a51);
138
+ b = transform(G, b, c, d, a, words[i+0], 20, 0xe9b6c7aa);
139
+ a = transform(G, a, b, c, d, words[i+5], 5, 0xd62f105d);
140
+ d = transform(G, d, a, b, c, words[i+10], 9, 0x02441453);
141
+ c = transform(G, c, d, a, b, words[i+15],14, 0xd8a1e681);
142
+ b = transform(G, b, c, d, a, words[i+4], 20, 0xe7d3fbc8);
143
+ a = transform(G, a, b, c, d, words[i+9], 5, 0x21e1cde6);
144
+ d = transform(G, d, a, b, c, words[i+14], 9, 0xc33707d6);
145
+ c = transform(G, c, d, a, b, words[i+3], 14, 0xf4d50d87);
146
+ b = transform(G, b, c, d, a, words[i+8], 20, 0x455a14ed);
147
+ a = transform(G, a, b, c, d, words[i+13], 5, 0xa9e3e905);
148
+ d = transform(G, d, a, b, c, words[i+2], 9, 0xfcefa3f8);
149
+ c = transform(G, c, d, a, b, words[i+7], 14, 0x676f02d9);
150
+ b = transform(G, b, c, d, a, words[i+12],20, 0x8d2a4c8a);
151
+ // Round 3
152
+ a = transform(H, a, b, c, d, words[i+5], 4, 0xfffa3942);
153
+ d = transform(H, d, a, b, c, words[i+8], 11, 0x8771f681);
154
+ c = transform(H, c, d, a, b, words[i+11],16, 0x6d9d6122);
155
+ b = transform(H, b, c, d, a, words[i+14],23, 0xfde5380c);
156
+ a = transform(H, a, b, c, d, words[i+1], 4, 0xa4beea44);
157
+ d = transform(H, d, a, b, c, words[i+4], 11, 0x4bdecfa9);
158
+ c = transform(H, c, d, a, b, words[i+7], 16, 0xf6bb4b60);
159
+ b = transform(H, b, c, d, a, words[i+10],23, 0xbebfbc70);
160
+ a = transform(H, a, b, c, d, words[i+13], 4, 0x289b7ec6);
161
+ d = transform(H, d, a, b, c, words[i+0], 11, 0xeaa127fa);
162
+ c = transform(H, c, d, a, b, words[i+3], 16, 0xd4ef3085);
163
+ b = transform(H, b, c, d, a, words[i+6], 23, 0x04881d05);
164
+ a = transform(H, a, b, c, d, words[i+9], 4, 0xd9d4d039);
165
+ d = transform(H, d, a, b, c, words[i+12],11, 0xe6db99e5);
166
+ c = transform(H, c, d, a, b, words[i+15],16, 0x1fa27cf8);
167
+ b = transform(H, b, c, d, a, words[i+2], 23, 0xc4ac5665);
168
+ // Round 4
169
+ a = transform(I, a, b, c, d, words[i+0], 6, 0xf4292244);
170
+ d = transform(I, d, a, b, c, words[i+7], 10, 0x432aff97);
171
+ c = transform(I, c, d, a, b, words[i+14],15, 0xab9423a7);
172
+ b = transform(I, b, c, d, a, words[i+5], 21, 0xfc93a039);
173
+ a = transform(I, a, b, c, d, words[i+12], 6, 0x655b59c3);
174
+ d = transform(I, d, a, b, c, words[i+3], 10, 0x8f0ccc92);
175
+ c = transform(I, c, d, a, b, words[i+10],15, 0xffeff47d);
176
+ b = transform(I, b, c, d, a, words[i+1], 21, 0x85845dd1);
177
+ a = transform(I, a, b, c, d, words[i+8], 6, 0x6fa87e4f);
178
+ d = transform(I, d, a, b, c, words[i+15],10, 0xfe2ce6e0);
179
+ c = transform(I, c, d, a, b, words[i+6], 15, 0xa3014314);
180
+ b = transform(I, b, c, d, a, words[i+13],21, 0x4e0811a1);
181
+ a = transform(I, a, b, c, d, words[i+4], 6, 0xf7537e82);
182
+ d = transform(I, d, a, b, c, words[i+11],10, 0xbd3af235);
183
+ c = transform(I, c, d, a, b, words[i+2], 15, 0x2ad7d2bb);
184
+ b = transform(I, b, c, d, a, words[i+9], 21, 0xeb86d391);
185
+ a = addUnsigned(a, oldA);
186
+ b = addUnsigned(b, oldB);
187
+ c = addUnsigned(c, oldC);
188
+ d = addUnsigned(d, oldD);
189
+ }
190
+
191
+ function toHex(v) {
192
+ var h = ''; for (var j = 0; j < 4; j++) h += ((v >> (j * 8)) & 0xff).toString(16).padStart(2, '0'); return h;
193
+ }
194
+ return toHex(a) + toHex(b) + toHex(c) + toHex(d);
195
+ }
196
+
197
+ self.onmessage = async function(e) {
198
+ try {
199
+ var fileBuffer = e.data.fileBuffer;
200
+ var hash = md5(new Uint8Array(fileBuffer));
201
+ self.postMessage({ error: null, hash: hash });
202
+ } catch (err) {
203
+ self.postMessage({ error: err.message, hash: null });
204
+ }
205
+ };
206
+ `;
207
+ _workerBlobUrl = null;
208
+ }
209
+ });
210
+
211
+ // src/utils/logger/index.ts
212
+ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
213
+ LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
214
+ LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
215
+ LogLevel2[LogLevel2["WARN"] = 2] = "WARN";
216
+ LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
217
+ return LogLevel2;
218
+ })(LogLevel || {});
219
+ var LEVEL_LABELS = {
220
+ [0 /* DEBUG */]: "DEBUG",
221
+ [1 /* INFO */]: "INFO",
222
+ [2 /* WARN */]: "WARN",
223
+ [3 /* ERROR */]: "ERROR"
224
+ };
225
+ var LEVEL_COLORS = {
226
+ [0 /* DEBUG */]: "\x1B[36m",
227
+ // 青色
228
+ [1 /* INFO */]: "\x1B[32m",
229
+ // 绿色
230
+ [2 /* WARN */]: "\x1B[33m",
231
+ // 黄色
232
+ [3 /* ERROR */]: "\x1B[31m"
233
+ // 红色
234
+ };
235
+ var RESET_COLOR = "\x1B[0m";
236
+ var DEFAULT_OPTIONS = {
237
+ enabled: false,
238
+ level: typeof process !== "undefined" && process.env?.NODE_ENV === "production" ? 2 /* WARN */ : 0 /* DEBUG */,
239
+ showTimestamp: true,
240
+ enableColors: typeof process !== "undefined" && process.env?.NODE_ENV !== "production"
241
+ };
242
+ var currentOptions = { ...DEFAULT_OPTIONS };
243
+ var logCollectors = [];
244
+ function getLogLevelFromEnv() {
245
+ if (typeof process === "undefined" || !process.env)
246
+ return void 0;
247
+ const envLevel = process.env.VITE_LOG_LEVEL || process.env.LOG_LEVEL;
248
+ if (!envLevel)
249
+ return void 0;
250
+ const levelMap = {
251
+ debug: 0 /* DEBUG */,
252
+ info: 1 /* INFO */,
253
+ warn: 2 /* WARN */,
254
+ error: 3 /* ERROR */
255
+ };
256
+ return levelMap[envLevel.toLowerCase()];
257
+ }
258
+ function initLogger(options) {
259
+ const envLevel = getLogLevelFromEnv();
260
+ currentOptions = {
261
+ ...DEFAULT_OPTIONS,
262
+ ...options || {},
263
+ // 环境变量优先级最高
264
+ ...envLevel !== void 0 ? { level: envLevel } : {}
265
+ };
266
+ console.log(`[Logger] Initialized with level: ${LEVEL_LABELS[currentOptions.level]}`);
267
+ }
268
+ function setLogLevel(level) {
269
+ currentOptions.level = level;
270
+ }
271
+ function addLogCollector(callback) {
272
+ logCollectors.push(callback);
273
+ return () => {
274
+ const index = logCollectors.indexOf(callback);
275
+ if (index > -1) {
276
+ logCollectors.splice(index, 1);
277
+ }
278
+ };
279
+ }
280
+ function clearLogCollectors() {
281
+ logCollectors.length = 0;
282
+ }
283
+ function formatMessage(level, module, message, args) {
284
+ const parts = [];
285
+ if (currentOptions.showTimestamp) {
286
+ const now = /* @__PURE__ */ new Date();
287
+ const year = now.getFullYear();
288
+ const month = String(now.getMonth() + 1).padStart(2, "0");
289
+ const day = String(now.getDate()).padStart(2, "0");
290
+ const hours = String(now.getHours()).padStart(2, "0");
291
+ const minutes = String(now.getMinutes()).padStart(2, "0");
292
+ const seconds = String(now.getSeconds()).padStart(2, "0");
293
+ const milliseconds = String(now.getMilliseconds()).padStart(3, "0");
294
+ const timeStr = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${milliseconds}`;
295
+ parts.push(`[${timeStr}]`);
296
+ }
297
+ const label = LEVEL_LABELS[level];
298
+ if (currentOptions.enableColors) {
299
+ parts.push(`${LEVEL_COLORS[level]}[${label}]${RESET_COLOR}`);
300
+ } else {
301
+ parts.push(`[${label}]`);
302
+ }
303
+ parts.push(`[${module}]`);
304
+ parts.push(message);
305
+ return parts.join(" ");
306
+ }
307
+ function extractStack(arg) {
308
+ if (arg instanceof Error) {
309
+ return arg.stack || arg.message;
310
+ }
311
+ return null;
312
+ }
313
+ function log(level, module, message, ...args) {
314
+ if (!currentOptions.enabled) {
315
+ return;
316
+ }
317
+ if (level < (currentOptions.level ?? 0 /* DEBUG */)) {
318
+ return;
319
+ }
320
+ const formattedMessage = formatMessage(level, module, message);
321
+ let stackInfo;
322
+ try {
323
+ const error = new Error();
324
+ const stackLines = error.stack?.split("\n") || [];
325
+ if (stackLines.length >= 3) {
326
+ stackInfo = stackLines[3].trim();
327
+ }
328
+ } catch (e) {
329
+ }
330
+ const outputArgs = stackInfo ? [...args, `
331
+ ${stackInfo}`] : args;
332
+ switch (level) {
333
+ case 0 /* DEBUG */:
334
+ console.debug(formattedMessage, ...outputArgs);
335
+ break;
336
+ case 1 /* INFO */:
337
+ console.info(formattedMessage, ...outputArgs);
338
+ break;
339
+ case 2 /* WARN */:
340
+ console.warn(formattedMessage, ...outputArgs);
341
+ break;
342
+ case 3 /* ERROR */:
343
+ console.error(formattedMessage, ...outputArgs);
344
+ break;
345
+ }
346
+ if (logCollectors.length > 0) {
347
+ const entry = {
348
+ timestamp: Date.now(),
349
+ level,
350
+ module,
351
+ message,
352
+ args
353
+ };
354
+ const stack = args.find(extractStack);
355
+ if (stack) {
356
+ entry.stack = extractStack(stack) || void 0;
357
+ }
358
+ logCollectors.forEach((collector) => {
359
+ try {
360
+ const result = collector(entry);
361
+ if (result instanceof Promise) {
362
+ result.catch((error) => {
363
+ console.error("[Logger] Collector error:", error);
364
+ });
365
+ }
366
+ } catch (error) {
367
+ console.error("[Logger] Collector error:", error);
368
+ }
369
+ });
370
+ }
371
+ }
372
+ var logger = {
373
+ /**
374
+ * 调试日志(仅开发环境)
375
+ * @param module 模块名称
376
+ * @param message 消息内容
377
+ * @param args 额外参数
378
+ */
379
+ debug: (module, message, ...args) => {
380
+ message = `\u{1F50D} ${message}`;
381
+ log(0 /* DEBUG */, module, message, ...args);
382
+ },
383
+ /**
384
+ * 信息日志
385
+ * @param module 模块名称
386
+ * @param message 消息内容
387
+ * @param args 额外参数
388
+ */
389
+ info: (module, message, ...args) => {
390
+ message = `\u2705 ${message}`;
391
+ log(1 /* INFO */, module, message, ...args);
392
+ },
393
+ /**
394
+ * 警告日志
395
+ * @param module 模块名称
396
+ * @param message 消息内容
397
+ * @param args 额外参数
398
+ */
399
+ warn: (module, message, ...args) => {
400
+ message = `\u26A0\uFE0F ${message}`;
401
+ log(2 /* WARN */, module, message, ...args);
402
+ },
403
+ /**
404
+ * 错误日志
405
+ * @param module 模块名称
406
+ * @param message 消息内容
407
+ * @param args 额外参数
408
+ */
409
+ error: (module, message, ...args) => {
410
+ message = `\u274C ${message}`;
411
+ log(3 /* ERROR */, module, message, ...args);
412
+ }
413
+ };
414
+
415
+ // src/utils/fileCache.ts
416
+ var DB_NAME = "file-ud-cache";
417
+ var DB_VERSION = 3;
418
+ var STORE_NAME = "files";
419
+ var DOWNLOAD_PROGRESS_STORE = "download-progress";
420
+ var FILE_HANDLE_STORE = "file-handles";
421
+ var dbInstance = null;
422
+ var dbOpeningPromise = null;
423
+ function openDB() {
424
+ if (dbInstance && dbInstance.version === DB_VERSION) {
425
+ try {
426
+ dbInstance.transaction([STORE_NAME], "readonly");
427
+ return Promise.resolve(dbInstance);
428
+ } catch (error) {
429
+ logger.warn("FileCache", "\u6570\u636E\u5E93\u8FDE\u63A5\u5DF2\u5931\u6548\uFF0C\u91CD\u65B0\u6253\u5F00", error);
430
+ dbInstance = null;
431
+ dbOpeningPromise = null;
432
+ }
433
+ }
434
+ if (dbOpeningPromise) {
435
+ return dbOpeningPromise;
436
+ }
437
+ dbOpeningPromise = new Promise((resolve, reject) => {
438
+ const request = indexedDB.open(DB_NAME, DB_VERSION);
439
+ request.onerror = () => {
440
+ logger.error("FileCache", "\u6253\u5F00 IndexedDB \u5931\u8D25", request.error);
441
+ dbOpeningPromise = null;
442
+ reject(request.error);
443
+ };
444
+ request.onsuccess = () => {
445
+ dbInstance = request.result;
446
+ dbOpeningPromise = null;
447
+ dbInstance.onclose = () => {
448
+ logger.warn("FileCache", "\u6570\u636E\u5E93\u8FDE\u63A5\u5DF2\u5173\u95ED");
449
+ dbInstance = null;
450
+ };
451
+ dbInstance.onerror = (event) => {
452
+ logger.error("FileCache", "\u6570\u636E\u5E93\u8FDE\u63A5\u9519\u8BEF", event);
453
+ dbInstance = null;
454
+ };
455
+ resolve(dbInstance);
456
+ };
457
+ request.onupgradeneeded = (event) => {
458
+ const db = event.target.result;
459
+ if (!db.objectStoreNames.contains(STORE_NAME)) {
460
+ const store = db.createObjectStore(STORE_NAME, { keyPath: "fileHash" });
461
+ store.createIndex("fileName", "fileName", { unique: false });
462
+ store.createIndex("createdAt", "createdAt", { unique: false });
463
+ store.createIndex("lastAccessedAt", "lastAccessedAt", { unique: false });
464
+ logger.info("FileCache", "IndexedDB \u6587\u4EF6\u7F13\u5B58\u5B58\u50A8\u521D\u59CB\u5316\u6210\u529F");
465
+ }
466
+ if (!db.objectStoreNames.contains(DOWNLOAD_PROGRESS_STORE)) {
467
+ const progressStore = db.createObjectStore(DOWNLOAD_PROGRESS_STORE, { keyPath: "fileHash" });
468
+ progressStore.createIndex("updatedAt", "updatedAt", { unique: false });
469
+ logger.info("FileCache", "IndexedDB \u4E0B\u8F7D\u8FDB\u5EA6\u5B58\u50A8\u521D\u59CB\u5316\u6210\u529F");
470
+ }
471
+ if (!db.objectStoreNames.contains(FILE_HANDLE_STORE)) {
472
+ const handleStore = db.createObjectStore(FILE_HANDLE_STORE, { keyPath: "fileName" });
473
+ handleStore.createIndex("updatedAt", "updatedAt", { unique: false });
474
+ logger.info("FileCache", "IndexedDB \u6587\u4EF6\u53E5\u67C4\u5B58\u50A8\u521D\u59CB\u5316\u6210\u529F");
475
+ }
476
+ };
477
+ });
478
+ return dbOpeningPromise;
479
+ }
480
+ function closeDB() {
481
+ if (dbInstance) {
482
+ try {
483
+ dbInstance.close();
484
+ logger.debug("FileCache", "\u6570\u636E\u5E93\u8FDE\u63A5\u5DF2\u5173\u95ED");
485
+ } catch (error) {
486
+ logger.warn("FileCache", "\u5173\u95ED\u6570\u636E\u5E93\u8FDE\u63A5\u65F6\u51FA\u9519", error);
487
+ } finally {
488
+ dbInstance = null;
489
+ dbOpeningPromise = null;
490
+ }
491
+ }
492
+ }
493
+ async function executeTransaction(operation) {
494
+ try {
495
+ const db = await openDB();
496
+ return await operation(db);
497
+ } catch (error) {
498
+ if (error instanceof DOMException && error.name === "InvalidStateError") {
499
+ logger.warn("FileCache", "\u68C0\u6D4B\u5230\u65E0\u6548\u72B6\u6001\u9519\u8BEF\uFF0C\u91CD\u7F6E\u8FDE\u63A5\u540E\u91CD\u8BD5", error);
500
+ closeDB();
501
+ const db = await openDB();
502
+ return await operation(db);
503
+ }
504
+ throw error;
505
+ }
506
+ }
507
+ async function saveFileToCache(fileHash, file) {
508
+ try {
509
+ const arrayBuffer = await file.arrayBuffer();
510
+ const record = {
511
+ fileHash,
512
+ fileName: file.name,
513
+ fileType: file.type,
514
+ fileSize: file.size,
515
+ data: arrayBuffer,
516
+ createdAt: Date.now(),
517
+ lastAccessedAt: Date.now()
518
+ };
519
+ await executeTransaction(async (db) => {
520
+ return new Promise((resolve, reject) => {
521
+ const transaction = db.transaction([STORE_NAME], "readwrite");
522
+ const store = transaction.objectStore(STORE_NAME);
523
+ const request = store.put(record);
524
+ request.onsuccess = () => {
525
+ logger.debug("FileCache", `\u6587\u4EF6\u5DF2\u7F13\u5B58: ${file.name} (${formatFileSize(file.size)})`, {
526
+ fileHash,
527
+ fileSize: file.size
528
+ });
529
+ resolve();
530
+ };
531
+ request.onerror = () => {
532
+ logger.error("FileCache", "\u4FDD\u5B58\u6587\u4EF6\u7F13\u5B58\u5931\u8D25", request.error);
533
+ reject(request.error);
534
+ };
535
+ transaction.onerror = () => {
536
+ logger.error("FileCache", "\u4E8B\u52A1\u6267\u884C\u5931\u8D25", transaction.error);
537
+ reject(transaction.error);
538
+ };
539
+ });
540
+ });
541
+ } catch (error) {
542
+ logger.error("FileCache", "\u4FDD\u5B58\u6587\u4EF6\u7F13\u5B58\u5F02\u5E38", error);
543
+ throw error;
544
+ }
545
+ }
546
+ async function restoreFileFromCache(fileHash) {
547
+ try {
548
+ return await executeTransaction(async (db) => {
549
+ return new Promise((resolve, reject) => {
550
+ const transaction = db.transaction([STORE_NAME], "readonly");
551
+ const store = transaction.objectStore(STORE_NAME);
552
+ const request = store.get(fileHash);
553
+ request.onsuccess = () => {
554
+ const record = request.result;
555
+ if (!record) {
556
+ logger.debug("FileCache", `\u672A\u627E\u5230\u7F13\u5B58\u6587\u4EF6: ${fileHash}`);
557
+ resolve(null);
558
+ return;
559
+ }
560
+ updateLastAccessedTime(fileHash);
561
+ const blob = new Blob([record.data], { type: record.fileType });
562
+ const file = new File([blob], record.fileName, { type: record.fileType });
563
+ logger.debug("FileCache", `\u6210\u529F\u6062\u590D\u7F13\u5B58\u6587\u4EF6: ${record.fileName}`, {
564
+ fileHash,
565
+ fileSize: record.fileSize
566
+ });
567
+ resolve(file);
568
+ };
569
+ request.onerror = () => {
570
+ logger.error("FileCache", "\u6062\u590D\u6587\u4EF6\u7F13\u5B58\u5931\u8D25", request.error);
571
+ reject(request.error);
572
+ };
573
+ transaction.onerror = () => {
574
+ logger.error("FileCache", "\u4E8B\u52A1\u6267\u884C\u5931\u8D25", transaction.error);
575
+ reject(transaction.error);
576
+ };
577
+ });
578
+ });
579
+ } catch (error) {
580
+ logger.error("FileCache", "\u6062\u590D\u6587\u4EF6\u7F13\u5B58\u5F02\u5E38", error);
581
+ throw error;
582
+ }
583
+ }
584
+ async function removeFileFromCache(fileHash) {
585
+ try {
586
+ await executeTransaction(async (db) => {
587
+ return new Promise((resolve, reject) => {
588
+ const transaction = db.transaction([STORE_NAME], "readwrite");
589
+ const store = transaction.objectStore(STORE_NAME);
590
+ const request = store.delete(fileHash);
591
+ request.onsuccess = () => {
592
+ logger.debug("FileCache", `\u5DF2\u5220\u9664\u6587\u4EF6\u7F13\u5B58: ${fileHash}`);
593
+ resolve();
594
+ };
595
+ request.onerror = () => {
596
+ logger.error("FileCache", "\u5220\u9664\u6587\u4EF6\u7F13\u5B58\u5931\u8D25", request.error);
597
+ reject(request.error);
598
+ };
599
+ transaction.onerror = () => {
600
+ logger.error("FileCache", "\u4E8B\u52A1\u6267\u884C\u5931\u8D25", transaction.error);
601
+ reject(transaction.error);
602
+ };
603
+ });
604
+ });
605
+ } catch (error) {
606
+ logger.error("FileCache", "\u5220\u9664\u6587\u4EF6\u7F13\u5B58\u5F02\u5E38", error);
607
+ throw error;
608
+ }
609
+ }
610
+ async function clearAllFileCache() {
611
+ try {
612
+ await executeTransaction(async (db) => {
613
+ return new Promise((resolve, reject) => {
614
+ const transaction = db.transaction([STORE_NAME], "readwrite");
615
+ const store = transaction.objectStore(STORE_NAME);
616
+ const request = store.clear();
617
+ request.onsuccess = () => {
618
+ logger.info("FileCache", "\u5DF2\u6E05\u7A7A\u6240\u6709\u6587\u4EF6\u7F13\u5B58");
619
+ resolve();
620
+ };
621
+ request.onerror = () => {
622
+ logger.error("FileCache", "\u6E05\u7A7A\u6587\u4EF6\u7F13\u5B58\u5931\u8D25", request.error);
623
+ reject(request.error);
624
+ };
625
+ transaction.onerror = () => {
626
+ logger.error("FileCache", "\u4E8B\u52A1\u6267\u884C\u5931\u8D25", transaction.error);
627
+ reject(transaction.error);
628
+ };
629
+ });
630
+ });
631
+ } catch (error) {
632
+ logger.error("FileCache", "\u6E05\u7A7A\u6587\u4EF6\u7F13\u5B58\u5F02\u5E38", error);
633
+ throw error;
634
+ }
635
+ }
636
+ async function getCacheStats() {
637
+ try {
638
+ return await executeTransaction(async (db) => {
639
+ return new Promise((resolve, reject) => {
640
+ const transaction = db.transaction([STORE_NAME], "readonly");
641
+ const store = transaction.objectStore(STORE_NAME);
642
+ const request = store.getAll();
643
+ request.onsuccess = () => {
644
+ const records = request.result || [];
645
+ const totalSize = records.reduce((sum, record) => sum + record.fileSize, 0);
646
+ resolve({
647
+ count: records.length,
648
+ totalSize
649
+ });
650
+ };
651
+ request.onerror = () => {
652
+ logger.error("FileCache", "\u83B7\u53D6\u7F13\u5B58\u7EDF\u8BA1\u5931\u8D25", request.error);
653
+ reject(request.error);
654
+ };
655
+ transaction.onerror = () => {
656
+ logger.error("FileCache", "\u4E8B\u52A1\u6267\u884C\u5931\u8D25", transaction.error);
657
+ reject(transaction.error);
658
+ };
659
+ });
660
+ });
661
+ } catch (error) {
662
+ logger.error("FileCache", "\u83B7\u53D6\u7F13\u5B58\u7EDF\u8BA1\u5F02\u5E38", error);
663
+ throw error;
664
+ }
665
+ }
666
+ async function cleanExpiredCache(days = 7) {
667
+ try {
668
+ const cutoffTime = Date.now() - days * 24 * 60 * 60 * 1e3;
669
+ return await executeTransaction(async (db) => {
670
+ return new Promise((resolve, reject) => {
671
+ const transaction = db.transaction([STORE_NAME], "readwrite");
672
+ const store = transaction.objectStore(STORE_NAME);
673
+ const index = store.index("lastAccessedAt");
674
+ const request = index.getAll();
675
+ request.onsuccess = () => {
676
+ const records = request.result || [];
677
+ const expiredRecords = records.filter(
678
+ (record) => record.lastAccessedAt < cutoffTime
679
+ );
680
+ let deletedCount = 0;
681
+ const deletePromises = expiredRecords.map((record) => {
682
+ return new Promise((resolveDelete, rejectDelete) => {
683
+ const deleteRequest = store.delete(record.fileHash);
684
+ deleteRequest.onsuccess = () => {
685
+ deletedCount++;
686
+ resolveDelete();
687
+ };
688
+ deleteRequest.onerror = () => {
689
+ logger.error("FileCache", `\u5220\u9664\u8FC7\u671F\u7F13\u5B58\u5931\u8D25: ${record.fileHash}`, deleteRequest.error);
690
+ resolveDelete();
691
+ };
692
+ });
693
+ });
694
+ Promise.all(deletePromises).then(() => {
695
+ if (deletedCount > 0) {
696
+ logger.info("FileCache", `\u5DF2\u6E05\u7406 ${deletedCount} \u4E2A\u8FC7\u671F\u7F13\u5B58`);
697
+ }
698
+ resolve(deletedCount);
699
+ });
700
+ };
701
+ request.onerror = () => {
702
+ logger.error("FileCache", "\u67E5\u8BE2\u8FC7\u671F\u7F13\u5B58\u5931\u8D25", request.error);
703
+ reject(request.error);
704
+ };
705
+ transaction.onerror = () => {
706
+ logger.error("FileCache", "\u4E8B\u52A1\u6267\u884C\u5931\u8D25", transaction.error);
707
+ reject(transaction.error);
708
+ };
709
+ });
710
+ });
711
+ } catch (error) {
712
+ logger.error("FileCache", "\u6E05\u7406\u8FC7\u671F\u7F13\u5B58\u5F02\u5E38", error);
713
+ throw error;
714
+ }
715
+ }
716
+ async function updateLastAccessedTime(fileHash) {
717
+ try {
718
+ await executeTransaction(async (db) => {
719
+ return new Promise((resolve, reject) => {
720
+ const transaction = db.transaction([STORE_NAME], "readwrite");
721
+ const store = transaction.objectStore(STORE_NAME);
722
+ const request = store.get(fileHash);
723
+ request.onsuccess = () => {
724
+ const record = request.result;
725
+ if (record) {
726
+ record.lastAccessedAt = Date.now();
727
+ const updateRequest = store.put(record);
728
+ updateRequest.onsuccess = () => resolve();
729
+ updateRequest.onerror = () => {
730
+ logger.warn("FileCache", "\u66F4\u65B0\u8BBF\u95EE\u65F6\u95F4\u5931\u8D25", updateRequest.error);
731
+ resolve();
732
+ };
733
+ } else {
734
+ resolve();
735
+ }
736
+ };
737
+ request.onerror = () => {
738
+ logger.warn("FileCache", "\u67E5\u8BE2\u8BB0\u5F55\u5931\u8D25", request.error);
739
+ resolve();
740
+ };
741
+ transaction.onerror = () => {
742
+ logger.warn("FileCache", "\u4E8B\u52A1\u6267\u884C\u5931\u8D25", transaction.error);
743
+ resolve();
744
+ };
745
+ });
746
+ });
747
+ } catch (error) {
748
+ logger.warn("FileCache", "\u66F4\u65B0\u8BBF\u95EE\u65F6\u95F4\u5F02\u5E38", error);
749
+ }
750
+ }
751
+ async function saveFileHandle(fileName, fileHandle) {
752
+ try {
753
+ const record = {
754
+ fileName,
755
+ fileHandle,
756
+ updatedAt: Date.now()
757
+ };
758
+ await executeTransaction(async (db) => {
759
+ return new Promise((resolve, reject) => {
760
+ const transaction = db.transaction([FILE_HANDLE_STORE], "readwrite");
761
+ const store = transaction.objectStore(FILE_HANDLE_STORE);
762
+ const request = store.put(record);
763
+ request.onsuccess = () => {
764
+ logger.debug("FileCache", `\u6587\u4EF6\u53E5\u67C4\u5DF2\u6301\u4E45\u5316: ${fileName}`);
765
+ resolve();
766
+ };
767
+ request.onerror = () => {
768
+ logger.warn("FileCache", "\u4FDD\u5B58\u6587\u4EF6\u53E5\u67C4\u5931\u8D25", request.error);
769
+ reject(request.error);
770
+ };
771
+ transaction.onerror = () => {
772
+ logger.warn("FileCache", "\u4E8B\u52A1\u6267\u884C\u5931\u8D25", transaction.error);
773
+ reject(transaction.error);
774
+ };
775
+ });
776
+ });
777
+ } catch (error) {
778
+ logger.warn("FileCache", "\u4FDD\u5B58\u6587\u4EF6\u53E5\u67C4\u5F02\u5E38", error);
779
+ }
780
+ }
781
+ async function loadFileHandle(fileName) {
782
+ try {
783
+ return await executeTransaction(async (db) => {
784
+ return new Promise((resolve, reject) => {
785
+ const transaction = db.transaction([FILE_HANDLE_STORE], "readonly");
786
+ const store = transaction.objectStore(FILE_HANDLE_STORE);
787
+ const request = store.get(fileName);
788
+ request.onsuccess = () => {
789
+ const record = request.result;
790
+ if (!record) {
791
+ logger.debug("FileCache", `\u672A\u627E\u5230\u6301\u4E45\u5316\u6587\u4EF6\u53E5\u67C4: ${fileName}`);
792
+ resolve(null);
793
+ return;
794
+ }
795
+ try {
796
+ record.fileHandle.getFile().then(
797
+ () => {
798
+ logger.debug("FileCache", `\u6587\u4EF6\u53E5\u67C4\u6709\u6548: ${fileName}`);
799
+ resolve(record.fileHandle);
800
+ },
801
+ () => {
802
+ logger.warn("FileCache", `\u6587\u4EF6\u53E5\u67C4\u5DF2\u5931\u6548\uFF08\u6743\u9650\u64A4\u9500\uFF09: ${fileName}`);
803
+ removeFileHandle(fileName);
804
+ resolve(null);
805
+ }
806
+ );
807
+ } catch {
808
+ removeFileHandle(fileName);
809
+ resolve(null);
810
+ }
811
+ };
812
+ request.onerror = () => {
813
+ logger.warn("FileCache", "\u52A0\u8F7D\u6587\u4EF6\u53E5\u67C4\u5931\u8D25", request.error);
814
+ reject(request.error);
815
+ };
816
+ transaction.onerror = () => {
817
+ logger.warn("FileCache", "\u4E8B\u52A1\u6267\u884C\u5931\u8D25", transaction.error);
818
+ reject(transaction.error);
819
+ };
820
+ });
821
+ });
822
+ } catch (error) {
823
+ logger.warn("FileCache", "\u52A0\u8F7D\u6587\u4EF6\u53E5\u67C4\u5F02\u5E38", error);
824
+ return null;
825
+ }
826
+ }
827
+ async function removeFileHandle(fileName) {
828
+ try {
829
+ await executeTransaction(async (db) => {
830
+ return new Promise((resolve, reject) => {
831
+ const transaction = db.transaction([FILE_HANDLE_STORE], "readwrite");
832
+ const store = transaction.objectStore(FILE_HANDLE_STORE);
833
+ const request = store.delete(fileName);
834
+ request.onsuccess = () => {
835
+ logger.debug("FileCache", `\u5DF2\u5220\u9664\u6587\u4EF6\u53E5\u67C4: ${fileName}`);
836
+ resolve();
837
+ };
838
+ request.onerror = () => {
839
+ logger.warn("FileCache", "\u5220\u9664\u6587\u4EF6\u53E5\u67C4\u5931\u8D25", request.error);
840
+ reject(request.error);
841
+ };
842
+ transaction.onerror = () => {
843
+ logger.warn("FileCache", "\u4E8B\u52A1\u6267\u884C\u5931\u8D25", transaction.error);
844
+ reject(transaction.error);
845
+ };
846
+ });
847
+ });
848
+ } catch (error) {
849
+ logger.warn("FileCache", "\u5220\u9664\u6587\u4EF6\u53E5\u67C4\u5F02\u5E38", error);
850
+ }
851
+ }
852
+
853
+ // src/utils/upload-monitor/index.ts
854
+ var UploadMonitor = class {
855
+ constructor() {
856
+ /** 上传记录列表 */
857
+ this.records = [];
858
+ /** 当前活跃的上传任务 */
859
+ this.activeUploads = /* @__PURE__ */ new Map();
860
+ /** 最大保留记录数 */
861
+ this.MAX_RECORDS = 1e3;
862
+ this.init();
863
+ }
864
+ /**
865
+ * 初始化日志收集器
866
+ */
867
+ init() {
868
+ addLogCollector((entry) => {
869
+ this.processLog(entry);
870
+ });
871
+ }
872
+ /**
873
+ * 处理日志条目
874
+ */
875
+ processLog(entry) {
876
+ if (entry.message.includes("\u4E0A\u4F20") || entry.message.includes("\u6587\u4EF6")) {
877
+ console.log("[Monitor Debug] \u6536\u5230\u65E5\u5FD7:", {
878
+ module: entry.module,
879
+ message: entry.message,
880
+ args: entry.args,
881
+ timestamp: entry.timestamp
882
+ });
883
+ }
884
+ if (entry.message.includes("\u5F00\u59CB\u4E0A\u4F20\u6587\u4EF6") && !entry.message.includes("\u5206\u7247")) {
885
+ const fileId = this.extractFileId(entry);
886
+ console.log("[Monitor Debug] \u5339\u914D\u5230\u5F00\u59CB\u4E0A\u4F20:", { fileId, hasFileId: !!fileId });
887
+ if (fileId && !this.activeUploads.has(fileId)) {
888
+ const record = {
889
+ fileId,
890
+ fileName: this.extractFileName(entry) || "unknown",
891
+ fileSize: this.extractFileSize(entry) || 0,
892
+ startTime: entry.timestamp,
893
+ success: false,
894
+ retryCount: 0
895
+ };
896
+ this.activeUploads.set(fileId, record);
897
+ }
898
+ }
899
+ if (entry.message.includes("\u6587\u4EF6\u4F20\u8F93\u6210\u529F")) {
900
+ const fileId = this.extractFileId(entry);
901
+ console.log("[Monitor Debug] \u5339\u914D\u5230\u4E0A\u4F20\u6210\u529F:", { fileId, hasFileId: !!fileId });
902
+ if (fileId) {
903
+ if (!this.activeUploads.has(fileId)) {
904
+ const record2 = {
905
+ fileId,
906
+ fileName: this.extractFileName(entry) || "unknown",
907
+ fileSize: this.extractFileSize(entry) || 0,
908
+ startTime: 0,
909
+ // ✅ 标记为未知,避免错误的耗时计算
910
+ endTime: entry.timestamp,
911
+ success: true,
912
+ retryCount: 0
913
+ };
914
+ this.finalizeRecord(record2);
915
+ return;
916
+ }
917
+ const record = this.activeUploads.get(fileId);
918
+ record.endTime = entry.timestamp;
919
+ record.success = true;
920
+ if (record.fileSize === 0) {
921
+ const extractedSize = this.extractFileSize(entry);
922
+ if (extractedSize) {
923
+ record.fileSize = extractedSize;
924
+ }
925
+ }
926
+ this.finalizeRecord(record);
927
+ this.activeUploads.delete(fileId);
928
+ }
929
+ }
930
+ if (entry.level === 3 /* ERROR */) {
931
+ const fileId = this.extractFileId(entry);
932
+ if (entry.module === "uploadChunkManager") {
933
+ if (fileId && this.activeUploads.has(fileId)) {
934
+ const record = this.activeUploads.get(fileId);
935
+ if (!record.errorModules) {
936
+ record.errorModules = /* @__PURE__ */ new Map();
937
+ }
938
+ record.errorModules.set("uploadChunkManager", (record.errorModules.get("uploadChunkManager") || 0) + 1);
939
+ if (entry.message.includes("\u5206\u7247") && entry.message.includes("\u5931\u8D25")) {
940
+ record.failedChunks = (record.failedChunks || 0) + 1;
941
+ }
942
+ if (entry.message.includes("\u6700\u7EC8\u5931\u8D25")) {
943
+ record.endTime = entry.timestamp;
944
+ record.success = false;
945
+ record.error = entry.message;
946
+ if (record.fileSize === 0) {
947
+ const extractedSize = this.extractFileSize(entry);
948
+ if (extractedSize) {
949
+ record.fileSize = extractedSize;
950
+ }
951
+ }
952
+ this.finalizeRecord(record);
953
+ this.activeUploads.delete(fileId);
954
+ }
955
+ }
956
+ }
957
+ if (entry.module === "UploadFile") {
958
+ if (fileId && this.activeUploads.has(fileId)) {
959
+ const record = this.activeUploads.get(fileId);
960
+ if (!record.errorModules) {
961
+ record.errorModules = /* @__PURE__ */ new Map();
962
+ }
963
+ record.errorModules.set("UploadFile", (record.errorModules.get("UploadFile") || 0) + 1);
964
+ record.endTime = entry.timestamp;
965
+ record.success = false;
966
+ record.error = entry.message;
967
+ if (record.fileSize === 0) {
968
+ const extractedSize = this.extractFileSize(entry);
969
+ if (extractedSize) {
970
+ record.fileSize = extractedSize;
971
+ }
972
+ }
973
+ this.finalizeRecord(record);
974
+ this.activeUploads.delete(fileId);
975
+ }
976
+ }
977
+ }
978
+ if (entry.message.includes("\u91CD\u8BD5")) {
979
+ const fileId = this.extractFileId(entry);
980
+ if (fileId && this.activeUploads.has(fileId)) {
981
+ const record = this.activeUploads.get(fileId);
982
+ record.retryCount++;
983
+ }
984
+ }
985
+ if (entry.module === "uploadChunkManager" && entry.message.includes("\u5206\u7247\u5207\u5272\u5B8C\u6210")) {
986
+ const fileId = this.extractFileId(entry);
987
+ if (fileId && this.activeUploads.has(fileId)) {
988
+ const record = this.activeUploads.get(fileId);
989
+ const totalChunks = this.extractTotalChunks(entry);
990
+ if (totalChunks) {
991
+ record.totalChunks = totalChunks;
992
+ record.chunks = 0;
993
+ record.failedChunks = 0;
994
+ }
995
+ }
996
+ }
997
+ }
998
+ /**
999
+ * 完成记录并添加到历史
1000
+ */
1001
+ finalizeRecord(record) {
1002
+ if (record.totalChunks) {
1003
+ record.chunks = record.totalChunks - (record.failedChunks || 0);
1004
+ }
1005
+ const existingIndex = this.records.findIndex((r) => r.fileId === record.fileId);
1006
+ if (existingIndex !== -1) {
1007
+ this.records[existingIndex] = record;
1008
+ } else {
1009
+ this.records.push(record);
1010
+ }
1011
+ if (this.records.length > this.MAX_RECORDS) {
1012
+ this.records.shift();
1013
+ }
1014
+ }
1015
+ /**
1016
+ * 从日志条目中提取 fileId
1017
+ */
1018
+ extractFileId(entry) {
1019
+ if (entry.args?.length) {
1020
+ for (const arg of entry.args) {
1021
+ if (arg && typeof arg === "object" && "fileId" in arg) {
1022
+ return String(arg.fileId);
1023
+ }
1024
+ }
1025
+ }
1026
+ const match = entry.message.match(/fileId[=:]\s*(\w+)/);
1027
+ if (match) {
1028
+ return match[1];
1029
+ }
1030
+ return null;
1031
+ }
1032
+ /**
1033
+ * 从日志条目中提取文件名
1034
+ */
1035
+ extractFileName(entry) {
1036
+ if (entry.args?.length) {
1037
+ for (const arg of entry.args) {
1038
+ if (typeof arg === "string") {
1039
+ return arg;
1040
+ }
1041
+ }
1042
+ }
1043
+ return null;
1044
+ }
1045
+ /**
1046
+ * 从日志条目中提取文件大小
1047
+ */
1048
+ extractFileSize(entry) {
1049
+ if (entry.args?.length) {
1050
+ for (const arg of entry.args) {
1051
+ if (arg && typeof arg === "object" && "size" in arg && typeof arg.size === "number") {
1052
+ return arg.size;
1053
+ }
1054
+ if (arg && typeof arg === "object" && "fileSize" in arg && typeof arg.fileSize === "number") {
1055
+ return arg.fileSize;
1056
+ }
1057
+ }
1058
+ }
1059
+ return null;
1060
+ }
1061
+ /**
1062
+ * 从日志条目中提取分片总数
1063
+ */
1064
+ extractTotalChunks(entry) {
1065
+ if (entry.args?.length) {
1066
+ for (const arg of entry.args) {
1067
+ if (arg && typeof arg === "object" && "totalChunks" in arg && typeof arg.totalChunks === "number") {
1068
+ return arg.totalChunks;
1069
+ }
1070
+ }
1071
+ }
1072
+ const match = entry.message.match(/(\d+)\s*\/\s*\d+/);
1073
+ if (match) {
1074
+ return parseInt(match[1], 10);
1075
+ }
1076
+ return null;
1077
+ }
1078
+ /**
1079
+ * 获取上传统计数据
1080
+ */
1081
+ getStats() {
1082
+ const completedRecords = this.records.filter((r) => r.endTime);
1083
+ if (completedRecords.length === 0) {
1084
+ return {
1085
+ totalUploads: 0,
1086
+ successfulUploads: 0,
1087
+ failedUploads: 0,
1088
+ successRate: 0,
1089
+ averageDuration: 0,
1090
+ minDuration: 0,
1091
+ maxDuration: 0,
1092
+ medianDuration: 0,
1093
+ averageFileSize: 0,
1094
+ totalBytesUploaded: 0,
1095
+ averageSpeed: 0,
1096
+ errorsByType: /* @__PURE__ */ new Map(),
1097
+ errorsByModule: /* @__PURE__ */ new Map(),
1098
+ averageRetries: 0
1099
+ };
1100
+ }
1101
+ const successful = completedRecords.filter((r) => r.success);
1102
+ const failed = completedRecords.filter((r) => !r.success);
1103
+ const durations = completedRecords.filter((r) => r.startTime > 0 && r.endTime).map((r) => r.endTime - r.startTime).filter((d) => d > 0);
1104
+ const averageDuration = durations.length > 0 ? Math.round(durations.reduce((a, b) => a + b, 0) / durations.length) : 0;
1105
+ const minDuration = durations.length > 0 ? Math.min(...durations) : 0;
1106
+ const maxDuration = durations.length > 0 ? Math.max(...durations) : 0;
1107
+ const sortedDurations = [...durations].sort((a, b) => a - b);
1108
+ const medianDuration = sortedDurations.length > 0 ? sortedDurations[Math.floor(sortedDurations.length / 2)] : 0;
1109
+ const fileSizes = completedRecords.map((r) => r.fileSize).filter((s) => s > 0);
1110
+ const averageFileSize = fileSizes.length > 0 ? Math.round(fileSizes.reduce((a, b) => a + b, 0) / fileSizes.length) : 0;
1111
+ const totalBytesUploaded = successful.reduce((sum, r) => sum + r.fileSize, 0);
1112
+ const totalDuration = durations.reduce((a, b) => a + b, 0);
1113
+ const averageSpeed = totalDuration > 0 ? Math.round(totalBytesUploaded / (totalDuration / 1e3)) : 0;
1114
+ const errorsByType = /* @__PURE__ */ new Map();
1115
+ const errorsByModule = /* @__PURE__ */ new Map();
1116
+ failed.forEach((record) => {
1117
+ if (record.error) {
1118
+ const errorType = this.classifyError(record.error);
1119
+ errorsByType.set(errorType, (errorsByType.get(errorType) || 0) + 1);
1120
+ }
1121
+ if (record.errorModules) {
1122
+ record.errorModules.forEach((count, module) => {
1123
+ errorsByModule.set(module, (errorsByModule.get(module) || 0) + count);
1124
+ });
1125
+ }
1126
+ });
1127
+ const totalRetries = completedRecords.reduce((sum, r) => sum + r.retryCount, 0);
1128
+ const averageRetries = completedRecords.length > 0 ? Math.round(totalRetries / completedRecords.length * 100) / 100 : 0;
1129
+ const chunkRecords = completedRecords.filter((r) => r.totalChunks);
1130
+ let chunkUploadStats;
1131
+ if (chunkRecords.length > 0) {
1132
+ const totalChunks = chunkRecords.reduce((sum, r) => sum + (r.totalChunks || 0), 0);
1133
+ const successfulChunks = chunkRecords.reduce((sum, r) => sum + (r.chunks || 0), 0);
1134
+ const failedChunks = chunkRecords.reduce((sum, r) => sum + (r.failedChunks || 0), 0);
1135
+ chunkUploadStats = {
1136
+ totalChunks,
1137
+ successfulChunks,
1138
+ failedChunks,
1139
+ chunkSuccessRate: totalChunks > 0 ? Math.round(successfulChunks / totalChunks * 1e4) / 100 : 0
1140
+ };
1141
+ }
1142
+ return {
1143
+ totalUploads: completedRecords.length,
1144
+ successfulUploads: successful.length,
1145
+ failedUploads: failed.length,
1146
+ successRate: Math.round(successful.length / completedRecords.length * 1e4) / 100,
1147
+ averageDuration,
1148
+ minDuration,
1149
+ maxDuration,
1150
+ medianDuration,
1151
+ averageFileSize,
1152
+ totalBytesUploaded,
1153
+ averageSpeed,
1154
+ errorsByType,
1155
+ errorsByModule,
1156
+ averageRetries,
1157
+ chunkUploadStats
1158
+ };
1159
+ }
1160
+ /**
1161
+ * 分类错误类型
1162
+ */
1163
+ classifyError(errorMessage) {
1164
+ if (errorMessage.includes("\u7F51\u7EDC") || errorMessage.includes("timeout")) {
1165
+ return "NETWORK_ERROR";
1166
+ }
1167
+ if (errorMessage.includes("\u670D\u52A1\u5668") || errorMessage.includes("500")) {
1168
+ return "SERVER_ERROR";
1169
+ }
1170
+ if (errorMessage.includes("\u672A\u6388\u6743") || errorMessage.includes("401")) {
1171
+ return "AUTH_ERROR";
1172
+ }
1173
+ if (errorMessage.includes("\u5206\u7247")) {
1174
+ return "CHUNK_ERROR";
1175
+ }
1176
+ if (errorMessage.includes("\u5408\u5E76")) {
1177
+ return "MERGE_ERROR";
1178
+ }
1179
+ return "UNKNOWN_ERROR";
1180
+ }
1181
+ /**
1182
+ * 获取最近 N 条上传记录
1183
+ */
1184
+ getRecentRecords(count = 10) {
1185
+ return this.records.slice(-count).reverse();
1186
+ }
1187
+ /**
1188
+ * 获取活跃上传任务
1189
+ */
1190
+ getActiveUploads() {
1191
+ return new Map(this.activeUploads);
1192
+ }
1193
+ /**
1194
+ * 重置所有统计数据
1195
+ */
1196
+ reset() {
1197
+ this.records = [];
1198
+ this.activeUploads.clear();
1199
+ }
1200
+ /**
1201
+ * 导出统计数据为 JSON
1202
+ */
1203
+ exportToJSON() {
1204
+ const stats = this.getStats();
1205
+ const serializableStats = {
1206
+ ...stats,
1207
+ errorsByType: Object.fromEntries(stats.errorsByType),
1208
+ errorsByModule: Object.fromEntries(stats.errorsByModule),
1209
+ exportedAt: (/* @__PURE__ */ new Date()).toISOString()
1210
+ };
1211
+ return JSON.stringify(serializableStats, null, 2);
1212
+ }
1213
+ /**
1214
+ * 打印统计报告到控制台
1215
+ */
1216
+ printReport() {
1217
+ const stats = this.getStats();
1218
+ console.group("\u{1F4CA} \u4E0A\u4F20\u6027\u80FD\u76D1\u63A7\u62A5\u544A");
1219
+ console.log("\u603B\u4E0A\u4F20\u6570:", stats.totalUploads);
1220
+ console.log("\u6210\u529F\u4E0A\u4F20:", stats.successfulUploads);
1221
+ console.log("\u5931\u8D25\u4E0A\u4F20:", stats.failedUploads);
1222
+ console.log("\u6210\u529F\u7387:", `${stats.successRate}%`);
1223
+ console.log("\u5E73\u5747\u8017\u65F6:", `${stats.averageDuration}ms`);
1224
+ console.log("\u6700\u77ED\u8017\u65F6:", `${stats.minDuration}ms`);
1225
+ console.log("\u6700\u957F\u8017\u65F6:", `${stats.maxDuration}ms`);
1226
+ console.log("\u4E2D\u4F4D\u6570\u8017\u65F6:", `${stats.medianDuration}ms`);
1227
+ console.log("\u5E73\u5747\u6587\u4EF6\u5927\u5C0F:", `${stats.averageFileSize} bytes`);
1228
+ console.log("\u603B\u4E0A\u4F20\u6570\u636E\u91CF:", `${stats.totalBytesUploaded} bytes`);
1229
+ console.log("\u5E73\u5747\u4E0A\u4F20\u901F\u5EA6:", `${stats.averageSpeed} bytes/s`);
1230
+ console.log("\u5E73\u5747\u91CD\u8BD5\u6B21\u6570:", stats.averageRetries);
1231
+ if (stats.chunkUploadStats) {
1232
+ console.group("\u5206\u7247\u4E0A\u4F20\u7EDF\u8BA1");
1233
+ console.log("\u603B\u5206\u7247\u6570:", stats.chunkUploadStats.totalChunks);
1234
+ console.log("\u6210\u529F\u5206\u7247:", stats.chunkUploadStats.successfulChunks);
1235
+ console.log("\u5931\u8D25\u5206\u7247:", stats.chunkUploadStats.failedChunks);
1236
+ console.log("\u5206\u7247\u6210\u529F\u7387:", `${stats.chunkUploadStats.chunkSuccessRate}%`);
1237
+ console.groupEnd();
1238
+ }
1239
+ if (stats.errorsByType.size > 0) {
1240
+ console.group("\u9519\u8BEF\u7C7B\u578B\u5206\u5E03");
1241
+ stats.errorsByType.forEach((count, type) => {
1242
+ console.log(`${type}:`, count);
1243
+ });
1244
+ console.groupEnd();
1245
+ }
1246
+ if (stats.errorsByModule.size > 0) {
1247
+ console.group("\u9519\u8BEF\u6A21\u5757\u5206\u5E03");
1248
+ stats.errorsByModule.forEach((count, module) => {
1249
+ console.log(`${module}:`, count);
1250
+ });
1251
+ console.groupEnd();
1252
+ }
1253
+ console.groupEnd();
1254
+ }
1255
+ };
1256
+ var uploadMonitor = new UploadMonitor();
1257
+
1258
+ // src/utils/network.ts
1259
+ function checkNetworkStatus() {
1260
+ const result = {
1261
+ online: navigator.onLine,
1262
+ timestamp: Date.now()
1263
+ };
1264
+ if (!result.online) {
1265
+ result.error = "\u7F51\u7EDC\u8FDE\u63A5\u5DF2\u65AD\u5F00\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u8BBE\u7F6E\u540E\u91CD\u8BD5";
1266
+ }
1267
+ return result;
1268
+ }
1269
+ async function checkNetworkConnectivity(testUrl, timeout = 5e3) {
1270
+ const basicCheck = checkNetworkStatus();
1271
+ if (!basicCheck.online) {
1272
+ return basicCheck;
1273
+ }
1274
+ const url = testUrl || window.location.origin;
1275
+ try {
1276
+ const controller = new AbortController();
1277
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
1278
+ await fetch(url, {
1279
+ method: "HEAD",
1280
+ signal: controller.signal,
1281
+ cache: "no-cache"
1282
+ });
1283
+ clearTimeout(timeoutId);
1284
+ return {
1285
+ online: true,
1286
+ timestamp: Date.now()
1287
+ };
1288
+ } catch (error) {
1289
+ return {
1290
+ online: false,
1291
+ timestamp: Date.now(),
1292
+ error: error instanceof Error ? error.message : "\u7F51\u7EDC\u8FDE\u63A5\u6D4B\u8BD5\u5931\u8D25"
1293
+ };
1294
+ }
1295
+ }
1296
+ function watchNetworkStatus(callback) {
1297
+ const handleOnline = () => callback(true);
1298
+ const handleOffline = () => callback(false);
1299
+ window.addEventListener("online", handleOnline);
1300
+ window.addEventListener("offline", handleOffline);
1301
+ return () => {
1302
+ window.removeEventListener("online", handleOnline);
1303
+ window.removeEventListener("offline", handleOffline);
1304
+ };
1305
+ }
1306
+
1307
+ // src/utils/index.ts
1308
+ init_md5Worker();
1309
+ function generateFileId() {
1310
+ const timestamp = Date.now().toString(36);
1311
+ const random = Math.random().toString(36).substring(2, 10);
1312
+ return `file_${timestamp}_${random}`;
1313
+ }
1314
+ function mergeObjects(target, source) {
1315
+ if (!target || typeof target !== "object" || Array.isArray(target)) {
1316
+ throw new TypeError("Target must be a valid object");
1317
+ }
1318
+ if (source && (typeof source !== "object" || Array.isArray(source))) {
1319
+ throw new TypeError("Source must be an object, undefined, or null");
1320
+ }
1321
+ if (!source) {
1322
+ return { ...target };
1323
+ }
1324
+ return { ...target, ...source };
1325
+ }
1326
+ function handleFile(file) {
1327
+ return new Promise((resolve, reject) => {
1328
+ if (file.size > 10 * 1024 * 1024) {
1329
+ try {
1330
+ resolve(URL.createObjectURL(file));
1331
+ } catch (error) {
1332
+ reject(new Error(`\u521B\u5EFAObject URL\u5931\u8D25: ${error.message}`));
1333
+ }
1334
+ } else {
1335
+ const reader = new FileReader();
1336
+ reader.onload = (e) => {
1337
+ resolve(e.target?.result);
1338
+ };
1339
+ reader.onerror = () => {
1340
+ reject(new Error("\u6587\u4EF6\u8BFB\u53D6\u9519\u8BEF"));
1341
+ };
1342
+ reader.onabort = () => {
1343
+ reject(new Error("\u6587\u4EF6\u8BFB\u53D6\u88AB\u4E2D\u6B62"));
1344
+ };
1345
+ reader.readAsDataURL(file);
1346
+ }
1347
+ });
1348
+ }
1349
+ function computeTransferTime(transferTime) {
1350
+ return {
1351
+ start() {
1352
+ const now = Date.now();
1353
+ transferTime.startTime = now;
1354
+ transferTime.endTime = 0;
1355
+ transferTime.duration = 0;
1356
+ transferTime.durationFormatted = "0s";
1357
+ },
1358
+ end() {
1359
+ const endTime = Date.now();
1360
+ const duration = endTime - transferTime.startTime;
1361
+ transferTime.endTime = endTime;
1362
+ transferTime.duration = duration;
1363
+ transferTime.durationFormatted = formatDuration(duration);
1364
+ }
1365
+ };
1366
+ }
1367
+ function getFileExtension(filename) {
1368
+ const parts = filename && filename?.split(".");
1369
+ return parts && parts.length > 1 ? parts[parts.length - 1] : "";
1370
+ }
1371
+ function isFileActive(file) {
1372
+ return ["UDLoading", "paused", "fail", "merging"].includes(file.status);
1373
+ }
1374
+ function formatFileSize(bytes, decimals = 2) {
1375
+ if (bytes === null || bytes === void 0 || isNaN(Number(bytes))) {
1376
+ return "0 B";
1377
+ }
1378
+ bytes = Number(bytes);
1379
+ if (isNaN(bytes))
1380
+ return "0 B";
1381
+ if (bytes === 0)
1382
+ return "0 B";
1383
+ if (bytes < 0) {
1384
+ console.warn("formatFileSize: \u63A5\u6536\u5230\u8D1F\u6570\u503C", bytes);
1385
+ return "0 B";
1386
+ }
1387
+ const k = 1024;
1388
+ const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
1389
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
1390
+ return (bytes / Math.pow(k, i)).toFixed(decimals) + " " + sizes[i];
1391
+ }
1392
+ var validator = {
1393
+ limit(limit, length) {
1394
+ return length < limit;
1395
+ },
1396
+ size(fileSize, maxSize) {
1397
+ return fileSize <= maxSize;
1398
+ },
1399
+ type(accept, file) {
1400
+ if (accept.length > 0) {
1401
+ return accept.some((acceptType) => {
1402
+ if (acceptType.endsWith("/*")) {
1403
+ const category = acceptType.split("/")[0];
1404
+ return file.File?.type.startsWith(category);
1405
+ }
1406
+ if (acceptType.startsWith(".")) {
1407
+ return file.fileName.toLowerCase().endsWith(acceptType.toLowerCase());
1408
+ }
1409
+ return file.File?.type === acceptType;
1410
+ });
1411
+ }
1412
+ return true;
1413
+ }
1414
+ };
1415
+ function createReactiveFile(file, manager) {
1416
+ Object.defineProperty(file, "transfer", {
1417
+ value: manager,
1418
+ enumerable: false,
1419
+ // 不可枚举,避免循环引用
1420
+ writable: false,
1421
+ configurable: true
1422
+ });
1423
+ return new Proxy(file, {
1424
+ get(target, prop, _receiver) {
1425
+ const value = Reflect.get(target, prop);
1426
+ if (typeof value === "function") {
1427
+ return function(...args) {
1428
+ const result = value.apply(target, args);
1429
+ return result;
1430
+ };
1431
+ }
1432
+ return value;
1433
+ },
1434
+ set(target, prop, value, _receiver) {
1435
+ const oldValue = Reflect.get(target, prop);
1436
+ const result = Reflect.set(target, prop, value);
1437
+ if (oldValue !== value) {
1438
+ manager.triggerUpdate();
1439
+ }
1440
+ return result;
1441
+ },
1442
+ // 添加 deleteProperty 陷阱,支持删除操作
1443
+ deleteProperty(target, prop) {
1444
+ const result = Reflect.deleteProperty(target, prop);
1445
+ manager.triggerUpdate();
1446
+ return result;
1447
+ }
1448
+ });
1449
+ }
1450
+ function createReactiveUploadFile(file, uploader) {
1451
+ return createReactiveFile(file, uploader);
1452
+ }
1453
+ function createReactiveDownloadFile(file, downloader) {
1454
+ return createReactiveFile(file, downloader);
1455
+ }
1456
+ function extractPathFromFunction(str) {
1457
+ const pattern = /['"`](\/[^'"`]*)['"`]/;
1458
+ const match = str.match(pattern);
1459
+ return match ? match[1] : null;
1460
+ }
1461
+ function isPlainObject(value) {
1462
+ return value !== null && typeof value === "object" && !Array.isArray(value);
1463
+ }
1464
+ function formatSpeed(bytesPerSecond) {
1465
+ if (bytesPerSecond === 0) {
1466
+ return "0 B/s";
1467
+ }
1468
+ const units = ["B/s", "KB/s", "MB/s", "GB/s"];
1469
+ let value = bytesPerSecond;
1470
+ let unitIndex = 0;
1471
+ while (value >= 1024 && unitIndex < units.length - 1) {
1472
+ value /= 1024;
1473
+ unitIndex++;
1474
+ }
1475
+ return `${value.toFixed(2)} ${units[unitIndex]}`;
1476
+ }
1477
+ function formatDuration(milliseconds) {
1478
+ if (milliseconds === 0) {
1479
+ return "0s";
1480
+ }
1481
+ const seconds = Math.floor(milliseconds / 1e3);
1482
+ const minutes = Math.floor(seconds / 60);
1483
+ const hours = Math.floor(minutes / 60);
1484
+ if (hours > 0) {
1485
+ const remainingMinutes = minutes % 60;
1486
+ const remainingSeconds = seconds % 60;
1487
+ return `${hours}h ${remainingMinutes}m ${remainingSeconds}s`;
1488
+ } else if (minutes > 0) {
1489
+ const remainingSeconds = seconds % 60;
1490
+ return `${minutes}m ${remainingSeconds}s`;
1491
+ } else {
1492
+ return `${seconds}s`;
1493
+ }
1494
+ }
1495
+ function sleep(ms) {
1496
+ return new Promise((resolve) => setTimeout(resolve, ms));
1497
+ }
1498
+ var _md5WorkerModule = null;
1499
+ async function getMD5WorkerModule() {
1500
+ if (!_md5WorkerModule) {
1501
+ _md5WorkerModule = await Promise.resolve().then(() => (init_md5Worker(), md5Worker_exports));
1502
+ }
1503
+ return _md5WorkerModule;
1504
+ }
1505
+ async function calculateFileMD5(file, onProgress, signal) {
1506
+ const WORKER_MIN_SIZE = 5 * 1024 * 1024;
1507
+ const useWorker = !onProgress && // 有进度回调时不用 Worker(Worker 不提供分片进度)
1508
+ typeof Worker !== "undefined" && file.size >= WORKER_MIN_SIZE;
1509
+ if (useWorker) {
1510
+ try {
1511
+ const { calculateFileMD5InWorker: calculateFileMD5InWorker2 } = await getMD5WorkerModule();
1512
+ return await calculateFileMD5InWorker2(file, signal);
1513
+ } catch (workerErr) {
1514
+ console.warn("[calculateFileMD5] Worker \u8DEF\u5F84\u5931\u8D25\uFF0C\u56DE\u9000\u5230\u4E3B\u7EBF\u7A0B:", workerErr);
1515
+ }
1516
+ }
1517
+ return new Promise(async (resolve, reject) => {
1518
+ try {
1519
+ let loadNext2 = function() {
1520
+ if (signal?.aborted) {
1521
+ reject(new Error("MD5 \u8BA1\u7B97\u5DF2\u53D6\u6D88"));
1522
+ return;
1523
+ }
1524
+ const start = currentChunk * chunkSize;
1525
+ const end = Math.min(start + chunkSize, file.size);
1526
+ fileReader.readAsArrayBuffer(file.slice(start, end));
1527
+ };
1528
+ var loadNext = loadNext2;
1529
+ const chunkSize = 2 * 1024 * 1024;
1530
+ const chunks = Math.ceil(file.size / chunkSize);
1531
+ let currentChunk = 0;
1532
+ const spark = new SparkMD5__default.default.ArrayBuffer();
1533
+ const fileReader = new FileReader();
1534
+ if (signal) {
1535
+ signal.addEventListener("abort", () => {
1536
+ fileReader.abort();
1537
+ reject(new Error("MD5 \u8BA1\u7B97\u5DF2\u53D6\u6D88"));
1538
+ });
1539
+ }
1540
+ fileReader.onload = (e) => {
1541
+ if (signal?.aborted) {
1542
+ fileReader.abort();
1543
+ reject(new Error("MD5 \u8BA1\u7B97\u5DF2\u53D6\u6D88"));
1544
+ return;
1545
+ }
1546
+ if (e.target?.result) {
1547
+ spark.append(e.target.result);
1548
+ currentChunk++;
1549
+ if (onProgress) {
1550
+ const percent = Math.round(currentChunk / chunks * 100);
1551
+ onProgress(percent);
1552
+ }
1553
+ if (currentChunk < chunks) {
1554
+ loadNext2();
1555
+ } else {
1556
+ resolve(spark.end());
1557
+ }
1558
+ }
1559
+ };
1560
+ fileReader.onerror = () => {
1561
+ reject(new Error("\u6587\u4EF6\u8BFB\u53D6\u5931\u8D25"));
1562
+ };
1563
+ loadNext2();
1564
+ } catch (error) {
1565
+ console.error("MD5 \u8BA1\u7B97\u5E93\u52A0\u8F7D\u5931\u8D25:", error);
1566
+ reject(new Error("MD5 \u8BA1\u7B97\u5E93\u52A0\u8F7D\u5931\u8D25"));
1567
+ }
1568
+ });
1569
+ }
1570
+
1571
+ exports.LogLevel = LogLevel;
1572
+ exports.addLogCollector = addLogCollector;
1573
+ exports.calculateFileMD5 = calculateFileMD5;
1574
+ exports.calculateFileMD5InWorker = calculateFileMD5InWorker;
1575
+ exports.checkNetworkConnectivity = checkNetworkConnectivity;
1576
+ exports.checkNetworkStatus = checkNetworkStatus;
1577
+ exports.cleanExpiredCache = cleanExpiredCache;
1578
+ exports.clearAllFileCache = clearAllFileCache;
1579
+ exports.clearLogCollectors = clearLogCollectors;
1580
+ exports.computeTransferTime = computeTransferTime;
1581
+ exports.createReactiveDownloadFile = createReactiveDownloadFile;
1582
+ exports.createReactiveUploadFile = createReactiveUploadFile;
1583
+ exports.disposeMD5Worker = disposeMD5Worker;
1584
+ exports.extractPathFromFunction = extractPathFromFunction;
1585
+ exports.formatDuration = formatDuration;
1586
+ exports.formatFileSize = formatFileSize;
1587
+ exports.formatSpeed = formatSpeed;
1588
+ exports.generateFileId = generateFileId;
1589
+ exports.getCacheStats = getCacheStats;
1590
+ exports.getFileExtension = getFileExtension;
1591
+ exports.handleFile = handleFile;
1592
+ exports.initLogger = initLogger;
1593
+ exports.isFileActive = isFileActive;
1594
+ exports.isPlainObject = isPlainObject;
1595
+ exports.loadFileHandle = loadFileHandle;
1596
+ exports.logger = logger;
1597
+ exports.mergeObjects = mergeObjects;
1598
+ exports.removeFileFromCache = removeFileFromCache;
1599
+ exports.removeFileHandle = removeFileHandle;
1600
+ exports.restoreFileFromCache = restoreFileFromCache;
1601
+ exports.saveFileHandle = saveFileHandle;
1602
+ exports.saveFileToCache = saveFileToCache;
1603
+ exports.setLogLevel = setLogLevel;
1604
+ exports.sleep = sleep;
1605
+ exports.uploadMonitor = uploadMonitor;
1606
+ exports.validator = validator;
1607
+ exports.watchNetworkStatus = watchNetworkStatus;
1608
+ //# sourceMappingURL=out.js.map
1609
+ //# sourceMappingURL=index.js.map