@lmcc-dev/mult-fetch-mcp-server 1.1.0 → 1.2.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 (216) hide show
  1. package/README.md +8 -8
  2. package/README.zh.md +16 -8
  3. package/dist/i18n-test-report.json +8 -0
  4. package/dist/i18n-unused-keys-report.json +8 -0
  5. package/dist/src/client.js +50 -35
  6. package/dist/src/index.js +0 -0
  7. package/dist/src/lib/BrowserFetcher.js +12 -12
  8. package/dist/src/lib/NodeFetcher.js +22 -22
  9. package/dist/src/lib/fetch.js +40 -0
  10. package/dist/src/lib/fetchers/FetcherFactory.js +43 -0
  11. package/dist/src/lib/fetchers/browser/BrowserFetcher.js +381 -0
  12. package/dist/src/lib/fetchers/browser/BrowserInstance.js +180 -0
  13. package/dist/src/lib/fetchers/browser/PageOperations.js +168 -0
  14. package/dist/src/lib/fetchers/common/types.js +41 -0
  15. package/dist/src/lib/fetchers/common/utils.js +141 -0
  16. package/dist/src/lib/fetchers/index.js +62 -0
  17. package/dist/src/lib/fetchers/node/HttpClient.js +239 -0
  18. package/dist/src/lib/fetchers/node/NodeFetcher.js +180 -0
  19. package/dist/src/lib/i18n/index.js +105 -17
  20. package/dist/src/lib/i18n/keys/base.js +41 -0
  21. package/dist/src/lib/i18n/keys/browser.js +91 -0
  22. package/dist/src/lib/i18n/keys/client.js +68 -0
  23. package/dist/src/lib/i18n/keys/errors.js +49 -0
  24. package/dist/src/lib/i18n/keys/factory.js +46 -0
  25. package/dist/src/lib/i18n/keys/fetcher.js +87 -0
  26. package/dist/src/lib/i18n/keys/index.js +16 -0
  27. package/dist/src/lib/i18n/keys/node.js +69 -0
  28. package/dist/src/lib/i18n/keys/prompts.js +79 -0
  29. package/dist/src/lib/i18n/keys/resources.js +53 -0
  30. package/dist/src/lib/i18n/keys/server.js +67 -0
  31. package/dist/src/lib/i18n/keys/tools.js +39 -0
  32. package/dist/src/lib/i18n/keys.js +488 -119
  33. package/dist/src/lib/i18n/locales/en/browser.js +67 -57
  34. package/dist/src/lib/i18n/locales/en/client.js +57 -33
  35. package/dist/src/lib/i18n/locales/en/errors.js +36 -12
  36. package/dist/src/lib/i18n/locales/en/factory.js +38 -0
  37. package/dist/src/lib/i18n/locales/en/fetcher.js +8 -2
  38. package/dist/src/lib/i18n/locales/en/index.js +10 -8
  39. package/dist/src/lib/i18n/locales/en/node.js +57 -35
  40. package/dist/src/lib/i18n/locales/en/prompts.js +42 -65
  41. package/dist/src/lib/i18n/locales/en/resources.js +52 -55
  42. package/dist/src/lib/i18n/locales/en/server.js +49 -24
  43. package/dist/src/lib/i18n/locales/en/tools.js +27 -19
  44. package/dist/src/lib/i18n/locales/zh/browser.js +71 -62
  45. package/dist/src/lib/i18n/locales/zh/client.js +57 -32
  46. package/dist/src/lib/i18n/locales/zh/errors.js +36 -12
  47. package/dist/src/lib/i18n/locales/zh/factory.js +38 -0
  48. package/dist/src/lib/i18n/locales/zh/fetcher.js +36 -30
  49. package/dist/src/lib/i18n/locales/zh/index.js +10 -8
  50. package/dist/src/lib/i18n/locales/zh/node.js +61 -36
  51. package/dist/src/lib/i18n/locales/zh/prompts.js +35 -57
  52. package/dist/src/lib/i18n/locales/zh/resources.js +52 -55
  53. package/dist/src/lib/i18n/locales/zh/server.js +51 -25
  54. package/dist/src/lib/i18n/locales/zh/tools.js +27 -19
  55. package/dist/src/lib/i18n/logger.js +90 -19
  56. package/dist/src/lib/logger.js +135 -14
  57. package/dist/src/lib/server/browser.js +2 -2
  58. package/dist/src/lib/server/fetcher.js +13 -34
  59. package/dist/src/lib/server/index.js +2 -2
  60. package/dist/src/lib/server/prompts.js +1 -1
  61. package/dist/src/lib/server/resources.js +1 -1
  62. package/dist/src/lib/server/tools.js +46 -10
  63. package/dist/src/lib/utils/ErrorHandler.js +125 -0
  64. package/dist/src/mcp-server.js +0 -0
  65. package/dist/src/test-i18n.js +139 -0
  66. package/dist/tests/BrowserFetcher.test.js +0 -0
  67. package/dist/tests/NodeFetcher.test.js +0 -0
  68. package/dist/tests/client.test.js +42 -81
  69. package/dist/tests/fetch.test.js +70 -0
  70. package/dist/tests/fetchers/Fetcher.test.js +108 -0
  71. package/dist/tests/fetchers/browser/BrowserFetcher.test.js +195 -0
  72. package/dist/tests/fetchers/browser/BrowserInstance.test.js +163 -0
  73. package/dist/tests/fetchers/node/NodeFetcher.test.js +211 -0
  74. package/dist/tests/i18n-missing-keys.js +364 -0
  75. package/dist/tests/i18n-remove-unused-keys.js +236 -0
  76. package/dist/tests/i18n-test-report.json +2004 -0
  77. package/dist/tests/i18n-unused-keys.js +425 -0
  78. package/dist/tests/i18n.test.js +6 -7
  79. package/dist/tests/logger.test.js +14 -13
  80. package/dist/tests/mcp-server.test.js +7 -7
  81. package/dist/tests/server/browser.test.js +25 -21
  82. package/dist/tests/server/fetcher.test.js +58 -101
  83. package/dist/tests/server/index.test.js +30 -30
  84. package/dist/tests/server/prompts.test.js +36 -33
  85. package/dist/tests/server/resources.test.js +120 -84
  86. package/dist/tests/server/tools.test.js +7 -6
  87. package/dist/tests/setup.js +36 -0
  88. package/dist/tests/src/lib/i18n/index.js +108 -0
  89. package/dist/tests/src/lib/i18n/keys/base.js +47 -0
  90. package/dist/tests/src/lib/i18n/keys/browser.js +93 -0
  91. package/dist/tests/src/lib/i18n/keys/client.js +70 -0
  92. package/dist/tests/src/lib/i18n/keys/errors.js +34 -0
  93. package/dist/tests/src/lib/i18n/keys/fetcher.js +84 -0
  94. package/dist/tests/src/lib/i18n/keys/index.js +31 -0
  95. package/dist/tests/src/lib/i18n/keys/node.js +56 -0
  96. package/dist/tests/src/lib/i18n/keys/prompts.js +82 -0
  97. package/dist/tests/src/lib/i18n/keys/resources.js +50 -0
  98. package/dist/tests/src/lib/i18n/keys/server.js +64 -0
  99. package/dist/tests/src/lib/i18n/keys/tools.js +34 -0
  100. package/dist/tests/src/lib/i18n/locales/en/browser.js +88 -0
  101. package/dist/tests/src/lib/i18n/locales/en/client.js +66 -0
  102. package/dist/tests/src/lib/i18n/locales/en/errors.js +28 -0
  103. package/dist/tests/src/lib/i18n/locales/en/fetcher.js +71 -0
  104. package/dist/tests/src/lib/i18n/locales/en/index.js +29 -0
  105. package/dist/tests/src/lib/i18n/locales/en/node.js +51 -0
  106. package/dist/tests/src/lib/i18n/locales/en/prompts.js +52 -0
  107. package/dist/tests/src/lib/i18n/locales/en/resources.js +50 -0
  108. package/dist/tests/src/lib/i18n/locales/en/server.js +56 -0
  109. package/dist/tests/src/lib/i18n/locales/en/tools.js +28 -0
  110. package/dist/tests/src/lib/i18n/locales/zh/browser.js +87 -0
  111. package/dist/tests/src/lib/i18n/locales/zh/client.js +66 -0
  112. package/dist/tests/src/lib/i18n/locales/zh/errors.js +28 -0
  113. package/dist/tests/src/lib/i18n/locales/zh/fetcher.js +71 -0
  114. package/dist/tests/src/lib/i18n/locales/zh/index.js +29 -0
  115. package/dist/tests/src/lib/i18n/locales/zh/node.js +51 -0
  116. package/dist/tests/src/lib/i18n/locales/zh/prompts.js +53 -0
  117. package/dist/tests/src/lib/i18n/locales/zh/resources.js +50 -0
  118. package/dist/tests/src/lib/i18n/locales/zh/server.js +57 -0
  119. package/dist/tests/src/lib/i18n/locales/zh/tools.js +28 -0
  120. package/dist/tests/src/lib/i18n/logger.js +114 -0
  121. package/dist/tests/src/lib/logger.js +181 -0
  122. package/dist/tests/test-direct-client.js +0 -0
  123. package/dist/tests/test-i18n.js +530 -0
  124. package/dist/tests/test-mcp-methods.js +1 -1
  125. package/dist/tests/test-mcp.js +0 -0
  126. package/dist/tests/test-mini4k.js +0 -0
  127. package/dist/tests/tests/test-i18n.js +588 -0
  128. package/dist/tests/types.test.js +1 -1
  129. package/dist/tests/utils/ErrorHandler.test.js +144 -0
  130. package/dist/vitest.config.js +29 -0
  131. package/package.json +31 -27
  132. package/dist/src/cli-language.js +0 -78
  133. package/dist/src/client.d.ts +0 -6
  134. package/dist/src/client.js.map +0 -1
  135. package/dist/src/index.d.ts +0 -15
  136. package/dist/src/index.js.map +0 -1
  137. package/dist/src/lib/BrowserFetcher.d.ts +0 -175
  138. package/dist/src/lib/BrowserFetcher.js.map +0 -1
  139. package/dist/src/lib/NodeFetcher.d.ts +0 -92
  140. package/dist/src/lib/NodeFetcher.js.map +0 -1
  141. package/dist/src/lib/example.js +0 -93
  142. package/dist/src/lib/i18n/index.js.map +0 -1
  143. package/dist/src/lib/i18n/locales/en/browser.d.ts +0 -61
  144. package/dist/src/lib/i18n/locales/en/browser.js.map +0 -1
  145. package/dist/src/lib/i18n/locales/en/client.d.ts +0 -39
  146. package/dist/src/lib/i18n/locales/en/client.js.map +0 -1
  147. package/dist/src/lib/i18n/locales/en/errors.d.ts +0 -17
  148. package/dist/src/lib/i18n/locales/en/errors.js.map +0 -1
  149. package/dist/src/lib/i18n/locales/en/fetcher.d.ts +0 -66
  150. package/dist/src/lib/i18n/locales/en/fetcher.js.map +0 -1
  151. package/dist/src/lib/i18n/locales/en/index.d.ts +0 -344
  152. package/dist/src/lib/i18n/locales/en/index.js.map +0 -1
  153. package/dist/src/lib/i18n/locales/en/node.d.ts +0 -41
  154. package/dist/src/lib/i18n/locales/en/node.js.map +0 -1
  155. package/dist/src/lib/i18n/locales/en/prompts.d.ts +0 -65
  156. package/dist/src/lib/i18n/locales/en/prompts.js.map +0 -1
  157. package/dist/src/lib/i18n/locales/en/resources.d.ts +0 -41
  158. package/dist/src/lib/i18n/locales/en/resources.js.map +0 -1
  159. package/dist/src/lib/i18n/locales/en/server.d.ts +0 -30
  160. package/dist/src/lib/i18n/locales/en/server.js.map +0 -1
  161. package/dist/src/lib/i18n/locales/en/tools.d.ts +0 -24
  162. package/dist/src/lib/i18n/locales/en/tools.js.map +0 -1
  163. package/dist/src/lib/i18n/locales/zh/browser.d.ts +0 -61
  164. package/dist/src/lib/i18n/locales/zh/browser.js.map +0 -1
  165. package/dist/src/lib/i18n/locales/zh/client.d.ts +0 -38
  166. package/dist/src/lib/i18n/locales/zh/client.js.map +0 -1
  167. package/dist/src/lib/i18n/locales/zh/errors.d.ts +0 -17
  168. package/dist/src/lib/i18n/locales/zh/errors.js.map +0 -1
  169. package/dist/src/lib/i18n/locales/zh/fetcher.d.ts +0 -66
  170. package/dist/src/lib/i18n/locales/zh/fetcher.js.map +0 -1
  171. package/dist/src/lib/i18n/locales/zh/index.d.ts +0 -343
  172. package/dist/src/lib/i18n/locales/zh/index.js.map +0 -1
  173. package/dist/src/lib/i18n/locales/zh/node.d.ts +0 -41
  174. package/dist/src/lib/i18n/locales/zh/node.js.map +0 -1
  175. package/dist/src/lib/i18n/locales/zh/prompts.d.ts +0 -65
  176. package/dist/src/lib/i18n/locales/zh/prompts.js.map +0 -1
  177. package/dist/src/lib/i18n/locales/zh/resources.d.ts +0 -41
  178. package/dist/src/lib/i18n/locales/zh/resources.js.map +0 -1
  179. package/dist/src/lib/i18n/locales/zh/server.d.ts +0 -30
  180. package/dist/src/lib/i18n/locales/zh/server.js.map +0 -1
  181. package/dist/src/lib/i18n/locales/zh/tools.d.ts +0 -24
  182. package/dist/src/lib/i18n/locales/zh/tools.js.map +0 -1
  183. package/dist/src/lib/i18n/logger.d.ts +0 -38
  184. package/dist/src/lib/i18n/logger.js.map +0 -1
  185. package/dist/src/lib/logger.d.ts +0 -32
  186. package/dist/src/lib/logger.js.map +0 -1
  187. package/dist/src/lib/server/browser.d.ts +0 -34
  188. package/dist/src/lib/server/browser.js.map +0 -1
  189. package/dist/src/lib/server/fetcher.d.ts +0 -20
  190. package/dist/src/lib/server/fetcher.js.map +0 -1
  191. package/dist/src/lib/server/index.d.ts +0 -10
  192. package/dist/src/lib/server/index.js.map +0 -1
  193. package/dist/src/lib/server/logger.js +0 -23
  194. package/dist/src/lib/server/prompts.d.ts +0 -11
  195. package/dist/src/lib/server/prompts.js.map +0 -1
  196. package/dist/src/lib/server/resources.d.ts +0 -11
  197. package/dist/src/lib/server/resources.js.map +0 -1
  198. package/dist/src/lib/server/tools.d.ts +0 -12
  199. package/dist/src/lib/server/tools.js.map +0 -1
  200. package/dist/src/lib/server/types.d.ts +0 -71
  201. package/dist/src/lib/server/types.js.map +0 -1
  202. package/dist/src/lib/types.d.ts +0 -119
  203. package/dist/src/lib/types.js.map +0 -1
  204. package/dist/src/mcp-server.d.ts +0 -6
  205. package/dist/src/mcp-server.js.map +0 -1
  206. package/dist/tests/jest.setup.d.ts +0 -6
  207. package/dist/tests/jest.setup.js +0 -30
  208. package/dist/tests/jest.setup.js.map +0 -1
  209. package/dist/tests/test-direct-client.d.ts +0 -6
  210. package/dist/tests/test-direct-client.js.map +0 -1
  211. package/dist/tests/test-mcp-methods.d.ts +0 -6
  212. package/dist/tests/test-mcp-methods.js.map +0 -1
  213. package/dist/tests/test-mcp.d.ts +0 -6
  214. package/dist/tests/test-mcp.js.map +0 -1
  215. package/dist/tests/test-mini4k.d.ts +0 -6
  216. package/dist/tests/test-mini4k.js.map +0 -1
