@lmcc-dev/mult-fetch-mcp-server 1.3.0 → 1.3.2

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 (91) hide show
  1. package/README.md +68 -15
  2. package/README.zh.md +31 -0
  3. package/dist/src/client.js +118 -91
  4. package/dist/src/lib/fetchers/browser/BrowserFetcher.js +25 -10
  5. package/dist/src/lib/fetchers/browser/BrowserInstance.js +67 -64
  6. package/dist/src/lib/fetchers/common/BaseFetcher.js +106 -10
  7. package/dist/src/lib/fetchers/common/types.js +10 -1
  8. package/dist/src/lib/fetchers/common/utils.js +1 -1
  9. package/dist/src/lib/fetchers/node/HttpClient.js +41 -21
  10. package/dist/src/lib/fetchers/node/NodeFetcher.js +24 -8
  11. package/dist/src/lib/i18n/index.js +2 -2
  12. package/dist/src/lib/i18n/keys/client.js +1 -0
  13. package/dist/src/lib/i18n/keys/extractor.js +26 -0
  14. package/dist/src/lib/i18n/keys/fetcher.js +12 -1
  15. package/dist/src/lib/i18n/keys/index.js +1 -0
  16. package/dist/src/lib/i18n/keys/node.js +2 -0
  17. package/dist/src/lib/i18n/locales/en/client.js +1 -0
  18. package/dist/src/lib/i18n/locales/en/extractor.js +24 -0
  19. package/dist/src/lib/i18n/locales/en/fetcher.js +3 -1
  20. package/dist/src/lib/i18n/locales/en/index.js +2 -0
  21. package/dist/src/lib/i18n/locales/en/node.js +2 -0
  22. package/dist/src/lib/i18n/locales/zh/client.js +1 -0
  23. package/dist/src/lib/i18n/locales/zh/extractor.js +22 -0
  24. package/dist/src/lib/i18n/locales/zh/fetcher.js +13 -3
  25. package/dist/src/lib/i18n/locales/zh/index.js +2 -0
  26. package/dist/src/lib/i18n/locales/zh/node.js +2 -0
  27. package/dist/src/lib/i18n/logger.js +2 -2
  28. package/dist/src/lib/logger.js +38 -17
  29. package/dist/src/lib/server/browser.js +2 -2
  30. package/dist/src/lib/server/fetcher.js +0 -3
  31. package/dist/src/lib/server/index.js +2 -2
  32. package/dist/src/lib/server/prompts.js +4 -4
  33. package/dist/src/lib/server/tools.js +127 -354
  34. package/dist/src/lib/utils/ChunkManager.js +2 -2
  35. package/dist/src/lib/utils/ContentExtractor.js +141 -0
  36. package/dist/src/lib/utils/ContentProcessor.js +5 -11
  37. package/dist/src/lib/utils/ContentSizeManager.js +2 -2
  38. package/dist/src/lib/utils/ErrorHandler.js +1 -0
  39. package/dist/src/lib/utils/TemplateUtils.js +6 -2
  40. package/dist/tests/client.test.js +1 -1
  41. package/dist/tests/test-extract-single.js +389 -0
  42. package/dist/tests/utils/ContentExtractor.test.js +173 -0
  43. package/dist/tests/utils/ContentProcessor.test.js +136 -0
  44. package/dist/tests/utils/TemplateUtils.test.js +118 -0
  45. package/package.json +14 -3
  46. package/dist/i18n-test-report.json +0 -8
  47. package/dist/i18n-unused-keys-report.json +0 -8
  48. package/dist/src/lib/BrowserFetcher.js +0 -787
  49. package/dist/src/lib/NodeFetcher.js +0 -492
  50. package/dist/src/lib/i18n/keys.js +0 -529
  51. package/dist/src/test-i18n.js +0 -139
  52. package/dist/tests/BrowserFetcher.test.js +0 -951
  53. package/dist/tests/NodeFetcher.test.js +0 -263
  54. package/dist/tests/i18n-remove-unused-keys.js +0 -236
  55. package/dist/tests/i18n-test-report.json +0 -2004
  56. package/dist/tests/src/lib/i18n/index.js +0 -108
  57. package/dist/tests/src/lib/i18n/keys/base.js +0 -47
  58. package/dist/tests/src/lib/i18n/keys/browser.js +0 -93
  59. package/dist/tests/src/lib/i18n/keys/client.js +0 -70
  60. package/dist/tests/src/lib/i18n/keys/errors.js +0 -34
  61. package/dist/tests/src/lib/i18n/keys/fetcher.js +0 -84
  62. package/dist/tests/src/lib/i18n/keys/index.js +0 -31
  63. package/dist/tests/src/lib/i18n/keys/node.js +0 -56
  64. package/dist/tests/src/lib/i18n/keys/prompts.js +0 -82
  65. package/dist/tests/src/lib/i18n/keys/resources.js +0 -50
  66. package/dist/tests/src/lib/i18n/keys/server.js +0 -64
  67. package/dist/tests/src/lib/i18n/keys/tools.js +0 -34
  68. package/dist/tests/src/lib/i18n/locales/en/browser.js +0 -88
  69. package/dist/tests/src/lib/i18n/locales/en/client.js +0 -66
  70. package/dist/tests/src/lib/i18n/locales/en/errors.js +0 -28
  71. package/dist/tests/src/lib/i18n/locales/en/fetcher.js +0 -71
  72. package/dist/tests/src/lib/i18n/locales/en/index.js +0 -29
  73. package/dist/tests/src/lib/i18n/locales/en/node.js +0 -51
  74. package/dist/tests/src/lib/i18n/locales/en/prompts.js +0 -52
  75. package/dist/tests/src/lib/i18n/locales/en/resources.js +0 -50
  76. package/dist/tests/src/lib/i18n/locales/en/server.js +0 -56
  77. package/dist/tests/src/lib/i18n/locales/en/tools.js +0 -28
  78. package/dist/tests/src/lib/i18n/locales/zh/browser.js +0 -87
  79. package/dist/tests/src/lib/i18n/locales/zh/client.js +0 -66
  80. package/dist/tests/src/lib/i18n/locales/zh/errors.js +0 -28
  81. package/dist/tests/src/lib/i18n/locales/zh/fetcher.js +0 -71
  82. package/dist/tests/src/lib/i18n/locales/zh/index.js +0 -29
  83. package/dist/tests/src/lib/i18n/locales/zh/node.js +0 -51
  84. package/dist/tests/src/lib/i18n/locales/zh/prompts.js +0 -53
  85. package/dist/tests/src/lib/i18n/locales/zh/resources.js +0 -50
  86. package/dist/tests/src/lib/i18n/locales/zh/server.js +0 -57
  87. package/dist/tests/src/lib/i18n/locales/zh/tools.js +0 -28
  88. package/dist/tests/src/lib/i18n/logger.js +0 -114
  89. package/dist/tests/src/lib/logger.js +0 -181
  90. package/dist/tests/tests/test-i18n.js +0 -588
  91. package/dist/vitest.config.js +0 -29
