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.
- package/README.md +114 -0
- package/dist/bin/dydl.d.ts +2 -0
- package/dist/bin/dydl.js +17 -0
- package/dist/bin/dydl.js.map +1 -0
- package/dist/src/cli/commands/check.d.ts +10 -0
- package/dist/src/cli/commands/check.js +102 -0
- package/dist/src/cli/commands/check.js.map +1 -0
- package/dist/src/cli/commands/info.d.ts +10 -0
- package/dist/src/cli/commands/info.js +106 -0
- package/dist/src/cli/commands/info.js.map +1 -0
- package/dist/src/cli/commands/list.d.ts +10 -0
- package/dist/src/cli/commands/list.js +85 -0
- package/dist/src/cli/commands/list.js.map +1 -0
- package/dist/src/cli/commands/login.d.ts +10 -0
- package/dist/src/cli/commands/login.js +158 -0
- package/dist/src/cli/commands/login.js.map +1 -0
- package/dist/src/cli/commands/open.d.ts +10 -0
- package/dist/src/cli/commands/open.js +141 -0
- package/dist/src/cli/commands/open.js.map +1 -0
- package/dist/src/cli/commands/video.d.ts +10 -0
- package/dist/src/cli/commands/video.js +209 -0
- package/dist/src/cli/commands/video.js.map +1 -0
- package/dist/src/cli/index.d.ts +15 -0
- package/dist/src/cli/index.js +134 -0
- package/dist/src/cli/index.js.map +1 -0
- package/dist/src/cli/progress-display.d.ts +80 -0
- package/dist/src/cli/progress-display.js +225 -0
- package/dist/src/cli/progress-display.js.map +1 -0
- package/dist/src/cli/utils.d.ts +31 -0
- package/dist/src/cli/utils.js +171 -0
- package/dist/src/cli/utils.js.map +1 -0
- package/dist/src/douyin/auth/cookie-path.d.ts +22 -0
- package/dist/src/douyin/auth/cookie-path.js +72 -0
- package/dist/src/douyin/auth/cookie-path.js.map +1 -0
- package/dist/src/douyin/auth/cookie-storage.d.ts +19 -0
- package/dist/src/douyin/auth/cookie-storage.js +65 -0
- package/dist/src/douyin/auth/cookie-storage.js.map +1 -0
- package/dist/src/douyin/auth/errors.d.ts +28 -0
- package/dist/src/douyin/auth/errors.js +49 -0
- package/dist/src/douyin/auth/errors.js.map +1 -0
- package/dist/src/douyin/auth/getDefaultCookiePath.d.ts +24 -0
- package/dist/src/douyin/auth/getDefaultCookiePath.js +90 -0
- package/dist/src/douyin/auth/getDefaultCookiePath.js.map +1 -0
- package/dist/src/douyin/auth/index.d.ts +16 -0
- package/dist/src/douyin/auth/index.js +68 -0
- package/dist/src/douyin/auth/index.js.map +1 -0
- package/dist/src/douyin/auth/isValidCookie.d.ts +18 -0
- package/dist/src/douyin/auth/isValidCookie.js +60 -0
- package/dist/src/douyin/auth/isValidCookie.js.map +1 -0
- package/dist/src/douyin/auth/loadAndValidateCookie.d.ts +17 -0
- package/dist/src/douyin/auth/loadAndValidateCookie.js +45 -0
- package/dist/src/douyin/auth/loadAndValidateCookie.js.map +1 -0
- package/dist/src/douyin/auth/loadCookie.d.ts +17 -0
- package/dist/src/douyin/auth/loadCookie.js +79 -0
- package/dist/src/douyin/auth/loadCookie.js.map +1 -0
- package/dist/src/douyin/auth/login.d.ts +33 -0
- package/dist/src/douyin/auth/login.js +157 -0
- package/dist/src/douyin/auth/login.js.map +1 -0
- package/dist/src/douyin/auth/saveCookie.d.ts +17 -0
- package/dist/src/douyin/auth/saveCookie.js +89 -0
- package/dist/src/douyin/auth/saveCookie.js.map +1 -0
- package/dist/src/douyin/auth/validate.d.ts +11 -0
- package/dist/src/douyin/auth/validate.js +104 -0
- package/dist/src/douyin/auth/validate.js.map +1 -0
- package/dist/src/douyin/browser/manager.d.ts +54 -0
- package/dist/src/douyin/browser/manager.js +344 -0
- package/dist/src/douyin/browser/manager.js.map +1 -0
- package/dist/src/douyin/download/download-manager.d.ts +25 -0
- package/dist/src/douyin/download/download-manager.js +107 -0
- package/dist/src/douyin/download/download-manager.js.map +1 -0
- package/dist/src/douyin/download/error-handler.d.ts +49 -0
- package/dist/src/douyin/download/error-handler.js +160 -0
- package/dist/src/douyin/download/error-handler.js.map +1 -0
- package/dist/src/douyin/download/index.d.ts +39 -0
- package/dist/src/douyin/download/index.js +156 -0
- package/dist/src/douyin/download/index.js.map +1 -0
- package/dist/src/douyin/download/path-formatter.d.ts +42 -0
- package/dist/src/douyin/download/path-formatter.js +107 -0
- package/dist/src/douyin/download/path-formatter.js.map +1 -0
- package/dist/src/douyin/download/video-downloader.d.ts +35 -0
- package/dist/src/douyin/download/video-downloader.js +223 -0
- package/dist/src/douyin/download/video-downloader.js.map +1 -0
- package/dist/src/douyin/index.d.ts +19 -0
- package/dist/src/douyin/index.js +52 -0
- package/dist/src/douyin/index.js.map +1 -0
- package/dist/src/douyin/info/batch-processor.d.ts +15 -0
- package/dist/src/douyin/info/batch-processor.js +65 -0
- package/dist/src/douyin/info/batch-processor.js.map +1 -0
- package/dist/src/douyin/info/browser-manager.d.ts +56 -0
- package/dist/src/douyin/info/browser-manager.js +225 -0
- package/dist/src/douyin/info/browser-manager.js.map +1 -0
- package/dist/src/douyin/info/error-handler.d.ts +36 -0
- package/dist/src/douyin/info/error-handler.js +172 -0
- package/dist/src/douyin/info/error-handler.js.map +1 -0
- package/dist/src/douyin/info/fetch-video-detail.d.ts +14 -0
- package/dist/src/douyin/info/fetch-video-detail.js +247 -0
- package/dist/src/douyin/info/fetch-video-detail.js.map +1 -0
- package/dist/src/douyin/info/index.d.ts +29 -0
- package/dist/src/douyin/info/index.js +85 -0
- package/dist/src/douyin/info/index.js.map +1 -0
- package/dist/src/douyin/info/text-processor.d.ts +15 -0
- package/dist/src/douyin/info/text-processor.js +47 -0
- package/dist/src/douyin/info/text-processor.js.map +1 -0
- package/dist/src/douyin/info/user.d.ts +26 -0
- package/dist/src/douyin/info/user.js +237 -0
- package/dist/src/douyin/info/user.js.map +1 -0
- package/dist/src/douyin/parser/containsDouyinLink.d.ts +18 -0
- package/dist/src/douyin/parser/containsDouyinLink.js +27 -0
- package/dist/src/douyin/parser/containsDouyinLink.js.map +1 -0
- package/dist/src/douyin/parser/extract-links.d.ts +23 -0
- package/dist/src/douyin/parser/extract-links.js +79 -0
- package/dist/src/douyin/parser/extract-links.js.map +1 -0
- package/dist/src/douyin/parser/extractDouyinLinks.d.ts +18 -0
- package/dist/src/douyin/parser/extractDouyinLinks.js +58 -0
- package/dist/src/douyin/parser/extractDouyinLinks.js.map +1 -0
- package/dist/src/douyin/parser/index.d.ts +35 -0
- package/dist/src/douyin/parser/index.js +70 -0
- package/dist/src/douyin/parser/index.js.map +1 -0
- package/dist/src/douyin/parser/link-patterns.d.ts +34 -0
- package/dist/src/douyin/parser/link-patterns.js +121 -0
- package/dist/src/douyin/parser/link-patterns.js.map +1 -0
- package/dist/src/douyin/parser/parse-batch.d.ts +26 -0
- package/dist/src/douyin/parser/parse-batch.js +67 -0
- package/dist/src/douyin/parser/parse-batch.js.map +1 -0
- package/dist/src/douyin/parser/parseDouyinLinks.d.ts +30 -0
- package/dist/src/douyin/parser/parseDouyinLinks.js +164 -0
- package/dist/src/douyin/parser/parseDouyinLinks.js.map +1 -0
- package/dist/src/douyin/parser/resolve-links.d.ts +25 -0
- package/dist/src/douyin/parser/resolve-links.js +131 -0
- package/dist/src/douyin/parser/resolve-links.js.map +1 -0
- package/dist/src/index.d.ts +16 -0
- package/dist/src/index.js +72 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/types.d.ts +217 -0
- package/dist/src/types.js +6 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils/browser.d.ts +73 -0
- package/dist/src/utils/browser.js +96 -0
- package/dist/src/utils/browser.js.map +1 -0
- package/dist/src/utils/error.d.ts +160 -0
- package/dist/src/utils/error.js +334 -0
- package/dist/src/utils/error.js.map +1 -0
- package/dist/src/utils/fetch.d.ts +41 -0
- package/dist/src/utils/fetch.js +155 -0
- package/dist/src/utils/fetch.js.map +1 -0
- package/dist/src/utils/file.d.ts +46 -0
- package/dist/src/utils/file.js +189 -0
- package/dist/src/utils/file.js.map +1 -0
- package/dist/src/utils/index.d.ts +11 -0
- package/dist/src/utils/index.js +29 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/logger.d.ts +161 -0
- package/dist/src/utils/logger.js +286 -0
- package/dist/src/utils/logger.js.map +1 -0
- package/dist/src/utils/performance.d.ts +98 -0
- package/dist/src/utils/performance.js +292 -0
- package/dist/src/utils/performance.js.map +1 -0
- package/dist/src/utils/retry.d.ts +56 -0
- package/dist/src/utils/retry.js +127 -0
- package/dist/src/utils/retry.js.map +1 -0
- 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;
|