@@ -0,0 +1,180 @@
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 { log, COMPONENTS } from '../../logger.js';
8
+ import { HttpClient } from './HttpClient.js';
9
+ import { ErrorHandler } from '../../utils/ErrorHandler.js';
10
+ /**
11
+ * Node模式获取器类 (Node mode fetcher class)
12
+ * 使用node-fetch实现标准模式的网页获取 (Implements webpage fetching in standard mode using node-fetch)
13
+ */
14
+ export class NodeFetcher {
15
+ /**
16
+ * 获取HTML内容 (Get HTML content)
17
+ * @param requestPayload 请求参数 (Request parameters)
18
+ * @returns HTML内容 (HTML content)
19
+ */
20
+ async html(requestPayload) {
21
+ const { debug = false } = requestPayload;
22
+ log('node.startingHtmlFetch', debug, {}, COMPONENTS.NODE_FETCH);
23
+ try {
24
+ // 执行请求 (Execute request)
25
+ const response = await HttpClient.fetchWithRedirects(requestPayload);
26
+ // 读取响应文本 (Read response text)
27
+ log('node.readingText', debug, {}, COMPONENTS.NODE_FETCH);
28
+ const html = await response.text();
29
+ log('node.htmlContentLength', debug, { length: html.length }, COMPONENTS.NODE_FETCH);
30
+ // 返回HTML内容 (Return HTML content)
31
+ return {
32
+ content: [{ type: 'text', text: html }],
33
+ isError: false
34
+ };
35
+ }
36
+ catch (error) {
37
+ // 使用ErrorHandler处理错误 (Use ErrorHandler to handle error)
38
+ const errorMessage = ErrorHandler.handleError(error, COMPONENTS.NODE_FETCH, debug, { url: requestPayload.url, method: 'html' });
39
+ // 返回错误信息 (Return error message)
40
+ return {
41
+ content: [{ type: 'text', text: `Error fetching HTML: ${errorMessage}` }],
42
+ isError: true
43
+ };
44
+ }
45
+ }
46
+ /**
47
+ * 获取JSON内容 (Get JSON content)
48
+ * @param requestPayload 请求参数 (Request parameters)
49
+ * @returns JSON内容 (JSON content)
50
+ */
51
+ async json(requestPayload) {
52
+ const { debug = false } = requestPayload;
53
+ log('node.startingJsonFetch', debug, {}, COMPONENTS.NODE_FETCH);
54
+ try {
55
+ // 执行请求 (Execute request)
56
+ const response = await HttpClient.fetchWithRedirects(requestPayload);
57
+ // 读取响应文本 (Read response text)
58
+ const text = await response.text();
59
+ // 解析JSON (Parse JSON)
60
+ log('node.parsingJson', debug, {}, COMPONENTS.NODE_FETCH);
61
+ let json;
62
+ try {
63
+ json = JSON.parse(text);
64
+ log('node.jsonParsed', debug, {}, COMPONENTS.NODE_FETCH);
65
+ // 返回JSON内容 (Return JSON content)
66
+ return {
67
+ content: [{ type: 'text', text }],
68
+ isError: false
69
+ };
70
+ }
71
+ catch (parseError) {
72
+ // 处理JSON解析错误 (Handle JSON parse error)
73
+ const textPreview = text.length > 100 ? `${text.substring(0, 100)}...` : text;
74
+ const error = new Error(`Invalid JSON: ${parseError instanceof Error ? parseError.message : String(parseError)}. Text preview: "${textPreview}", length: ${text.length}`);
75
+ error.text = text;
76
+ error.originalError = parseError;
77
+ log('fetcher.jsonParseError', debug, {
78
+ error: String(parseError),
79
+ textPreview,
80
+ textLength: text.length
81
+ }, COMPONENTS.NODE_FETCH);
82
+ // 返回错误信息 (Return error message)
83
+ return {
84
+ content: [{ type: 'text', text: `Error parsing JSON: ${error}` }],
85
+ isError: true
86
+ };
87
+ }
88
+ }
89
+ catch (error) {
90
+ // 使用ErrorHandler处理错误 (Use ErrorHandler to handle error)
91
+ const errorMessage = ErrorHandler.handleError(error, COMPONENTS.NODE_FETCH, debug, { url: requestPayload.url, method: 'json' });
92
+ // 返回错误信息 (Return error message)
93
+ return {
94
+ content: [{ type: 'text', text: `Error fetching JSON: ${errorMessage}` }],
95
+ isError: true
96
+ };
97
+ }
98
+ }
99
+ /**
100
+ * 获取纯文本内容 (Get plain text content)
101
+ * @param requestPayload 请求参数 (Request parameters)
102
+ * @returns 纯文本内容 (Plain text content)
103
+ */
104
+ async txt(requestPayload) {
105
+ const { debug = false } = requestPayload;
106
+ log('node.startingTxtFetch', debug, {}, COMPONENTS.NODE_FETCH);
107
+ try {
108
+ // 执行请求 (Execute request)
109
+ const response = await HttpClient.fetchWithRedirects(requestPayload);
110
+ // 读取响应文本 (Read response text)
111
+ log('node.readingText', debug, {}, COMPONENTS.NODE_FETCH);
112
+ const text = await response.text();
113
+ log('node.textContentLength', debug, { length: text.length }, COMPONENTS.NODE_FETCH);
114
+ // 返回纯文本内容 (Return plain text content)
115
+ return {
116
+ content: [{ type: 'text', text }],
117
+ isError: false
118
+ };
119
+ }
120
+ catch (error) {
121
+ // 使用ErrorHandler处理错误 (Use ErrorHandler to handle error)
122
+ const errorMessage = ErrorHandler.handleError(error, COMPONENTS.NODE_FETCH, debug, { url: requestPayload.url, method: 'txt' });
123
+ // 返回错误信息 (Return error message)
124
+ return {
125
+ content: [{ type: 'text', text: `Error fetching text: ${errorMessage}` }],
126
+ isError: true
127
+ };
128
+ }
129
+ }
130
+ /**
131
+ * 获取Markdown内容 (Get Markdown content)
132
+ * @param requestPayload 请求参数 (Request parameters)
133
+ * @returns Markdown内容 (Markdown content)
134
+ */
135
+ async markdown(requestPayload) {
136
+ const { debug = false } = requestPayload;
137
+ log('node.startingMarkdownFetch', debug, {}, COMPONENTS.NODE_FETCH);
138
+ try {
139
+ // 执行请求 (Execute request)
140
+ const response = await HttpClient.fetchWithRedirects(requestPayload);
141
+ // 读取响应文本 (Read response text)
142
+ log('node.readingText', debug, {}, COMPONENTS.NODE_FETCH);
143
+ const html = await response.text();
144
+ log('node.htmlContentLength', debug, { length: html.length }, COMPONENTS.NODE_FETCH);
145
+ // 创建Turndown服务 (Create Turndown service)
146
+ log('node.creatingTurndown', debug, {}, COMPONENTS.NODE_FETCH);
147
+ const turndownService = new TurndownService({
148
+ headingStyle: 'atx',
149
+ codeBlockStyle: 'fenced',
150
+ bulletListMarker: '-'
151
+ });
152
+ // 添加表格支持
153
+ turndownService.addRule('tables', {
154
+ filter: ['table'],
155
+ replacement: function (content, node) {
156
+ const tableContent = content.trim();
157
+ return '\n\n' + tableContent + '\n\n';
158
+ }
159
+ });
160
+ // 将HTML转换为Markdown (Convert HTML to Markdown)
161
+ log('node.convertingToMarkdown', debug, {}, COMPONENTS.NODE_FETCH);
162
+ const markdown = turndownService.turndown(html);
163
+ log('node.markdownContentLength', debug, { length: markdown.length }, COMPONENTS.NODE_FETCH);
164
+ // 返回Markdown内容 (Return Markdown content)
165
+ return {
166
+ content: [{ type: 'text', text: markdown }],
167
+ isError: false
168
+ };
169
+ }
170
+ catch (error) {
171
+ // 使用ErrorHandler处理错误 (Use ErrorHandler to handle error)
172
+ const errorMessage = ErrorHandler.handleError(error, COMPONENTS.NODE_FETCH, debug, { url: requestPayload.url, method: 'markdown' });
173
+ // 返回错误信息 (Return error message)
174
+ return {
175
+ content: [{ type: 'text', text: `Error fetching Markdown: ${errorMessage}` }],
176
+ isError: true
177
+ };
178
+ }
179
+ }
180
+ }
@@ -15,22 +15,110 @@ const resources = {
15
15
  translation: zhTranslation
16
16
  }
