douyin-downloader 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.
Files changed (161) hide show
  1. package/README.md +114 -0
  2. package/dist/bin/dydl.d.ts +2 -0
  3. package/dist/bin/dydl.js +17 -0
  4. package/dist/bin/dydl.js.map +1 -0
  5. package/dist/src/cli/commands/check.d.ts +10 -0
  6. package/dist/src/cli/commands/check.js +102 -0
  7. package/dist/src/cli/commands/check.js.map +1 -0
  8. package/dist/src/cli/commands/info.d.ts +10 -0
  9. package/dist/src/cli/commands/info.js +106 -0
  10. package/dist/src/cli/commands/info.js.map +1 -0
  11. package/dist/src/cli/commands/list.d.ts +10 -0
  12. package/dist/src/cli/commands/list.js +85 -0
  13. package/dist/src/cli/commands/list.js.map +1 -0
  14. package/dist/src/cli/commands/login.d.ts +10 -0
  15. package/dist/src/cli/commands/login.js +158 -0
  16. package/dist/src/cli/commands/login.js.map +1 -0
  17. package/dist/src/cli/commands/open.d.ts +10 -0
  18. package/dist/src/cli/commands/open.js +141 -0
  19. package/dist/src/cli/commands/open.js.map +1 -0
  20. package/dist/src/cli/commands/video.d.ts +10 -0
  21. package/dist/src/cli/commands/video.js +209 -0
  22. package/dist/src/cli/commands/video.js.map +1 -0
  23. package/dist/src/cli/index.d.ts +15 -0
  24. package/dist/src/cli/index.js +134 -0
  25. package/dist/src/cli/index.js.map +1 -0
  26. package/dist/src/cli/progress-display.d.ts +80 -0
  27. package/dist/src/cli/progress-display.js +225 -0
  28. package/dist/src/cli/progress-display.js.map +1 -0
  29. package/dist/src/cli/utils.d.ts +31 -0
  30. package/dist/src/cli/utils.js +171 -0
  31. package/dist/src/cli/utils.js.map +1 -0
  32. package/dist/src/douyin/auth/cookie-path.d.ts +22 -0
  33. package/dist/src/douyin/auth/cookie-path.js +72 -0
  34. package/dist/src/douyin/auth/cookie-path.js.map +1 -0
  35. package/dist/src/douyin/auth/cookie-storage.d.ts +19 -0
  36. package/dist/src/douyin/auth/cookie-storage.js +65 -0
  37. package/dist/src/douyin/auth/cookie-storage.js.map +1 -0
  38. package/dist/src/douyin/auth/errors.d.ts +28 -0
  39. package/dist/src/douyin/auth/errors.js +49 -0
  40. package/dist/src/douyin/auth/errors.js.map +1 -0
  41. package/dist/src/douyin/auth/getDefaultCookiePath.d.ts +24 -0
  42. package/dist/src/douyin/auth/getDefaultCookiePath.js +90 -0
  43. package/dist/src/douyin/auth/getDefaultCookiePath.js.map +1 -0
  44. package/dist/src/douyin/auth/index.d.ts +16 -0
  45. package/dist/src/douyin/auth/index.js +68 -0
  46. package/dist/src/douyin/auth/index.js.map +1 -0
  47. package/dist/src/douyin/auth/isValidCookie.d.ts +18 -0
  48. package/dist/src/douyin/auth/isValidCookie.js +60 -0
  49. package/dist/src/douyin/auth/isValidCookie.js.map +1 -0
  50. package/dist/src/douyin/auth/loadAndValidateCookie.d.ts +17 -0
  51. package/dist/src/douyin/auth/loadAndValidateCookie.js +45 -0
  52. package/dist/src/douyin/auth/loadAndValidateCookie.js.map +1 -0
  53. package/dist/src/douyin/auth/loadCookie.d.ts +17 -0
  54. package/dist/src/douyin/auth/loadCookie.js +79 -0
  55. package/dist/src/douyin/auth/loadCookie.js.map +1 -0
  56. package/dist/src/douyin/auth/login.d.ts +33 -0
  57. package/dist/src/douyin/auth/login.js +157 -0
  58. package/dist/src/douyin/auth/login.js.map +1 -0
  59. package/dist/src/douyin/auth/saveCookie.d.ts +17 -0
  60. package/dist/src/douyin/auth/saveCookie.js +89 -0
  61. package/dist/src/douyin/auth/saveCookie.js.map +1 -0
  62. package/dist/src/douyin/auth/validate.d.ts +11 -0
  63. package/dist/src/douyin/auth/validate.js +104 -0
  64. package/dist/src/douyin/auth/validate.js.map +1 -0
  65. package/dist/src/douyin/browser/manager.d.ts +54 -0
  66. package/dist/src/douyin/browser/manager.js +344 -0
  67. package/dist/src/douyin/browser/manager.js.map +1 -0
  68. package/dist/src/douyin/download/download-manager.d.ts +25 -0
  69. package/dist/src/douyin/download/download-manager.js +107 -0
  70. package/dist/src/douyin/download/download-manager.js.map +1 -0
  71. package/dist/src/douyin/download/error-handler.d.ts +49 -0
  72. package/dist/src/douyin/download/error-handler.js +160 -0
  73. package/dist/src/douyin/download/error-handler.js.map +1 -0
  74. package/dist/src/douyin/download/index.d.ts +39 -0
  75. package/dist/src/douyin/download/index.js +156 -0
  76. package/dist/src/douyin/download/index.js.map +1 -0
  77. package/dist/src/douyin/download/path-formatter.d.ts +42 -0
  78. package/dist/src/douyin/download/path-formatter.js +107 -0
  79. package/dist/src/douyin/download/path-formatter.js.map +1 -0
  80. package/dist/src/douyin/download/video-downloader.d.ts +35 -0
  81. package/dist/src/douyin/download/video-downloader.js +223 -0
  82. package/dist/src/douyin/download/video-downloader.js.map +1 -0
  83. package/dist/src/douyin/index.d.ts +19 -0
  84. package/dist/src/douyin/index.js +52 -0
  85. package/dist/src/douyin/index.js.map +1 -0
  86. package/dist/src/douyin/info/batch-processor.d.ts +15 -0
  87. package/dist/src/douyin/info/batch-processor.js +65 -0
  88. package/dist/src/douyin/info/batch-processor.js.map +1 -0
  89. package/dist/src/douyin/info/browser-manager.d.ts +56 -0
  90. package/dist/src/douyin/info/browser-manager.js +225 -0
  91. package/dist/src/douyin/info/browser-manager.js.map +1 -0
  92. package/dist/src/douyin/info/error-handler.d.ts +36 -0
  93. package/dist/src/douyin/info/error-handler.js +172 -0
  94. package/dist/src/douyin/info/error-handler.js.map +1 -0
  95. package/dist/src/douyin/info/fetch-video-detail.d.ts +14 -0
  96. package/dist/src/douyin/info/fetch-video-detail.js +247 -0
  97. package/dist/src/douyin/info/fetch-video-detail.js.map +1 -0
  98. package/dist/src/douyin/info/index.d.ts +29 -0
  99. package/dist/src/douyin/info/index.js +85 -0
  100. package/dist/src/douyin/info/index.js.map +1 -0
  101. package/dist/src/douyin/info/text-processor.d.ts +15 -0
  102. package/dist/src/douyin/info/text-processor.js +47 -0
  103. package/dist/src/douyin/info/text-processor.js.map +1 -0
  104. package/dist/src/douyin/info/user.d.ts +26 -0
  105. package/dist/src/douyin/info/user.js +237 -0
  106. package/dist/src/douyin/info/user.js.map +1 -0
  107. package/dist/src/douyin/parser/containsDouyinLink.d.ts +18 -0
  108. package/dist/src/douyin/parser/containsDouyinLink.js +27 -0
  109. package/dist/src/douyin/parser/containsDouyinLink.js.map +1 -0
  110. package/dist/src/douyin/parser/extract-links.d.ts +23 -0
  111. package/dist/src/douyin/parser/extract-links.js +79 -0
  112. package/dist/src/douyin/parser/extract-links.js.map +1 -0
  113. package/dist/src/douyin/parser/extractDouyinLinks.d.ts +18 -0
  114. package/dist/src/douyin/parser/extractDouyinLinks.js +58 -0
  115. package/dist/src/douyin/parser/extractDouyinLinks.js.map +1 -0
  116. package/dist/src/douyin/parser/index.d.ts +35 -0
  117. package/dist/src/douyin/parser/index.js +70 -0
  118. package/dist/src/douyin/parser/index.js.map +1 -0
  119. package/dist/src/douyin/parser/link-patterns.d.ts +34 -0
  120. package/dist/src/douyin/parser/link-patterns.js +121 -0
  121. package/dist/src/douyin/parser/link-patterns.js.map +1 -0
  122. package/dist/src/douyin/parser/parse-batch.d.ts +26 -0
  123. package/dist/src/douyin/parser/parse-batch.js +67 -0
  124. package/dist/src/douyin/parser/parse-batch.js.map +1 -0
  125. package/dist/src/douyin/parser/parseDouyinLinks.d.ts +30 -0
  126. package/dist/src/douyin/parser/parseDouyinLinks.js +164 -0
  127. package/dist/src/douyin/parser/parseDouyinLinks.js.map +1 -0
  128. package/dist/src/douyin/parser/resolve-links.d.ts +25 -0
  129. package/dist/src/douyin/parser/resolve-links.js +131 -0
  130. package/dist/src/douyin/parser/resolve-links.js.map +1 -0
  131. package/dist/src/index.d.ts +16 -0
  132. package/dist/src/index.js +72 -0
  133. package/dist/src/index.js.map +1 -0
  134. package/dist/src/types.d.ts +217 -0
  135. package/dist/src/types.js +6 -0
  136. package/dist/src/types.js.map +1 -0
  137. package/dist/src/utils/browser.d.ts +73 -0
  138. package/dist/src/utils/browser.js +96 -0
  139. package/dist/src/utils/browser.js.map +1 -0
  140. package/dist/src/utils/error.d.ts +160 -0
  141. package/dist/src/utils/error.js +334 -0
  142. package/dist/src/utils/error.js.map +1 -0
  143. package/dist/src/utils/fetch.d.ts +41 -0
  144. package/dist/src/utils/fetch.js +155 -0
  145. package/dist/src/utils/fetch.js.map +1 -0
  146. package/dist/src/utils/file.d.ts +46 -0
  147. package/dist/src/utils/file.js +189 -0
  148. package/dist/src/utils/file.js.map +1 -0
  149. package/dist/src/utils/index.d.ts +11 -0
  150. package/dist/src/utils/index.js +29 -0
  151. package/dist/src/utils/index.js.map +1 -0
  152. package/dist/src/utils/logger.d.ts +161 -0
  153. package/dist/src/utils/logger.js +286 -0
  154. package/dist/src/utils/logger.js.map +1 -0
  155. package/dist/src/utils/performance.d.ts +98 -0
  156. package/dist/src/utils/performance.js +292 -0
  157. package/dist/src/utils/performance.js.map +1 -0
  158. package/dist/src/utils/retry.d.ts +56 -0
  159. package/dist/src/utils/retry.js +127 -0
  160. package/dist/src/utils/retry.js.map +1 -0
  161. package/package.json +61 -0