@@ -1,492 +0,0 @@
1
- /**
2
- * Author: Martin <lmccc.dev@gmail.com>
3
- * Co-Author: AI Assistant (Claude)
4
- * Description: This code was collaboratively developed by Martin and AI Assistant.
5
- */
6
- import TurndownService from "turndown";
7
- import fetch from "node-fetch";
8
- import { HttpProxyAgent } from "http-proxy-agent";
9
- import { HttpsProxyAgent } from "https-proxy-agent";
10
- import { execSync } from 'child_process';
11
- import { log, COMPONENTS } from './logger.js';
12
- export class NodeFetcher {
13
- /**
14
- * 常用浏览器的User-Agent列表 (List of common browser User-Agents)
15
- * 用于模拟不同浏览器的请求 (Used to simulate requests from different browsers)
16
- */
17
- static userAgents = [
18
- // Chrome
19
- 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
20
- 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
21
- // Firefox
22
- 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0',
23
- 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:89.0) Gecko/20100101 Firefox/89.0',
24
- // Safari
25
- 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15',
26
- // Edge
27
- 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.59'
28
- ];
29
- /**
30
- * 获取随机User-Agent (Get random User-Agent)
31
- * @returns 随机的User-Agent字符串 (Random User-Agent string)
32
- */
33
- static getRandomUserAgent() {
34
- const index = Math.floor(Math.random() * this.userAgents.length);
35
- return this.userAgents[index];
36
- }
37
- /**
38
- * 随机延迟函数 (Random delay function)
39
- * 模拟人类行为,避免被检测为机器人 (Simulate human behavior, avoid being detected as a bot)
40
- * @param minMs 最小延迟毫秒数 (Minimum delay in milliseconds)
41
- * @param maxMs 最大延迟毫秒数 (Maximum delay in milliseconds)
42
- * @returns Promise对象 (Promise object)
43
- */
44
- static async randomDelay(minMs = 500, maxMs = 3000) {
45
- const delay = Math.floor(Math.random() * (maxMs - minMs + 1)) + minMs;
46
- return new Promise(resolve => setTimeout(resolve, delay));
47
- }
48
- /**
49
- * 获取系统代理设置 (Get system proxy settings)
50
- * @param useSystemProxy 是否使用系统代理 (Whether to use system proxy)
51
- * @returns 代理URL或undefined (Proxy URL or undefined)
52
- */
53
- static getSystemProxy(useSystemProxy = true) {
54
- if (!useSystemProxy) {
55
- return undefined;
56
- }
57
- // 检查环境变量 (Check environment variables)
58
- log('node.checkingProxyEnv', true, {}, COMPONENTS.NODE_FETCH);
59
- const envVars = ['https_proxy', 'HTTPS_PROXY', 'http_proxy', 'HTTP_PROXY'];
60
- for (const envVar of envVars) {
61
- log('node.envVarValue', true, {
62
- envVar,
63
- value: process.env[envVar]
64
- }, COMPONENTS.NODE_FETCH);
65
- if (process.env[envVar]) {
66
- const proxyUrl = process.env[envVar];
67
- log('node.foundSystemProxy', true, { proxy: proxyUrl }, COMPONENTS.NODE_FETCH);
68
- return proxyUrl;
69
- }
70
- }
71
- // 尝试使用系统命令获取环境变量 (Try to get environment variables using system commands)
72
- try {
73
- const platform = process.platform;
74
- let proxyUrl;
75
- log('node.checkingSystemEnvVars', true, { platform }, COMPONENTS.NODE_FETCH);
76
- if (platform === 'win32') {
77
- // Windows系统 - 使用set命令 (Windows - use set command)
78
- try {
79
- // 使用set命令获取代理环境变量 (Use set command to get proxy environment variables)
80
- const setOutput = execSync('set http_proxy & set https_proxy & set HTTP_PROXY & set HTTPS_PROXY').toString();
81
- log('node.windowsEnvVars', true, { output: setOutput.trim() }, COMPONENTS.NODE_FETCH);
82
- // 解析输出找到代理设置 (Parse output to find proxy settings)
83
- const proxyMatch = setOutput.match(/(?:http_proxy|https_proxy|HTTP_PROXY|HTTPS_PROXY)=(https?:\/\/[^=\r\n]+)/i);
84
- if (proxyMatch && proxyMatch[1]) {
85
- proxyUrl = proxyMatch[1].trim();
86
- log('node.foundWindowsEnvProxy', true, { proxy: proxyUrl }, COMPONENTS.NODE_FETCH);
87
- }
88
- }
89
- catch (winError) {
90
- log('node.errorGettingWindowsEnvVars', true, { error: String(winError) }, COMPONENTS.NODE_FETCH);
91
- }
92
- }
93
- else {
94
- // Unix系统 (macOS/Linux) - 使用export或env命令 (Unix systems - use export or env command)
95
- try {
96
- // 使用env命令获取所有环境变量 (Use env command to get all environment variables)
97
- const envOutput = execSync('env').toString();
98
- log('node.unixEnvVars', true, { output: envOutput.length > 200 ? envOutput.substring(0, 200) + '...' : envOutput }, COMPONENTS.NODE_FETCH);
99
- // 解析输出找到代理设置 (Parse output to find proxy settings)
100
- const proxyMatch = envOutput.match(/(?:http_proxy|https_proxy|HTTP_PROXY|HTTPS_PROXY)=(https?:\/\/[^=\n]+)/i);
101
- if (proxyMatch && proxyMatch[1]) {
102
- proxyUrl = proxyMatch[1].trim();
103
- log('node.foundUnixEnvProxy', true, { proxy: proxyUrl }, COMPONENTS.NODE_FETCH);
104
- }
105
- }
106
- catch (unixError) {
107
- log('node.errorGettingUnixEnvVars', true, { error: String(unixError) }, COMPONENTS.NODE_FETCH);
108
- }
109
- }
110
- if (proxyUrl) {
111
- return proxyUrl;
112
- }
113
- // 如果没有找到代理,记录日志 (If no proxy is found, log a message)
114
- log('node.noSystemProxyFound', true, {}, COMPONENTS.NODE_FETCH);
115
- }
116
- catch (error) {
117
- log('node.errorGettingSystemEnvVars', true, { error: String(error) }, COMPONENTS.NODE_FETCH);
118
- }
119
- // 检查NO_PROXY环境变量 (Check NO_PROXY environment variable)
120
- const noProxy = process.env.NO_PROXY || process.env.no_proxy;
121
- if (noProxy) {
122
- log('node.foundNoProxy', true, { noProxy }, COMPONENTS.NODE_FETCH);
123
- }
124
- return undefined;
125
- }
126
- /**
127
- * 处理请求延迟 (Handle request delay)
128
- * @param noDelay 是否禁用延迟 (Whether to disable delay)
129
- * @param isRedirect 是否是重定向请求 (Whether it's a redirect request)
130
- * @param debug 是否启用调试模式 (Whether debug mode is enabled)
131
- */
132
- static async handleDelay(noDelay, isRedirect, debug) {
133
- if (!noDelay && isRedirect) {
134
- await this.randomDelay();
135
- }
136
- }
137
- /**
138
- * 准备请求头 (Prepare request headers)
139
- * @param headers 原始请求头 (Original headers)
140
- * @param debug 是否启用调试模式 (Whether debug mode is enabled)
141
- * @returns 处理后的请求头 (Processed headers)
142
- */
143
- static prepareHeaders(headers = {}, debug) {
144
- const requestHeaders = { ...headers };
145
- // 添加随机User-Agent (Add random User-Agent)
146
- if (!requestHeaders['User-Agent']) {
147
- const userAgent = this.getRandomUserAgent();
148
- requestHeaders['User-Agent'] = userAgent;
149
- log('node.usingUserAgent', debug, { userAgent }, COMPONENTS.NODE_FETCH);
150
- }
151
- return requestHeaders;
152
- }
153
- /**
154
- * 设置代理 (Set proxy)
155
- * @param url 请求URL (Request URL)
156
- * @param proxy 代理URL (Proxy URL)
157
- * @param debug 是否启用调试模式 (Whether debug mode is enabled)
158
- * @returns 代理Agent (Proxy agent)
159
- */
160
- static setupProxy(url, proxy, debug) {
161
- if (!proxy)
162
- return undefined;
163
- let agent = undefined;
164
- if (url.startsWith('https://')) {
165
- agent = new HttpsProxyAgent(proxy);
166
- log('node.usingHttpsProxy', debug, {}, COMPONENTS.NODE_FETCH);
167
- }
168
- else {
169
- agent = new HttpProxyAgent(proxy);
170
- log('node.usingHttpProxy', debug, {}, COMPONENTS.NODE_FETCH);
171
- }
172
- return agent;
173
- }
174
- /**
175
- * 处理重定向URL (Handle redirect URL)
176
- * @param location 重定向位置 (Redirect location)
177
- * @param currentUrl 当前URL (Current URL)
178
- * @param debug 是否启用调试模式 (Whether debug mode is enabled)
179
- * @returns 完整的重定向URL (Complete redirect URL)
180
- */
181
- static buildRedirectUrl(location, currentUrl, debug) {
182
- let redirectUrl = location;
183
- if (location.startsWith('/')) {
184
- const urlObj = new URL(currentUrl);
185
- redirectUrl = `${urlObj.protocol}//${urlObj.host}${location}`;
186
- }
187
- else if (!location.startsWith('http')) {
188
- redirectUrl = new URL(location, currentUrl).toString();
189
- }
190
- log('node.constructedFullRedirectUrl', debug, { redirectUrl }, COMPONENTS.NODE_FETCH);
191
- return redirectUrl;
192
- }
193
- /**
194
- * 处理错误响应 (Handle error response)
195
- * @param response 响应对象 (Response object)
196
- * @param debug 是否启用调试模式 (Whether debug mode is enabled)
197
- * @returns Promise<never> 抛出错误 (Throws error)
198
- */
199
- static async handleErrorResponse(response, debug) {
200
- log('node.errorResponse', debug, { status: response.status, statusText: response.statusText }, COMPONENTS.NODE_FETCH);
201
- // 尝试读取错误响应体 (Try to read error response body)
202
- let errorText = '';
203
- try {
204
- errorText = await response.text();
205
- log('node.errorResponseBody', debug, { body: errorText.substring(0, 200) + (errorText.length > 200 ? '...' : '') }, COMPONENTS.NODE_FETCH);
206
- }
207
- catch (textError) {
208
- log('node.errorReadingBody', debug, { error: String(textError) }, COMPONENTS.NODE_FETCH);
209
- }
210
- // 创建错误对象 (Create error object)
211
- const error = new Error(`HTTP Error ${response.status}: ${response.statusText}`);
212
- error.status = response.status;
213
- error.statusText = response.statusText;
214
- error.body = errorText;
215
- throw error;
216
- }
217
- /**
218
- * 处理请求错误 (Handle request error)
219
- * @param error 错误对象 (Error object)
220
- * @param fetchStart 请求开始时间 (Request start time)
221
- * @param timeout 超时时间 (Timeout)
222
- * @param redirectCount 重定向计数 (Redirect count)
223
- * @param maxRedirects 最大重定向次数 (Maximum redirects)
224
- * @param debug 是否启用调试模式 (Whether debug mode is enabled)
225
- * @returns Promise<never> 抛出错误 (Throws error)
226
- */
227
- static handleRequestError(error, fetchStart, timeout, redirectCount, maxRedirects, debug) {
228
- // 记录错误 (Log error)
229
- log('node.fetchError', debug, { error: String(error) }, COMPONENTS.NODE_FETCH);
230
- // 处理超时错误 (Handle timeout error)
231
- if (error.name === 'AbortError') {
232
- log('node.requestAborted', debug, { duration: Date.now() - fetchStart }, COMPONENTS.NODE_FETCH);
233
- const timeoutError = new Error(`Request timeout after ${timeout}ms`);
234
- timeoutError.code = 'ETIMEDOUT';
235
- timeoutError.timeout = timeout;
236
- throw timeoutError;
237
- }
238
- // 处理网络错误 (Handle network error)
239
- if (error.code) {
240
- log('node.networkError', debug, { code: error.code || error.name }, COMPONENTS.NODE_FETCH);
241
- const networkError = new Error(`Network error: ${error.code || error.message}`);
242
- networkError.code = error.code;
243
- networkError.originalError = error;
244
- throw networkError;
245
- }
246
- // 处理重定向错误 (Handle redirect error)
247
- if (redirectCount >= maxRedirects) {
248
- log('node.tooManyRedirects', debug, { redirects: maxRedirects }, COMPONENTS.NODE_FETCH);
249
- const redirectError = new Error(`Too many redirects (${maxRedirects})`);
250
- redirectError.code = 'EMAXREDIRECTS';
251
- redirectError.redirects = redirectCount;
252
- throw redirectError;
253
- }
254
- // 重新抛出其他错误 (Rethrow other errors)
255
- throw error;
256
- }
257
- /**
258
- * 执行带重定向处理的HTTP请求 (Execute HTTP request with redirect handling)
259
- * 支持自动处理重定向、超时和代理 (Supports automatic handling of redirects, timeouts, and proxies)
260
- */
261
- static async _fetchWithRedirects({ url, headers = {}, proxy, noDelay, timeout = 30000, // 默认30秒超时
262
- maxRedirects = 10, // 最大重定向次数
263
- useSystemProxy = true, // 是否使用系统代理
264
- debug = false, // 是否启用调试模式
265
- }) {
266
- log('node.fetchingUrl', debug, { url }, COMPONENTS.NODE_FETCH);
267
- // 处理代理设置 (Handle proxy settings)
268
- const systemProxy = this.getSystemProxy(useSystemProxy);
269
- const finalProxy = proxy || systemProxy;
270
- if (finalProxy) {
271
- log('node.usingProxy', debug, { proxy: finalProxy }, COMPONENTS.NODE_FETCH);
272
- }
273
- // 初始化重定向计数器 (Initialize redirect counter)
274
- let redirectCount = 0;
275
- let currentUrl = url;
276
- // 记录请求开始时间 (Record request start time)
277
- const fetchStart = Date.now();
278
- // 创建AbortController用于超时控制 (Create AbortController for timeout control)
279
- const controller = new AbortController();
280
- const timeoutId = setTimeout(() => controller.abort(), timeout);
281
- try {
282
- // 处理重定向循环 (Handle redirect loop)
283
- while (redirectCount < maxRedirects) {
284
- log('node.fetchingUrl', debug, { url: currentUrl, redirect: redirectCount }, COMPONENTS.NODE_FETCH);
285
- // 处理延迟 (Handle delay)
286
- await this.handleDelay(noDelay, redirectCount > 0, debug);
287
- // 准备请求头 (Prepare request headers)
288
- const requestHeaders = this.prepareHeaders(headers, debug);
289
- // 设置代理 (Set proxy)
290
- const agent = this.setupProxy(currentUrl, finalProxy, debug);
291
- // 准备请求选项 (Prepare request options)
292
- const fetchOptions = {
293
- method: 'GET',
294
- headers: requestHeaders,
295
- timeout,
296
- signal: controller.signal,
297
- };
298
- if (agent) {
299
- fetchOptions.agent = agent;
300
- }
301
- // 记录请求详情 (Log request details)
302
- log('node.requestDetails', debug, {
303
- url: currentUrl,
304
- method: fetchOptions.method || 'GET',
305
- headers: requestHeaders,
306
- proxy: finalProxy,
307
- timeout,
308
- }, COMPONENTS.NODE_FETCH);
309
- // 执行请求 (Execute request)
310
- const response = await fetch(currentUrl, fetchOptions);
311
- // 记录响应状态 (Log response status)
312
- log('node.responseStatus', debug, {
313
- status: response.status,
314
- statusText: response.statusText,
315
- headers: Object.fromEntries(response.headers.entries()),
316
- }, COMPONENTS.NODE_FETCH);
317
- // 处理重定向 (Handle redirects)
318
- if (response.status >= 300 && response.status < 400 && response.headers.has('location')) {
319
- redirectCount++;
320
- // 获取重定向URL (Get redirect URL)
321
- const location = response.headers.get('location');
322
- log('node.redirectingTo', debug, { location }, COMPONENTS.NODE_FETCH);
323
- // 构建完整的重定向URL (Build complete redirect URL)
324
- currentUrl = this.buildRedirectUrl(location, currentUrl, debug);
325
- continue;
326
- }
327
- // 如果响应成功,返回响应 (If response is successful, return response)
328
- if (response.ok) {
329
- log('node.requestSuccess', debug, {}, COMPONENTS.NODE_FETCH);
330
- return response;
331
- }
332
- else {
333
- // 处理错误响应 (Handle error response)
334
- return await this.handleErrorResponse(response, debug);
335
- }
336
- }
337
- // 如果达到最大重定向次数,抛出错误 (If maximum redirects reached, throw error)
338
- throw new Error(`Too many redirects (${maxRedirects})`);
339
- }
340
- catch (error) {
341
- // 处理请求错误 (Handle request error)
342
- this.handleRequestError(error, fetchStart, timeout, redirectCount, maxRedirects, debug);
343
- }
344
- finally {
345
- // 清除超时定时器 (Clear timeout timer)
346
- clearTimeout(timeoutId);
347
- }
348
- }
349
- /**
350
- * 获取HTML内容 (Get HTML content)
351
- * @param requestPayload 请求参数 (Request parameters)
352
- * @returns HTML内容 (HTML content)
353
- */
354
- static async html(requestPayload) {
355
- const { debug = false } = requestPayload;
356
- log('node.startingHtmlFetch', debug, {}, COMPONENTS.NODE_FETCH);
357
- try {
358
- // 执行请求 (Execute request)
359
- const response = await this._fetchWithRedirects(requestPayload);
360
- // 读取响应文本 (Read response text)
361
- log('node.readingText', debug, {}, COMPONENTS.NODE_FETCH);
362
- const html = await response.text();
363
- log('node.htmlContentLength', debug, { length: html.length }, COMPONENTS.NODE_FETCH);
364
- // 返回HTML内容 (Return HTML content)
365
- return {
366
- html,
367
- url: response.url,
368
- status: response.status,
369
- headers: Object.fromEntries(response.headers.entries()),
370
- };
371
- }
372
- catch (error) {
373
- // 处理错误 (Handle error)
374
- log('node.htmlFetchError', debug, { error: error instanceof Error ? error.message : String(error) }, COMPONENTS.NODE_FETCH);
375
- // 重新抛出错误 (Rethrow error)
376
- throw error;
377
- }
378
- }
379
- /**
380
- * 获取JSON内容 (Get JSON content)
381
- * @param requestPayload 请求参数 (Request parameters)
382
- * @returns JSON内容 (JSON content)
383
- */
384
- static async json(requestPayload) {
385
- const { debug = false } = requestPayload;
386
- log('node.startingJsonFetch', debug, {}, COMPONENTS.NODE_FETCH);
387
- try {
388
- // 执行请求 (Execute request)
389
- const response = await this._fetchWithRedirects(requestPayload);
390
- // 读取响应文本 (Read response text)
391
- const text = await response.text();
392
- // 解析JSON (Parse JSON)
393
- log('node.parsingJson', debug, {}, COMPONENTS.NODE_FETCH);
394
- let json;
395
- try {
396
- json = JSON.parse(text);
397
- log('node.jsonParsed', debug, {}, COMPONENTS.NODE_FETCH);
398
- }
399
- catch (parseError) {
400
- // 处理JSON解析错误 (Handle JSON parse error)
401
- const textPreview = text.length > 100 ? `${text.substring(0, 100)}...` : text;
402
- const error = new Error(`Invalid JSON: ${parseError instanceof Error ? parseError.message : String(parseError)}. Text preview: "${textPreview}", length: ${text.length}`);
403
- error.text = text;
404
- error.originalError = parseError;
405
- log('fetcher.jsonParseError', debug, {
406
- error: String(parseError),
407
- textPreview,
408
- textLength: text.length
409
- }, COMPONENTS.NODE_FETCH);
410
- throw error;
411
- }
412
- // 返回JSON内容 (Return JSON content)
413
- return {
414
- json,
415
- text,
416
- url: response.url,
417
- status: response.status,
418
- headers: Object.fromEntries(response.headers.entries()),
419
- };
420
- }
421
- catch (error) {
422
- // 处理错误 (Handle error)
423
- log('node.jsonFetchError', debug, { error: error instanceof Error ? error.message : String(error) }, COMPONENTS.NODE_FETCH);
424
- // 重新抛出错误 (Rethrow error)
425
- throw error;
426
- }
427
- }
428
- /**
429
- * 获取纯文本内容 (Get plain text content)
430
- * @param requestPayload 请求参数 (Request parameters)
431
- * @returns 纯文本内容 (Plain text content)
432
- */
433
- static async txt(requestPayload) {
434
- const { debug = false } = requestPayload;
435
- log('node.startingTxtFetch', debug, {}, COMPONENTS.NODE_FETCH);
436
- try {
437
- // 执行请求 (Execute request)
438
- const response = await this._fetchWithRedirects(requestPayload);
439
- // 读取响应文本 (Read response text)
440
- log('node.readingText', debug, {}, COMPONENTS.NODE_FETCH);
441
- const text = await response.text();
442
- log('node.textContentLength', debug, { length: text.length }, COMPONENTS.NODE_FETCH);
443
- // 返回纯文本内容 (Return plain text content)
444
- return {
445
- text,
446
- url: response.url,
447
- status: response.status,
448
- headers: Object.fromEntries(response.headers.entries()),
449
- };
450
- }
451
- catch (error) {
452
- // 重新抛出错误 (Rethrow error)
453
- throw error;
454
- }
455
- }
456
- /**
457
- * 获取Markdown内容 (Get Markdown content)
458
- * @param requestPayload 请求参数 (Request parameters)
459
- * @returns Markdown内容 (Markdown content)
460
- */
461
- static async markdown(requestPayload) {
462
- const { debug = false } = requestPayload;
463
- log('node.startingMarkdownFetch', debug, {}, COMPONENTS.NODE_FETCH);
464
- try {
465
- // 执行请求 (Execute request)
466
- const response = await this._fetchWithRedirects(requestPayload);
467
- // 读取响应文本 (Read response text)
468
- log('node.readingText', debug, {}, COMPONENTS.NODE_FETCH);
469
- const html = await response.text();
470
- log('node.htmlContentLength', debug, { length: html.length }, COMPONENTS.NODE_FETCH);
471
- // 创建Turndown服务 (Create Turndown service)
472
- log('node.creatingTurndown', debug, {}, COMPONENTS.NODE_FETCH);
473
- const turndownService = new TurndownService();
474
- // 将HTML转换为Markdown (Convert HTML to Markdown)
475
- log('node.convertingToMarkdown', debug, {}, COMPONENTS.NODE_FETCH);
476
- const markdown = turndownService.turndown(html);
477
- log('node.markdownContentLength', debug, { length: markdown.length }, COMPONENTS.NODE_FETCH);
478
- // 返回Markdown内容 (Return Markdown content)
479
- return {
480
- markdown,
481
- html,
482
- url: response.url,
483
- status: response.status,
484
- headers: Object.fromEntries(response.headers.entries()),
485
- };
486
- }
487
- catch (error) {
488
- // 重新抛出错误 (Rethrow error)
489
- throw error;
490
- }
491
- }
492
- }