17
17
  };
18
- // 初始化 i18next (Initialize i18next)
19
- i18next.init({
20
- resources,
21
- // 优先使用专门的环境变量,其次默认使用英语
22
- // (Priority: dedicated environment variable, then default to English)
23
- lng: process.env.MCP_LANG || 'en',
24
- fallbackLng: 'en',
25
- interpolation: {
26
- escapeValue: false // 不转义插值 (Don't escape interpolation)
18
+ /**
19
+ * 将嵌套的翻译资源扁平化 (Flatten nested translation resources)
20
+ * @param resources 嵌套的翻译资源 (Nested translation resources)
21
+ * @returns 扁平化的翻译资源 (Flattened translation resources)
22
+ */
23
+ function flattenResources(resources) {
24
+ const flattened = {};
25
+ // 遍历所有语言 (Iterate through all languages)
26
+ for (const lang in resources) {
27
+ flattened[lang] = { translation: {} };
28
+ const translation = resources[lang].translation;
29
+ // 遍历所有命名空间 (Iterate through all namespaces)
30
+ for (const namespace in translation) {
31
+ const nsTranslation = translation[namespace];
32
+ // 遍历命名空间中的所有键 (Iterate through all keys in the namespace)
33
+ for (const key in nsTranslation) {
34
+ // 直接使用原始键名,不添加命名空间前缀 (Use the original key directly, without adding namespace prefix)
35
+ flattened[lang].translation[key] = nsTranslation[key];
36
+ }
37
+ }
27
38
  }
28
- });
39
+ return flattened;
40
+ }
41
+ // 扁平化翻译资源 (Flatten translation resources)
42
+ const flattenedResources = flattenResources(resources);
43
+ /**
44
+ * 初始化 i18next 配置 (Initialize i18next configuration)
45
+ */
46
+ const initializeI18n = () => {
47
+ // 获取当前语言环境 (Get current language environment)
48
+ const currentLanguage = process.env.MCP_LANG || 'en';
49
+ // 初始化 i18next (Initialize i18next)
50
+ i18next.init({
51
+ resources: flattenedResources,
52
+ // 优先使用专门的环境变量,其次默认使用英语
53
+ // (Priority: dedicated environment variable, then default to English)
54
+ lng: currentLanguage,
55
+ fallbackLng: 'en',
56
+ interpolation: {
57
+ escapeValue: false // 不转义插值 (Don't escape interpolation)
58
+ },
59
+ debug: false, // 禁用 i18n 调试 (Disable i18n debug)
60
+ returnEmptyString: false, // 不返回空字符串 (Don't return empty string)
61
+ returnNull: false, // 不返回 null (Don't return null)
62
+ returnObjects: true, // 返回对象 (Return objects)
63
+ saveMissing: false, // 不保存缺失的翻译键 (Don't save missing translation keys)
64
+ keySeparator: false, // 禁用键分隔符,使用完整的键路径 (Disable key separator, use full key path)
65
+ nsSeparator: false, // 禁用命名空间分隔符 (Disable namespace separator)
66
+ missingKeyHandler: (lng, ns, key, fallbackValue) => {
67
+ // 不输出任何日志,由上层调用决定是否输出 (Don't output any logs, let the upper-level call decide whether to output)
68
+ }
69
+ });
70
+ return i18next;
71
+ };
72
+ // 初始化 i18next 实例 (Initialize i18next instance)
73
+ const i18n = initializeI18n();
29
74
  // 导出 i18next 实例 (Export i18next instance)
30
- export default i18next;
31
- // 导出一个简便的翻译函数 (Export a convenient translation function)
32
- export const t = (key, options) => i18next.t(key, options);
33
- // 导出语言切换函数 (Export language switching function)
34
- export const changeLanguage = (lng) => i18next.changeLanguage(lng);
35
- // 导出获取当前语言函数 (Export get current language function)
36
- export const getCurrentLanguage = () => i18next.language;
75
+ export default i18n;
76
+ /**
77
+ * 翻译函数 - 提供类型安全和错误处理 (Translation function - provides type safety and error handling)
78
+ * @param key 翻译键 (Translation key)
79
+ * @param options 翻译选项 (Translation options)
80
+ * @returns 翻译结果 (Translation result)
81
+ */
82
+ export const t = (key, options) => {
83
+ try {
84
+ // 检查键是否存在 (Check if the key exists)
85
+ const exists = i18n.exists(key);
86
+ if (!exists) {
87
+ return key;
88
+ }
89
+ const result = i18n.t(key, options);
90
+ return result;
91
+ }
92
+ catch (error) {
93
+ return key; // 出错时返回原始键 (Return the original key when an error occurs)
94
+ }
95
+ };
96
+ /**
97
+ * 切换语言函数 (Language switching function)
98
+ * @param lng 目标语言 (Target language)
99
+ * @returns Promise,解析为切换后的语言 (Promise that resolves to the switched language)
100
+ */
101
+ export const changeLanguage = (lng) => {
102
+ // 不输出任何日志,由上层调用决定是否输出 (Don't output any logs, let the upper-level call decide whether to output)
103
+ return i18n.changeLanguage(lng).then(() => lng);
104
+ };
105
+ /**
106
+ * 获取当前语言函数 (Get current language function)
107
+ * @returns 当前语言 (Current language)
108
+ */
109
+ export const getCurrentLanguage = () => (i18n.language || 'en');
110
+ /**
111
+ * 检查键是否存在 (Check if a key exists)
112
+ * @param key 要检查的键 (Key to check)
113
+ * @returns 键是否存在 (Whether the key exists)
114
+ */
115
+ export const hasTranslation = (key) => {
116
+ return i18n.exists(key);
117
+ };
118
+ /**
119
+ * 获取所有支持的语言 (Get all supported languages)
120
+ * @returns 支持的语言数组 (Array of supported languages)
121
+ */
122
+ export const getSupportedLanguages = () => {
123
+ return Object.keys(resources);
124
+ };
@@ -0,0 +1,41 @@
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
+ /**
7
+ * 创建键名生成器 - 用于生成特定模块的键名 (Create key name generator - for generating key names for specific modules)
8
+ * @param module 模块名称 (Module name)
9
+ * @returns 键名生成函数 (Key name generator function)
10
+ */
11
+ export const createKeyGenerator = (module) => (key) => `${module}.${key}`;
12
+ /**
13
+ * 创建资源操作键 - 用于生成资源操作相关的键 (Create resource operation keys - for generating resource operation related keys)
14
+ * @param module 模块名称 (Module name)
15
+ * @param operation 操作名称 (Operation name)
16
+ * @returns 资源操作键对象 (Resource operation keys object)
17
+ */
18
+ export const createResourceOperationKeys = (module, operation) => {
19
+ const keyGen = createKeyGenerator(`${module}.${operation}`);
20
+ return {
21
+ request: keyGen('request'),
22
+ success: keyGen('success'),
23
+ error: keyGen('error'),
24
+ notFound: keyGen('notFound'),
25
+ duplicate: keyGen('duplicate')
26
+ };
27
+ };
28
+ /**
29
+ * 创建资源键 - 用于生成资源相关的键 (Create resource keys - for generating resource related keys)
30
+ * @param module 模块名称 (Module name)
31
+ * @returns 资源键对象 (Resource keys object)
32
+ */
33
+ export const createResourceKeys = (module) => {
34
+ return {
35
+ list: createResourceOperationKeys(module, 'list'),
36
+ get: createResourceOperationKeys(module, 'get'),
37
+ create: createResourceOperationKeys(module, 'create'),
38
+ update: createResourceOperationKeys(module, 'update'),
39
+ delete: createResourceOperationKeys(module, 'delete')
40
+ };
41
+ };
@@ -0,0 +1,91 @@
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 { createKeyGenerator } from './base.js';
7
+ /**
8
+ * 浏览器相关键 (Browser related keys)
9
+ */
10
+ export const BROWSER_KEYS = (() => {
11
+ const keyGen = createKeyGenerator('browser');
12
+ return {
13
+ // 浏览器生命周期 (Browser lifecycle)
14
+ closing: keyGen('closing'),
15
+ closed: keyGen('closed'),
16
+ starting: keyGen('starting'),
17
+ startingFailed: keyGen('startingFailed'),
18
+ alreadyRunning: keyGen('alreadyRunning'),
19
+ // 页面操作 (Page operations)
20
+ creatingPage: keyGen('creatingPage'),
21
+ navigatingTo: keyGen('navigatingTo'),
22
+ waitingForSelector: keyGen('waitingForSelector'),
23
+ waitingForTimeout: keyGen('waitingForTimeout'),
24
+ scrollingToBottom: keyGen('scrollingToBottom'),
25
+ scrollError: keyGen('scrollError'),
26
+ gettingContent: keyGen('gettingContent'),
27
+ contentLength: keyGen('contentLength'),
28
+ // Cookie 相关 (Cookie related)
29
+ savingCookies: keyGen('savingCookies'),
30
+ cookiesSaved: keyGen('cookiesSaved'),
31
+ loadingCookies: keyGen('loadingCookies'),
32
+ cookiesLoaded: keyGen('cookiesLoaded'),
33
+ noCookiesFound: keyGen('noCookiesFound'),
34
+ // 错误相关 (Error related)
35
+ errorLoadingCookies: keyGen('errorLoadingCookies'),
36
+ errorSavingCookies: keyGen('errorSavingCookies'),
37
+ errorNavigating: keyGen('errorNavigating'),
38
+ errorGettingContent: keyGen('errorGettingContent'),
39
+ errorClosingBrowser: keyGen('errorClosingBrowser'),
40
+ errorCreatingPage: keyGen('errorCreatingPage'),
41
+ closingError: keyGen('closingError'),
42
+ // 额外的浏览器相关键 (Additional browser related keys)
43
+ waiting: keyGen('waiting'),
44
+ startupSuccess: keyGen('startupSuccess'),
45
+ navigating: keyGen('navigating'),
46
+ scrolling: keyGen('scrolling'),
47
+ scrollCompleted: keyGen('scrollCompleted'),
48
+ contentTruncated: keyGen('contentTruncated'),
49
+ pageClosed: keyGen('pageClosed'),
50
+ fetchError: keyGen('fetchError'),
51
+ highMemory: keyGen('highMemory'),
52
+ closingDueToMemory: keyGen('closingDueToMemory'),
53
+ forcingGC: keyGen('forcingGC'),
54
+ memoryCheckError: keyGen('memoryCheckError'),
55
+ usingCookies: keyGen('usingCookies'),
56
+ usingProxy: keyGen('usingProxy'),
57
+ // Cloudflare 相关 (Cloudflare related)
58
+ checkingCloudflare: keyGen('checkingCloudflare'),
59
+ cloudflareDetected: keyGen('cloudflareDetected'),
60
+ simulatingHuman: keyGen('simulatingHuman'),
61
+ simulatingHumanError: keyGen('simulatingHumanError'),
62
+ stillOnCloudflare: keyGen('stillOnCloudflare'),
63
+ bypassFailed: keyGen('bypassFailed'),
64
+ cloudflareError: keyGen('cloudflareError'),
65
+ continuingWithoutBypass: keyGen('continuingWithoutBypass'),
66
+ unableToBypassCloudflare: keyGen('unableToBypassCloudflare'),
67
+ // 获取和重试相关 (Fetch and retry related)
68
+ fetchingWithRetry: keyGen('fetchingWithRetry'),
69
+ memoryUsage: keyGen('memoryUsage'),
70
+ memoryTooHigh: keyGen('memoryTooHigh'),
71
+ contentTooLarge: keyGen('contentTooLarge'),
72
+ failedToParseJSON: keyGen('failedToParseJSON'),
73
+ startingBrowserFetchForMarkdown: keyGen('startingBrowserFetchForMarkdown'),
74
+ errorInBrowserFetchForMarkdown: keyGen('errorInBrowserFetchForMarkdown'),
75
+ fetchRequest: keyGen('fetchRequest'),
76
+ usingStoredCookies: keyGen('usingStoredCookies'),
77
+ closingInstance: keyGen('closingInstance'),
78
+ fetchErrorWithAttempt: keyGen('fetchErrorWithAttempt'),
79
+ retryingAfterDelay: keyGen('retryingAfterDelay'),
80
+ // 浏览器启动相关 (Browser startup related)
81
+ browserStartupSuccess: keyGen('browserStartupSuccess'),
82
+ browserStartupFailed: keyGen('browserStartupFailed'),
83
+ usingCustomChromePath: keyGen('usingCustomChromePath'),
84
+ browserDisconnected: keyGen('browserDisconnected'),
85
+ waitingForBrowserStart: keyGen('waitingForBrowserStart'),
86
+ reusingExistingBrowser: keyGen('reusingExistingBrowser'),
87
+ startingBrowser: keyGen('startingBrowser'),
88
+ browserStarted: keyGen('browserStarted'),
89
+ browserStartError: keyGen('browserStartError')
90
+ };
91
+ })();
@@ -0,0 +1,68 @@
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 { createKeyGenerator } from './base.js';
7
+ /**
8
+ * 客户端相关键 (Client related keys)
9
+ */
10
+ export const CLIENT_KEYS = (() => {
11
+ const keyGen = createKeyGenerator('client');
12
+ return {
13
+ // 连接相关 (Connection related)
14
+ connecting: keyGen('connecting'),
15
+ connected: keyGen('connected'),
16
+ connectionFailed: keyGen('connectionFailed'),
17
+ disconnected: keyGen('disconnected'),
18
+ reconnecting: keyGen('reconnecting'),
19
+ // 错误相关 (Error related)
20
+ clientError: keyGen('clientError'),
21
+ transportError: keyGen('transportError'),
22
+ requestError: keyGen('requestError'),
23
+ fetchError: keyGen('fetchError'),
24
+ // 请求相关 (Request related)
25
+ requestStarted: keyGen('requestStarted'),
26
+ requestCompleted: keyGen('requestCompleted'),
27
+ requestCancelled: keyGen('requestCancelled'),
28
+ // 内容相关 (Content related)
29
+ fetchingHtml: keyGen('fetchingHtml'),
30
+ fetchingJson: keyGen('fetchingJson'),
31
+ fetchingText: keyGen('fetchingText'),
32
+ fetchingMarkdown: keyGen('fetchingMarkdown'),
33
+ fetchSuccessful: keyGen('fetchSuccessful'),
34
+ contentLength: keyGen('contentLength'),
35
+ // 调试相关 (Debug related)
36
+ debugMode: keyGen('debugMode'),
37
+ debugInfo: keyGen('debugInfo'),
38
+ error: keyGen('error'),
39
+ callTool: keyGen('callTool'),
40
+ callToolSuccess: keyGen('callToolSuccess'),
41
+ callToolError: keyGen('callToolError'),
42
+ statusCodeDetected: keyGen('statusCodeDetected'),
43
+ usageInfo: keyGen('usageInfo'),
44
+ exampleUsage: keyGen('exampleUsage'),
45
+ invalidJson: keyGen('invalidJson'),
46
+ usingCommandLineProxy: keyGen('usingCommandLineProxy'),
47
+ invalidProxyFormat: keyGen('invalidProxyFormat'),
48
+ usingEnvProxy: keyGen('usingEnvProxy'),
49
+ usingShellProxy: keyGen('usingShellProxy'),
50
+ noShellProxy: keyGen('noShellProxy'),
51
+ systemProxyDisabled: keyGen('systemProxyDisabled'),
52
+ usingSystemProxy: keyGen('usingSystemProxy'),
53
+ noSystemProxy: keyGen('noSystemProxy'),
54
+ requestFailed: keyGen('requestFailed'),
55
+ fatalError: keyGen('fatalError'),
56
+ startingServer: keyGen('startingServer'),
57
+ fetchingUrl: keyGen('fetchingUrl'),
58
+ usingMode: keyGen('usingMode'),
59
+ fetchFailed: keyGen('fetchFailed'),
60
+ fetchSuccess: keyGen('fetchSuccess'),
61
+ browserModeNeeded: keyGen('browserModeNeeded'),
62
+ retryingWithBrowser: keyGen('retryingWithBrowser'),
63
+ browserModeFetchFailed: keyGen('browserModeFetchFailed'),
64
+ browserModeFetchSuccess: keyGen('browserModeFetchSuccess'),
65
+ serverClosed: keyGen('serverClosed'),
66
+ proxySet: keyGen('proxySet')
67
+ };
68
+ })();
@@ -0,0 +1,49 @@
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 { createKeyGenerator } from './base.js';
7
+ /**
8
+ * 错误相关键 (Error related keys)
9
+ */
10
+ export const ERROR_KEYS = (() => {
11
+ const keyGen = createKeyGenerator('errors');
12
+ const errorKeyGen = createKeyGenerator('error'); // 为 error 前缀创建键生成器
13
+ return {
14
+ // 通用错误日志 (Generic error logging)
15
+ occurred: errorKeyGen('occurred'), // 添加 error.occurred 键
16
+ // 参数错误 (Parameter errors)
17
+ missingRequiredParam: keyGen('missingRequiredParam'),
18
+ invalidUrl: keyGen('invalidUrl'),
19
+ // 请求错误 (Request errors)
20
+ requestTimeout: keyGen('requestTimeout'),
21
+ maxRedirectsExceeded: keyGen('maxRedirectsExceeded'),
22
+ requestFailed: keyGen('requestFailed'),
23
+ networkError: keyGen('networkError'),
24
+ // 响应错误 (Response errors)
25
+ invalidResponse: keyGen('invalidResponse'),
26
+ invalidContentType: keyGen('invalidContentType'),
27
+ invalidJson: keyGen('invalidJson'),
28
+ // 浏览器错误 (Browser errors)
29
+ browserInitFailed: keyGen('browserInitFailed'),
30
+ pageLoadFailed: keyGen('pageLoadFailed'),
31
+ // 访问限制错误 (Access restriction errors)
32
+ forbidden: keyGen('forbidden'),
33
+ cloudflareProtection: keyGen('cloudflareProtection'),
34
+ captchaRequired: keyGen('captchaRequired'),
35
+ // 连接错误 (Connection errors)
36
+ timeout: keyGen('timeout'),
37
+ connectionProblem: keyGen('connectionProblem'),
38
+ // 通用错误 (Generic errors)
39
+ unknownError: keyGen('unknownError'),
40
+ // 错误类型键 (Error type keys)
41
+ network_error: keyGen('network_error'),
42
+ access_denied_error: keyGen('access_denied_error'),
43
+ timeout_error: keyGen('timeout_error'),
44
+ parse_error: keyGen('parse_error'),
45
+ validation_error: keyGen('validation_error'),
46
+ browser_error: keyGen('browser_error'),
47
+ unknown_error: keyGen('unknown_error')
48
+ };
49
+ })();
@@ -0,0 +1,46 @@
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 { createKeyGenerator } from './base.js';
7
+ /**
8
+ * 工厂相关键 (Factory related keys)
9
+ */
10
+ export const FACTORY_KEYS = (() => {
11
+ const keyGen = createKeyGenerator('factory');
12
+ return {
13
+ // 日志消息 (Log messages)
14
+ creating_fetcher: keyGen('creating_fetcher'),
15
+ fetcher_created: keyGen('fetcher_created'),
16
+ fetcher_creation_failed: keyGen('fetcher_creation_failed'),
17
+ invalid_fetcher_type: keyGen('invalid_fetcher_type'),
18
+ browser_mode_enabled: keyGen('browser_mode_enabled'),
19
+ browser_mode_disabled: keyGen('browser_mode_disabled'),
20
+ using_default_mode: keyGen('using_default_mode'),
21
+ initializing: keyGen('initializing'),
22
+ initialization_complete: keyGen('initialization_complete'),
23
+ initialization_failed: keyGen('initialization_failed'),
24
+ auto_detecting_mode: keyGen('auto_detecting_mode'),
25
+ using_browser_mode: keyGen('using_browser_mode'),
26
+ using_node_mode: keyGen('using_node_mode'),
27
+ defaultingToNodeMode: keyGen('defaultingToNodeMode')
28
+ };
29
+ })();
30
+ // 为了向后兼容,保留旧的 FACTORY 对象 (For backward compatibility, keep the old FACTORY object)
31
+ export const FACTORY = {
32
+ CREATING_FETCHER: 'factory.creating_fetcher',
33
+ FETCHER_CREATED: 'factory.fetcher_created',
34
+ FETCHER_CREATION_FAILED: 'factory.fetcher_creation_failed',
35
+ INVALID_FETCHER_TYPE: 'factory.invalid_fetcher_type',
36
+ BROWSER_MODE_ENABLED: 'factory.browser_mode_enabled',
37
+ BROWSER_MODE_DISABLED: 'factory.browser_mode_disabled',
38
+ USING_DEFAULT_MODE: 'factory.using_default_mode',
39
+ INITIALIZING: 'factory.initializing',
40
+ INITIALIZATION_COMPLETE: 'factory.initialization_complete',
41
+ INITIALIZATION_FAILED: 'factory.initialization_failed',
42
+ AUTO_DETECTING_MODE: 'factory.auto_detecting_mode',
43
+ USING_BROWSER_MODE: 'factory.using_browser_mode',
44
+ USING_NODE_MODE: 'factory.using_node_mode',
45
+ DEFAULTING_TO_NODE_MODE: 'factory.defaultingToNodeMode'
46
+ };