@@ -0,0 +1,334 @@
1
+ "use strict";
2
+ /**
3
+ * 通用錯誤處理系統
4
+ * 提供統一的錯誤類型和處理機制
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.AppError = exports.ErrorCode = void 0;
8
+ exports.parseHttpStatusFromError = parseHttpStatusFromError;
9
+ exports.parseNetworkError = parseNetworkError;
10
+ /**
11
+ * 錯誤碼枚舉
12
+ * 用於標識不同類型的錯誤
13
+ */
14
+ var ErrorCode;
15
+ (function (ErrorCode) {
16
+ // 通用錯誤
17
+ ErrorCode["UNKNOWN_ERROR"] = "UNKNOWN_ERROR";
18
+ ErrorCode["INVALID_ARGUMENT"] = "INVALID_ARGUMENT";
19
+ // 網絡相關錯誤
20
+ ErrorCode["NETWORK_ERROR"] = "NETWORK_ERROR";
21
+ ErrorCode["TIMEOUT_ERROR"] = "TIMEOUT_ERROR";
22
+ ErrorCode["RATE_LIMIT_ERROR"] = "RATE_LIMIT_ERROR";
23
+ // 認證相關錯誤
24
+ ErrorCode["AUTHENTICATION_ERROR"] = "AUTHENTICATION_ERROR";
25
+ ErrorCode["COOKIE_INVALID"] = "COOKIE_INVALID";
26
+ ErrorCode["COOKIE_EXPIRED"] = "COOKIE_EXPIRED";
27
+ ErrorCode["CAPTCHA_REQUIRED"] = "CAPTCHA_REQUIRED";
28
+ // 解析相關錯誤
29
+ ErrorCode["PARSING_ERROR"] = "PARSING_ERROR";
30
+ ErrorCode["INVALID_URL"] = "INVALID_URL";
31
+ // 資源相關錯誤
32
+ ErrorCode["RESOURCE_ERROR"] = "RESOURCE_ERROR";
33
+ ErrorCode["VIDEO_NOT_FOUND"] = "VIDEO_NOT_FOUND";
34
+ ErrorCode["USER_NOT_FOUND"] = "USER_NOT_FOUND";
35
+ ErrorCode["CONTENT_RESTRICTED"] = "CONTENT_RESTRICTED";
36
+ // 下載相關錯誤
37
+ ErrorCode["DOWNLOAD_ERROR"] = "DOWNLOAD_ERROR";
38
+ ErrorCode["DOWNLOAD_INTERRUPTED"] = "DOWNLOAD_INTERRUPTED";
39
+ // 文件系統錯誤
40
+ ErrorCode["FILE_SYSTEM_ERROR"] = "FILE_SYSTEM_ERROR";
41
+ ErrorCode["PERMISSION_DENIED"] = "PERMISSION_DENIED";
42
+ // 瀏覽器相關錯誤
43
+ ErrorCode["BROWSER_ERROR"] = "BROWSER_ERROR";
44
+ ErrorCode["BROWSER_LAUNCH_FAILED"] = "BROWSER_LAUNCH_FAILED";
45
+ // API 相關錯誤
46
+ ErrorCode["API_ERROR"] = "API_ERROR";
47
+ })(ErrorCode || (exports.ErrorCode = ErrorCode = {}));
48
+ /**
49
+ * 應用程序錯誤類
50
+ * 統一的錯誤類,包含錯誤碼、原因和其他信息
51
+ */
52
+ class AppError extends Error {
53
+ code;
54
+ cause;
55
+ details;
56
+ /**
57
+ * 創建應用程序錯誤
58
+ * @param message 錯誤消息
59
+ * @param code 錯誤碼,默認為 UNKNOWN_ERROR
60
+ * @param cause 原始錯誤,用於錯誤鏈
61
+ * @param details 錯誤詳情,可包含任何額外信息
62
+ */
63
+ constructor(message, code = ErrorCode.UNKNOWN_ERROR, cause, // Allow unknown cause
64
+ details) {
65
+ super(message);
66
+ this.code = code;
67
+ this.cause = cause;
68
+ this.details = details;
69
+ this.name = 'AppError';
70
+ // 捕獲堆棧跟踪
71
+ if (Error.captureStackTrace) {
72
+ Error.captureStackTrace(this, AppError);
73
+ }
74
+ // 如果有原因錯誤,附加其堆棧
75
+ if (this.cause && this.cause instanceof Error && this.cause.stack) {
76
+ this.stack = `${this.stack}\nCaused by: ${this.cause.stack}`;
77
+ }
78
+ }
79
+ /**
80
+ * 獲取完整的錯誤消息,包括錯誤碼和詳情
81
+ */
82
+ get fullMessage() {
83
+ let msg = `[${this.code}] ${this.message}`;
84
+ if (this.cause) {
85
+ const causeMessage = this.cause instanceof Error ? this.cause.message : String(this.cause);
86
+ msg += `\nCaused by: ${causeMessage}`;
87
+ }
88
+ if (this.details) {
89
+ try {
90
+ msg += `\nDetails: ${JSON.stringify(this.details)}`;
91
+ }
92
+ catch (e) {
93
+ msg += `\nDetails: [無法序列化詳情]`;
94
+ }
95
+ }
96
+ return msg;
97
+ }
98
+ /**
99
+ * 判斷錯誤是否可重試
100
+ * @returns 是否可重試
101
+ */
102
+ isRetryable() {
103
+ const retryableCodes = [
104
+ ErrorCode.NETWORK_ERROR,
105
+ ErrorCode.TIMEOUT_ERROR,
106
+ ErrorCode.RATE_LIMIT_ERROR,
107
+ ErrorCode.DOWNLOAD_INTERRUPTED,
108
+ ErrorCode.BROWSER_ERROR,
109
+ ErrorCode.API_ERROR // Consider if all API errors are retryable
110
+ ];
111
+ return retryableCodes.includes(this.code);
112
+ }
113
+ /**
114
+ * 從通用錯誤創建 AppError
115
+ * @param error 通用錯誤
116
+ * @param code 錯誤碼,默認為 UNKNOWN_ERROR
117
+ * @param defaultMessage 默認錯誤消息,如果原錯誤沒有消息
118
+ * @returns AppError 實例
119
+ */
120
+ static from(error, code = ErrorCode.UNKNOWN_ERROR, defaultMessage = '未知錯誤') {
121
+ if (error instanceof AppError) {
122
+ return error;
123
+ }
124
+ const errorObject = error instanceof Error ? error : new Error(typeof error === 'string' ? error : defaultMessage);
125
+ return new AppError(errorObject.message, code, errorObject);
126
+ }
127
+ /**
128
+ * 創建網絡錯誤
129
+ * @param message 錯誤消息
130
+ * @param cause 原始錯誤
131
+ * @returns AppError 實例
132
+ */
133
+ static network(message, cause) {
134
+ return new AppError(message, ErrorCode.NETWORK_ERROR, cause);
135
+ }
136
+ /**
137
+ * 創建認證錯誤
138
+ * @param message 錯誤消息
139
+ * @param cause 原始錯誤
140
+ * @returns AppError 實例
141
+ */
142
+ static authentication(message, cause) {
143
+ return new AppError(message, ErrorCode.AUTHENTICATION_ERROR, cause);
144
+ }
145
+ /**
146
+ * 創建解析錯誤
147
+ * @param message 錯誤消息
148
+ * @param cause 原始錯誤
149
+ * @returns AppError 實例
150
+ */
151
+ static parsing(message, cause) {
152
+ return new AppError(message, ErrorCode.PARSING_ERROR, cause);
153
+ }
154
+ /**
155
+ * 創建視頻未找到錯誤
156
+ * @param message 錯誤消息
157
+ * @param videoId 視頻ID
158
+ * @returns AppError 實例
159
+ */
160
+ static videoNotFound(message, videoId) {
161
+ return new AppError(message, ErrorCode.VIDEO_NOT_FOUND, undefined, videoId ? { videoId } : undefined);
162
+ }
163
+ /**
164
+ * 創建用戶未找到錯誤
165
+ * @param message 錯誤消息
166
+ * @param userId 用戶ID
167
+ * @returns AppError 實例
168
+ */
169
+ static userNotFound(message, userId) {
170
+ return new AppError(message, ErrorCode.USER_NOT_FOUND, undefined, userId ? { userId } : undefined);
171
+ }
172
+ /**
173
+ * 創建下載錯誤
174
+ * @param message 錯誤消息
175
+ * @param cause 原始錯誤
176
+ * @param url 下載URL
177
+ * @returns AppError 實例
178
+ */
179
+ static download(message, cause, url) {
180
+ return new AppError(message, ErrorCode.DOWNLOAD_ERROR, cause, url ? { url } : undefined);
181
+ }
182
+ /**
183
+ * 創建文件系統錯誤
184
+ * @param message 錯誤消息
185
+ * @param cause 原始錯誤
186
+ * @param path 文件路徑
187
+ * @returns AppError 實例
188
+ */
189
+ static fileSystem(message, cause, path) {
190
+ return new AppError(message, ErrorCode.FILE_SYSTEM_ERROR, cause, path ? { path } : undefined);
191
+ }
192
+ /**
193
+ * 創建權限錯誤
194
+ * @param message 錯誤消息
195
+ * @param cause 原始錯誤
196
+ * @param path 文件路徑
197
+ * @returns AppError 實例
198
+ */
199
+ static permissionDenied(message, cause, path) {
200
+ return new AppError(message, ErrorCode.PERMISSION_DENIED, cause, path ? { path } : undefined);
201
+ }
202
+ /**
203
+ * 創建瀏覽器錯誤
204
+ * @param message 錯誤消息
205
+ * @param cause 原始錯誤
206
+ * @returns AppError 實例
207
+ */
208
+ static browser(message, cause) {
209
+ return new AppError(message, ErrorCode.BROWSER_ERROR, cause);
210
+ }
211
+ /**
212
+ * 創建API錯誤
213
+ * @param message 錯誤消息
214
+ * @param cause 原始錯誤
215
+ * @param statusCode HTTP狀態碼
216
+ * @returns AppError 實例
217
+ */
218
+ static api(message, cause, statusCode) {
219
+ return new AppError(message, ErrorCode.API_ERROR, cause, statusCode ? { statusCode } : undefined);
220
+ }
221
+ /**
222
+ * 處理平台API特定錯誤 (需要平台特定實現來覆蓋或擴展)
223
+ * @param apiResponse API響應
224
+ * @param platform 平台標識 ('douyin', 'tiktok', etc.)
225
+ * @returns AppError 實例
226
+ */
227
+ static fromApiResponse(apiResponse, platform = 'unknown') {
228
+ // 這裡提供一個基礎實現,平台特定代碼應提供更詳細的解析
229
+ console.warn(`[AppError] Platform-specific API error parsing not implemented for platform: ${platform}. Using generic parsing.`);
230
+ // 嘗試通用解析
231
+ if (apiResponse && typeof apiResponse.statusCode === 'number') {
232
+ const { statusCode, statusMsg } = apiResponse;
233
+ const message = statusMsg || `${platform} API 錯誤`;
234
+ // 通用狀態碼處理
235
+ if (statusCode === 401 || statusCode === 403) {
236
+ return new AppError(message, ErrorCode.AUTHENTICATION_ERROR, undefined, { statusCode });
237
+ }
238
+ if (statusCode === 404) {
239
+ return new AppError(message, ErrorCode.RESOURCE_ERROR, undefined, { statusCode });
240
+ }
241
+ if (statusCode === 429) {
242
+ return new AppError(message, ErrorCode.RATE_LIMIT_ERROR, undefined, { statusCode });
243
+ }
244
+ if (statusCode >= 500) {
245
+ return new AppError(message, ErrorCode.API_ERROR, undefined, { statusCode });
246
+ }
247
+ // 其他狀態碼視為通用 API 錯誤
248
+ return new AppError(message, ErrorCode.API_ERROR, undefined, { statusCode, statusMsg });
249
+ }
250
+ // 如果沒有明確的狀態碼,返回通用API錯誤
251
+ return new AppError(typeof apiResponse === 'string'
252
+ ? apiResponse
253
+ : `${platform} API 響應解析失敗`, ErrorCode.API_ERROR);
254
+ }
255
+ }
256
+ exports.AppError = AppError;
257
+ /**
258
+ * 解析錯誤消息中的HTTP狀態碼
259
+ * @param error 錯誤對象
260
+ * @returns 狀態碼或undefined
261
+ */
262
+ function parseHttpStatusFromError(error) {
263
+ // Check AppError details first
264
+ if (error instanceof AppError && error.details?.statusCode) {
265
+ return error.details.statusCode;
266
+ }
267
+ const message = error.message;
268
+ // 嘗試從消息中提取HTTP狀態碼
269
+ const statusMatch = message.match(/(\b[45]\d\d\b)/);
270
+ if (statusMatch) {
271
+ return parseInt(statusMatch[1], 10);
272
+ }
273
+ // 檢查錯誤對象是否包含狀態碼
274
+ if ('statusCode' in error && typeof error.statusCode === 'number') {
275
+ return error.statusCode;
276
+ }
277
+ // 檢查錯誤對象是否包含響應對象
278
+ if ('response' in error && error.response) {
279
+ const response = error.response;
280
+ if (typeof response.status === 'number') {
281
+ return response.status;
282
+ }
283
+ if (typeof response.statusCode === 'number') {
284
+ return response.statusCode;
285
+ }
286
+ }
287
+ // Check cause if it exists
288
+ if (error instanceof AppError && error.cause instanceof Error) {
289
+ return parseHttpStatusFromError(error.cause);
290
+ }
291
+ return undefined;
292
+ }
293
+ /**
294
+ * 解析常見的網絡錯誤
295
+ * @param error 錯誤對象
296
+ * @returns 標準化的AppError
297
+ */
298
+ function parseNetworkError(error) {
299
+ // If it's already an AppError, return it, unless it's UNKNOWN
300
+ if (error instanceof AppError && error.code !== ErrorCode.UNKNOWN_ERROR) {
301
+ return error;
302
+ }
303
+ const originalError = error instanceof AppError ? error.cause || error : error;
304
+ const message = originalError instanceof Error ? originalError.message.toLowerCase() : String(originalError).toLowerCase();
305
+ const statusCode = parseHttpStatusFromError(error); // Parse from original error or AppError wrapper
306
+ // 處理常見的狀態碼
307
+ if (statusCode) {
308
+ if (statusCode === 404) {
309
+ return AppError.from(originalError, ErrorCode.RESOURCE_ERROR, '資源不存在');
310
+ }
311
+ if (statusCode === 401 || statusCode === 403) {
312
+ return AppError.from(originalError, ErrorCode.AUTHENTICATION_ERROR, '認證失敗或無權訪問');
313
+ }
314
+ if (statusCode === 429) {
315
+ return AppError.from(originalError, ErrorCode.RATE_LIMIT_ERROR, '請求過於頻繁,請稍後再試');
316
+ }
317
+ if (statusCode >= 500) {
318
+ return AppError.from(originalError, ErrorCode.API_ERROR, '服務器錯誤,請稍後再試');
319
+ }
320
+ }
321
+ // 處理常見的錯誤信息
322
+ if (message.includes('timeout') || message.includes('timed out')) {
323
+ return AppError.from(originalError, ErrorCode.TIMEOUT_ERROR, '網絡請求超時');
324
+ }
325
+ if (message.includes('network') || message.includes('connection') || message.includes('econnrefused') || message.includes('econnreset')) {
326
+ return AppError.from(originalError, ErrorCode.NETWORK_ERROR, '網絡連接錯誤');
327
+ }
328
+ if (message.includes('captcha') || message.includes('人機驗證')) {
329
+ return AppError.from(originalError, ErrorCode.CAPTCHA_REQUIRED, '需要進行人機驗證');
330
+ }
331
+ // 默認為通用網絡錯誤
332
+ return AppError.network(originalError instanceof Error ? originalError.message : '網絡請求失敗', originalError);
333
+ }
334
+ //# sourceMappingURL=error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.js","sourceRoot":"","sources":["../../../src/utils/error.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * 通用網絡請求工具
3
+ * 提供封裝的 fetch API,包含重試和超時處理
4
+ */
5
+ /**
6
+ * 請求選項接口
7
+ */
8
+ export interface FetchOptions extends RequestInit {
9
+ timeout?: number;
10
+ retries?: number;
11
+ retryDelay?: number;
12
+ }
13
+ /**
14
+ * 延遲函數
15
+ * @param ms 延遲毫秒數
16
+ * @returns Promise<void>
17
+ */
18
+ export declare const delay: (ms: number) => Promise<void>;
19
+ /**
20
+ * 增強的 fetch 函數
21
+ * 支持超時、重試和錯誤處理
22
+ * @param url 請求 URL
23
+ * @param options 請求選項
24
+ * @returns Promise<Response>
25
+ */
26
+ export declare function enhancedFetch(url: string, options?: FetchOptions): Promise<Response>;
27
+ /**
28
+ * GET 請求,返回 JSON
29
+ * @param url 請求 URL
30
+ * @param options 請求選項
31
+ * @returns Promise<T> 返回 JSON 響應
32
+ */
33
+ export declare function getJson<T = any>(url: string, options?: FetchOptions): Promise<T>;
34
+ /**
35
+ * POST 請求,發送 JSON,返回 JSON
36
+ * @param url 請求 URL
37
+ * @param data 請求數據
38
+ * @param options 請求選項
39
+ * @returns Promise<T> 返回 JSON 響應
40
+ */
41
+ export declare function postJson<T = any>(url: string, data: any, options?: FetchOptions): Promise<T>;
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+ /**
3
+ * 通用網絡請求工具
4
+ * 提供封裝的 fetch API,包含重試和超時處理
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.delay = void 0;
8
+ exports.enhancedFetch = enhancedFetch;
9
+ exports.getJson = getJson;
10
+ exports.postJson = postJson;
11
+ const logger_1 = require("./logger"); // Use the utils logger
12
+ /**
13
+ * 默認請求選項
14
+ */
15
+ const DEFAULT_FETCH_OPTIONS = {
16
+ timeout: 10000, // 默認超時時間為 10 秒
17
+ retries: 3, // 默認重試 3 次
18
+ retryDelay: 1000, // 默認重試間隔 1 秒
19
+ headers: {
20
+ // Keep a generic User-Agent, platform-specific headers can be added in options
21
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36',
22
+ 'Accept': 'application/json, text/plain, */*',
23
+ 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
24
+ 'Connection': 'keep-alive',
25
+ 'Pragma': 'no-cache',
26
+ 'Cache-Control': 'no-cache',
27
+ }
28
+ };
29
+ /**
30
+ * 延遲函數
31
+ * @param ms 延遲毫秒數
32
+ * @returns Promise<void>
33
+ */
34
+ const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
35
+ exports.delay = delay;
36
+ /**
37
+ * 增強的 fetch 函數
38
+ * 支持超時、重試和錯誤處理
39
+ * @param url 請求 URL
40
+ * @param options 請求選項
41
+ * @returns Promise<Response>
42
+ */
43
+ async function enhancedFetch(url, options = {}) {
44
+ // Merge default options with provided options, ensuring headers are merged correctly
45
+ const mergedOptions = {
46
+ ...DEFAULT_FETCH_OPTIONS,
47
+ ...options,
48
+ headers: {
49
+ ...(DEFAULT_FETCH_OPTIONS.headers || {}),
50
+ ...(options.headers || {}),
51
+ },
52
+ };
53
+ const { timeout, retries, retryDelay, ...fetchOptions } = mergedOptions;
54
+ let attempt = 0;
55
+ while (attempt <= retries) {
56
+ attempt++;
57
+ let timeoutId = null;
58
+ try {
59
+ const controller = new AbortController();
60
+ if (timeout) {
61
+ timeoutId = setTimeout(() => controller.abort(), timeout);
62
+ }
63
+ fetchOptions.signal = controller.signal;
64
+ logger_1.utilsLogger.debug(`發起請求: ${fetchOptions.method || 'GET'} ${url} (嘗試 ${attempt})`);
65
+ const response = await fetch(url, fetchOptions);
66
+ if (timeoutId) {
67
+ clearTimeout(timeoutId);
68
+ }
69
+ if (!response.ok) {
70
+ // 處理非 2xx 狀態碼
71
+ let errorText = '';
72
+ try {
73
+ errorText = await response.text();
74
+ }
75
+ catch (textError) {
76
+ logger_1.utilsLogger.warn(`無法讀取錯誤響應體: ${textError}`);
77
+ }
78
+ const errorMessage = `HTTP 錯誤 ${response.status} (${response.statusText}) for ${url}: ${errorText.slice(0, 200)}`; // Limit error text length
79
+ logger_1.utilsLogger.warn(`請求失敗: ${errorMessage}`);
80
+ // Throw an error that includes the status code for better handling
81
+ const httpError = new Error(errorMessage);
82
+ httpError.statusCode = response.status;
83
+ throw httpError;
84
+ }
85
+ logger_1.utilsLogger.debug(`請求成功: ${url}`);
86
+ return response;
87
+ }
88
+ catch (error) {
89
+ if (timeoutId) {
90
+ clearTimeout(timeoutId);
91
+ }
92
+ const err = error instanceof Error ? error : new Error(String(error));
93
+ logger_1.utilsLogger.warn(`請求失敗 (嘗試 ${attempt}/${retries + 1}): ${err.message}`);
94
+ // Check if the error is an abort error due to timeout
95
+ if (err.name === 'AbortError') {
96
+ logger_1.utilsLogger.error(`請求 ${url} 超時 (超時時間: ${timeout}ms)`);
97
+ // Optionally rethrow a specific timeout error
98
+ // throw new Error(`Request timed out after ${timeout}ms: ${url}`);
99
+ }
100
+ if (attempt > retries) {
101
+ logger_1.utilsLogger.error(`請求 ${url} 最終失敗: ${err.message}`);
102
+ throw err; // 達到最大重試次數後拋出錯誤
103
+ }
104
+ // 等待一段時間後重試
105
+ const delayTime = retryDelay * Math.pow(2, attempt - 1); // Exponential backoff
106
+ logger_1.utilsLogger.debug(`等待 ${delayTime}ms 後重試...`);
107
+ await (0, exports.delay)(delayTime);
108
+ }
109
+ }
110
+ // 如果循環結束仍未成功(理論上不應發生,除非 retries < 0)
111
+ throw new Error('請求失敗,達到最大重試次數');
112
+ }
113
+ /**
114
+ * GET 請求,返回 JSON
115
+ * @param url 請求 URL
116
+ * @param options 請求選項
117
+ * @returns Promise<T> 返回 JSON 響應
118
+ */
119
+ async function getJson(url, options = {}) {
120
+ const response = await enhancedFetch(url, { ...options, method: 'GET' });
121
+ try {
122
+ return await response.json();
123
+ }
124
+ catch (e) {
125
+ logger_1.utilsLogger.error(`解析 JSON 失敗 from ${url}:`, e);
126
+ throw new Error(`Failed to parse JSON response from ${url}`);
127
+ }
128
+ }
129
+ /**
130
+ * POST 請求,發送 JSON,返回 JSON
131
+ * @param url 請求 URL
132
+ * @param data 請求數據
133
+ * @param options 請求選項
134
+ * @returns Promise<T> 返回 JSON 響應
135
+ */
136
+ async function postJson(url, data, options = {}) {
137
+ const response = await enhancedFetch(url, {
138
+ method: 'POST',
139
+ headers: {
140
+ 'Content-Type': 'application/json',
141
+ // User-defined headers should override defaults if specified in options
142
+ ...(options.headers || {}),
143
+ },
144
+ body: JSON.stringify(data),
145
+ ...options, // Spread other options like timeout, retries
146
+ });
147
+ try {
148
+ return await response.json();
149
+ }
150
+ catch (e) {
151
+ logger_1.utilsLogger.error(`解析 JSON 失敗 from ${url}:`, e);
152
+ throw new Error(`Failed to parse JSON response from ${url}`);
153
+ }
154
+ }
155
+ //# sourceMappingURL=fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../../src/utils/fetch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * 通用檔案操作工具
3
+ * 提供檔案系統操作功能,如下載檔案、獲取安全檔案名等
4
+ */
5
+ /**
6
+ * 下載檔案
7
+ * @param url 檔案 URL
8
+ * @param destPath 目標路徑
9
+ * @param options 下載選項
10
+ * @returns Promise<string> 下載完成的檔案路徑
11
+ */
12
+ export declare function downloadFile(url: string, destPath: string, options?: {
13
+ headers?: Record<string, string>;
14
+ timeout?: number;
15
+ /**
16
+ * 進度回調函數
17
+ * @param downloaded 已下載的字節數
18
+ * @param total 總字節數 (如果可用)
19
+ */
20
+ onProgress?: (downloaded: number, total?: number) => void;
21
+ }): Promise<string>;
22
+ /**
23
+ * 獲取安全的檔案名(替換非法字符)
24
+ * @param filename 原始檔案名
25
+ * @returns 安全的檔案名
26
+ */
27
+ export declare function getSafeFilename(filename: string): string;
28
+ /**
29
+ * 建立帶有時間戳的檔案名
30
+ * @param name 檔案名(不含副檔名)
31
+ * @param ext 副檔名(不含句點)
32
+ * @returns 格式化的檔案名
33
+ */
34
+ export declare function getTimestampedFilename(name: string, ext: string): string;
35
+ /**
36
+ * 確保目錄存在,如果不存在則創建
37
+ * @param dirPath 目錄路徑
38
+ */
39
+ export declare function ensureDirectoryExists(dirPath: string): Promise<void>;
40
+ /**
41
+ * 獲取應用數據目錄
42
+ * 根據作業系統選擇適當的目錄
43
+ * @param appName 應用程式名稱,用於創建子目錄
44
+ * @returns 資料目錄路徑
45
+ */
46
+ export declare function getAppDataDir(appName?: string): string;