@liangshanli/mcp-server-project-standards 1.2.2 → 2.0.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.
@@ -1,646 +1,172 @@
1
- const fs = require('fs-extra');
2
- const path = require('path');
3
-
4
- // Get allowed methods from environment variable
5
- const getAllowedMethods = () => {
6
- const allowedMethods = process.env.API_DEBUG_ALLOWED_METHODS || 'GET';
7
- return allowedMethods.split(',').map(method => method.trim().toUpperCase());
8
- };
9
-
10
- // Get login URL from environment variable
11
- const getLoginUrl = () => {
12
- return process.env.API_DEBUG_LOGIN_URL || '/api/login';
13
- };
14
-
15
- // Get login method from environment variable
16
- const getLoginMethod = () => {
17
- return (process.env.API_DEBUG_LOGIN_METHOD || 'POST').toUpperCase();
18
- };
19
-
20
- // Get login body from environment variable
21
- const getLoginBody = () => {
22
- return process.env.API_DEBUG_LOGIN_BODY || '{"username":"","password":""}';
23
- };
24
-
25
- // Get login description from environment variable
26
- const getLoginDescription = () => {
27
- return process.env.API_DEBUG_LOGIN_DESCRIPTION || 'Save returned token to common headers in debug tool, field name Authorization, field value Bearer token';
28
- };
29
-
30
- // Get API debug config file path
31
- const getApiConfigPath = () => {
32
- const configDir = process.env.CONFIG_DIR || './.setting';
33
- return path.join(configDir, 'api.json');
34
- };
35
-
36
- // Load API debug config
37
- const loadApiConfig = () => {
38
- const apiConfigPath = getApiConfigPath();
39
- try {
40
- if (fs.existsSync(apiConfigPath)) {
41
- const configData = fs.readFileSync(apiConfigPath, 'utf8');
42
- return JSON.parse(configData);
43
- }
44
- } catch (err) {
45
- console.error('Failed to read API config file:', err.message);
46
- }
47
- return {
48
- baseUrl: '',
49
- headers: {
50
- 'Content-Type': 'application/json',
51
- 'Accept': 'application/json'
52
- },
53
- list: []
54
- };
55
- };
56
-
57
- // Save API debug config
58
- const saveApiConfig = (apiConfig) => {
59
- const configDir = process.env.CONFIG_DIR || './.setting';
60
- const apiConfigPath = path.join(configDir, 'api.json');
61
-
62
- try {
63
- if (!fs.existsSync(configDir)) {
64
- fs.mkdirSync(configDir, { recursive: true });
65
- }
66
- fs.writeFileSync(apiConfigPath, JSON.stringify(apiConfig, null, 2), 'utf8');
67
- return true;
68
- } catch (err) {
69
- console.error('Failed to save API config file:', err.message);
70
- return false;
71
- }
72
- };
73
-
74
- // Detect content type based on body content
75
- const detectContentType = (body) => {
76
- if (typeof body !== 'string') {
77
- return 'application/json';
78
- }
79
-
80
- const trimmedBody = body.trim();
81
-
82
- // Check for XML
83
- if (trimmedBody.startsWith('<') && trimmedBody.endsWith('>')) {
84
- return 'application/xml';
85
- }
86
-
87
- // Check for HTML
88
- if (trimmedBody.includes('<html') || trimmedBody.includes('<!DOCTYPE html')) {
89
- return 'text/html';
90
- }
91
-
92
- // Check for JSON
93
- try {
94
- JSON.parse(trimmedBody);
95
- return 'application/json';
96
- } catch {
97
- // Not JSON, continue checking
98
- }
99
-
100
- // Check for URL encoded format
101
- if (trimmedBody.includes('=') && trimmedBody.includes('&')) {
102
- return 'application/x-www-form-urlencoded';
103
- }
104
-
105
- // Check for plain text patterns
106
- if (trimmedBody.includes('\n') || trimmedBody.includes('\r')) {
107
- return 'text/plain';
108
- }
109
-
110
- // Default to text/plain
111
- return 'text/plain';
112
- };
1
+ const { getAllowedMethods, loadApiConfig, saveApiConfig, detectContentType } = require('./api_common');
113
2
 
114
3
  /**
115
- * API 调试工具 - 执行 API 请求和调试
4
+ * API 调试工具 - 直接执行API请求
116
5
  * @param {Object} params - 参数
117
- * @param {string} params.action - 操作类型 ('get', 'set', 'delete', 'execute', 'updateBaseUrl', 'updateHeaders', 'deleteHeader', 'search')
118
- * @param {Object} params.config - API 调试配置
119
- * @param {string} params.config.baseUrl - API 基础 URL
120
- * @param {Object} params.config.headers - 公共请求头
121
- * @param {Array} params.config.list - API 接口列表
122
- * @param {string} params.url - 要执行的接口URL(执行时必需)
123
- * @param {string} params.baseUrl - 新的基础 URL(updateBaseUrl 时必需)
124
- * @param {Object} params.headers - 新的公共请求头(updateHeaders 时必需)
125
- * @param {string} params.headerName - 要删除的请求头名称(deleteHeader 时必需)
126
- * @param {string} params.keyword - 搜索关键词(search 时必需)
6
+ * @param {string} params.url - 要执行的接口URL(必需)
7
+ * @param {string} params.method - HTTP方法(可选,默认GET)
8
+ * @param {Object} params.headers - 额外请求头(可选)
9
+ * @param {Object} params.query - 查询参数(可选)
10
+ * @param {*} params.body - 请求体(可选)
11
+ * @param {string} params.contentType - 内容类型(可选,会自动检测)
127
12
  * @param {Object} config - 服务器配置
128
13
  * @param {Function} saveConfig - 保存配置函数
129
- * @returns {Object} API 调试结果
14
+ * @returns {Object} API调试结果
130
15
  */
131
16
  async function api_debug(params, config, saveConfig) {
132
- const { action, config: apiConfig, url } = params || {};
17
+ const { url, method = 'GET', headers = {}, query, body, contentType } = params || {};
133
18
 
134
- if (!action) {
135
- throw new Error('Missing action parameter. Must be "get", "set", "delete", "execute", "updateBaseUrl", "updateHeaders", "deleteHeader", or "search"');
19
+ if (!url) {
20
+ throw new Error('Missing url parameter');
136
21
  }
137
22
 
138
- if (action === 'get') {
139
- try {
140
- // api.json 文件中获取配置
141
- const apiDebugConfig = loadApiConfig();
142
- return apiDebugConfig;
143
- } catch (err) {
144
- throw new Error(`Failed to get API debug config: ${err.message}`);
145
- }
146
- } else if (action === 'set') {
147
- if (!apiConfig) {
148
- throw new Error('Missing config parameter for set action');
149
- }
23
+ try {
24
+ // 加载当前配置
25
+ const apiDebugConfig = loadApiConfig();
150
26
 
151
- try {
152
- // 加载现有配置
153
- const existingConfig = loadApiConfig();
154
-
155
- // 合并配置,保持 baseUrl 和 headers
156
- const mergedConfig = {
157
- baseUrl: apiConfig.baseUrl || existingConfig.baseUrl || '',
158
- headers: { ...existingConfig.headers, ...apiConfig.headers },
159
- list: []
160
- };
161
-
162
- // 去重处理:相同的 URL 只保留一份
163
- const urlMap = new Map();
164
-
165
- // 先添加现有列表中的项目
166
- if (existingConfig.list && Array.isArray(existingConfig.list)) {
167
- existingConfig.list.forEach(item => {
168
- if (item.url) {
169
- urlMap.set(item.url, item);
170
- }
171
- });
172
- }
173
-
174
- // 再添加新配置中的项目(会覆盖相同 URL 的项目)
175
- if (apiConfig.list && Array.isArray(apiConfig.list)) {
176
- apiConfig.list.forEach(item => {
177
- if (item.url) {
178
- urlMap.set(item.url, item);
179
- }
180
- });
181
- }
182
-
183
- // 转换为数组
184
- mergedConfig.list = Array.from(urlMap.values());
185
-
186
- // 保存到 api.json 文件
187
- const saved = saveApiConfig(mergedConfig);
188
- if (!saved) {
189
- throw new Error('Failed to save API configuration');
190
- }
191
-
192
- return {
193
- success: true,
194
- message: `Successfully updated API debug config. Total APIs: ${mergedConfig.list.length}`,
195
- totalApis: mergedConfig.list.length,
196
- timestamp: new Date().toISOString()
197
- };
198
- } catch (err) {
199
- throw new Error(`Failed to update API debug config: ${err.message}`);
200
- }
201
- } else if (action === 'delete') {
202
- if (!url) {
203
- throw new Error('Missing url parameter for delete action');
204
- }
27
+ // 验证请求方法是否被允许
28
+ const allowedMethods = getAllowedMethods();
29
+ const requestMethod = method.toUpperCase();
205
30
 
206
- try {
207
- // 加载当前配置
208
- const apiDebugConfig = loadApiConfig();
209
-
210
- if (!apiDebugConfig.list) {
211
- apiDebugConfig.list = [];
212
- }
213
-
214
- // 查找并删除指定URL的接口
215
- const originalLength = apiDebugConfig.list.length;
216
- apiDebugConfig.list = apiDebugConfig.list.filter(item => item.url !== url);
217
-
218
- if (apiDebugConfig.list.length === originalLength) {
219
- return {
220
- success: false,
221
- message: `API with URL "${url}" not found`,
222
- timestamp: new Date().toISOString()
223
- };
224
- }
225
-
226
- // 保存配置
227
- const saved = saveApiConfig(apiDebugConfig);
228
- if (!saved) {
229
- throw new Error('Failed to save API configuration');
230
- }
231
-
232
- return {
233
- success: true,
234
- message: `Successfully deleted API with URL: ${url}`,
235
- deletedUrl: url,
236
- timestamp: new Date().toISOString()
237
- };
238
- } catch (err) {
239
- throw new Error(`Failed to delete API: ${err.message}`);
240
- }
241
- } else if (action === 'execute') {
242
- if (!url) {
243
- throw new Error('Missing url parameter for execute action');
31
+ if (!allowedMethods.includes(requestMethod)) {
32
+ throw new Error(`Method ${requestMethod} is not allowed. Allowed methods: ${allowedMethods.join(', ')}`);
244
33
  }
245
34
 
246
- try {
247
- // 加载当前配置
248
- const apiDebugConfig = loadApiConfig();
249
-
250
- if (!apiDebugConfig.list || !Array.isArray(apiDebugConfig.list)) {
251
- apiDebugConfig.list = [];
252
- }
253
-
254
- // 查找指定URL的接口,如果不存在则创建一个新的
255
- let apiItem = apiDebugConfig.list.find(item => item.url === url);
256
- let itemIndex = apiDebugConfig.list.findIndex(item => item.url === url);
257
-
258
- if (!apiItem) {
259
- // 如果接口不存在,创建一个新的接口配置
260
- apiItem = {
261
- url: url,
262
- method: 'GET',
263
- description: `API: ${url}`
264
- };
265
- apiDebugConfig.list.push(apiItem);
266
- itemIndex = apiDebugConfig.list.length - 1;
267
- }
35
+ // 构建完整 URL
36
+ let fullUrl;
37
+ if (url.startsWith('http://') || url.startsWith('https://')) {
38
+ fullUrl = url;
39
+ } else {
268
40
  const baseUrl = apiDebugConfig.baseUrl || '';
269
- const commonHeaders = apiDebugConfig.headers || {};
270
-
271
- // 验证请求方法是否被允许
272
- const allowedMethods = getAllowedMethods();
273
- const requestMethod = (apiItem.method || 'GET').toUpperCase();
274
- const loginUrl = getLoginUrl();
275
-
276
- // 判断是否为登录接口 - 支持完整 URL 和相对路径匹配
277
- const isLoginRequest = (() => {
278
- const apiUrl = apiItem.url;
279
- const loginUrlPattern = loginUrl;
280
-
281
- // 如果登录 URL 是完整 URL,提取路径部分进行匹配
282
- if (loginUrlPattern.startsWith('http://') || loginUrlPattern.startsWith('https://')) {
283
- try {
284
- const url = new URL(loginUrlPattern);
285
- const loginPath = url.pathname;
286
- // 匹配完整路径或去掉前导斜杠的路径
287
- return apiUrl === loginPath || apiUrl === loginPath.replace(/^\//, '') || apiUrl === loginUrlPattern;
288
- } catch (e) {
289
- // 如果 URL 解析失败,回退到字符串匹配
290
- return apiUrl === loginUrlPattern;
291
- }
41
+ fullUrl = baseUrl + url;
42
+ }
43
+
44
+ // 合并请求头
45
+ const finalHeaders = {
46
+ ...apiDebugConfig.headers,
47
+ ...headers
48
+ };
49
+
50
+ // 处理请求体
51
+ let requestBody = null;
52
+ if (body && (requestMethod === 'POST' || requestMethod === 'PUT' || requestMethod === 'PATCH')) {
53
+ if (typeof body === 'string') {
54
+ // 检查是否指定了 Content-Type
55
+ if (contentType) {
56
+ finalHeaders['Content-Type'] = contentType;
57
+ requestBody = body;
292
58
  } else {
293
- // 相对路径匹配
294
- return apiUrl === loginUrlPattern ||
295
- apiUrl === loginUrlPattern.replace(/^\//, '') ||
296
- apiUrl.endsWith(loginUrlPattern) ||
297
- apiUrl.endsWith(loginUrlPattern.replace(/^\//, ''));
298
- }
299
- })();
300
-
301
- if (!allowedMethods.includes(requestMethod)) {
302
- // 如果是登录接口,继续执行;否则返回错误
303
- if (!isLoginRequest) {
304
- throw new Error(`Method ${requestMethod} is not allowed. Allowed methods: ${allowedMethods.join(', ')}`);
305
- }
306
- }
307
-
308
- // 构建完整 URL - 如果用户提供的是完整URL,直接使用;否则拼接baseUrl
309
- let fullUrl;
310
- if (apiItem.url.startsWith('http://') || apiItem.url.startsWith('https://')) {
311
- fullUrl = apiItem.url;
312
- } else {
313
- fullUrl = baseUrl + apiItem.url;
314
- }
315
-
316
- // 合并请求头
317
- const headers = {
318
- ...commonHeaders,
319
- ...apiItem.header
320
- };
321
-
322
- // 处理请求体
323
- let body = null;
324
- if (apiItem.body && (apiItem.method === 'POST' || apiItem.method === 'PUT' || apiItem.method === 'PATCH')) {
325
- if (typeof apiItem.body === 'string') {
326
- // 检查是否指定了 Content-Type
327
- if (apiItem.contentType) {
328
- headers['Content-Type'] = apiItem.contentType;
329
- body = apiItem.body;
330
- } else {
331
- // 自动判断 Content-Type
332
- const detectedType = detectContentType(apiItem.body);
333
- headers['Content-Type'] = detectedType;
334
- body = apiItem.body;
335
- }
336
- } else if (typeof apiItem.body === 'object') {
337
- // 检查是否指定了 Content-Type
338
- if (apiItem.contentType) {
339
- if (apiItem.contentType === 'application/x-www-form-urlencoded') {
340
- // 转换为 URL 编码格式
341
- const formData = new URLSearchParams();
342
- Object.entries(apiItem.body).forEach(([key, value]) => {
343
- if (value !== null && value !== undefined) {
344
- formData.append(key, value);
345
- }
346
- });
347
- headers['Content-Type'] = 'application/x-www-form-urlencoded';
348
- body = formData.toString();
349
- } else {
350
- // 其他指定类型,直接序列化
351
- headers['Content-Type'] = apiItem.contentType;
352
- body = JSON.stringify(apiItem.body);
353
- }
354
- } else {
355
- // 自动判断:对象默认使用 JSON 格式
356
- headers['Content-Type'] = 'application/json';
357
- body = JSON.stringify(apiItem.body);
358
- }
59
+ // 自动判断 Content-Type
60
+ const detectedType = detectContentType(body);
61
+ finalHeaders['Content-Type'] = detectedType;
62
+ requestBody = body;
359
63
  }
360
- }
361
-
362
- // 处理查询参数
363
- let queryString = '';
364
- if (apiItem.query && Object.keys(apiItem.query).length > 0) {
365
- const queryParams = new URLSearchParams();
366
- Object.entries(apiItem.query).forEach(([key, value]) => {
367
- if (value !== null && value !== undefined) {
368
- queryParams.append(key, value);
369
- }
370
- });
371
- queryString = queryParams.toString();
372
- }
373
-
374
- const finalUrl = queryString ? `${fullUrl}?${queryString}` : fullUrl;
375
-
376
- let success = true;
377
- let response;
378
- let responseData;
379
- let error = null;
380
-
381
- // 请求处理部分 - 只有这部分出错才会保存到 api.json
382
- try {
383
-
384
- // 如果是登录接口且方法不被允许,使用环境变量中的登录配置
385
- if (isLoginRequest && !allowedMethods.includes(requestMethod)) {
386
- const loginMethod = getLoginMethod();
387
- const loginBody = getLoginBody();
388
-
389
- // 更新请求方法和请求体
390
- apiItem.method = loginMethod;
391
- if (loginBody) {
392
- apiItem.body = loginBody;
393
- }
394
-
395
- // 更新最终 URL 和方法
396
- const updatedFinalUrl = queryString ? `${fullUrl}?${queryString}` : fullUrl;
397
-
398
- try {
399
- response = await fetch(updatedFinalUrl, {
400
- method: loginMethod,
401
- headers: headers,
402
- body: loginBody
64
+ } else if (typeof body === 'object') {
65
+ // 检查是否指定了 Content-Type
66
+ if (contentType) {
67
+ if (contentType === 'application/x-www-form-urlencoded') {
68
+ // 转换为 URL 编码格式
69
+ const formData = new URLSearchParams();
70
+ Object.entries(body).forEach(([key, value]) => {
71
+ if (value !== null && value !== undefined) {
72
+ formData.append(key, value);
73
+ }
403
74
  });
404
- } catch (fetchError) {
405
- error = fetchError.message;
406
- success = false;
407
- response = null;
408
- }
409
- } else {
410
- try {
411
- // 执行请求
412
- response = await fetch(finalUrl, {
413
- method: apiItem.method || 'GET',
414
- headers: headers,
415
- body: body
416
- });
417
- } catch (fetchError) {
418
- error = fetchError.message;
419
- success = false;
420
- response = null;
421
- }
422
- }
423
-
424
- if (response) {
425
- // 获取响应数据
426
- const contentType = response.headers.get('content-type');
427
-
428
- if (contentType && contentType.includes('application/json')) {
429
- responseData = await response.json();
75
+ finalHeaders['Content-Type'] = 'application/x-www-form-urlencoded';
76
+ requestBody = formData.toString();
430
77
  } else {
431
- responseData = await response.text();
78
+ // 其他指定类型,直接序列化
79
+ finalHeaders['Content-Type'] = contentType;
80
+ requestBody = JSON.stringify(body);
432
81
  }
433
-
434
- // 判断请求是否成功(HTTP 状态码 200-299 为成功)
435
- const isHttpSuccess = response.status >= 200 && response.status < 300;
436
- success = isHttpSuccess;
437
-
438
- // 记录响应信息
439
- apiDebugConfig.list[itemIndex].data = responseData;
440
- apiDebugConfig.list[itemIndex].status = response.status;
441
- apiDebugConfig.list[itemIndex].statusText = response.statusText;
442
- apiDebugConfig.list[itemIndex].responseHeaders = Object.fromEntries(response.headers.entries());
443
- apiDebugConfig.list[itemIndex].lastExecuted = new Date().toISOString();
444
- apiDebugConfig.list[itemIndex].success = isHttpSuccess;
445
- apiDebugConfig.list[itemIndex].error = isHttpSuccess ? null : `HTTP ${response.status}: ${response.statusText}`;
446
82
  } else {
447
- // 记录失败信息
448
- success = false;
449
- apiDebugConfig.list[itemIndex].data = null;
450
- apiDebugConfig.list[itemIndex].status = null;
451
- apiDebugConfig.list[itemIndex].statusText = null;
452
- apiDebugConfig.list[itemIndex].responseHeaders = null;
453
- apiDebugConfig.list[itemIndex].lastExecuted = new Date().toISOString();
454
- apiDebugConfig.list[itemIndex].success = false;
455
- apiDebugConfig.list[itemIndex].error = error;
456
- }
457
-
458
- // 去重处理:相同的 URL 只保留一份(保留最新的执行结果)
459
- const urlMap = new Map();
460
- apiDebugConfig.list.forEach(item => {
461
- if (item.url) {
462
- urlMap.set(item.url, item);
463
- }
464
- });
465
- apiDebugConfig.list = Array.from(urlMap.values());
466
-
467
- // 无论成功还是失败,都保存配置
468
- saveApiConfig(apiDebugConfig);
469
-
470
- } catch (requestError) {
471
- // 只有请求相关的错误才保存到 api.json
472
- try {
473
- apiDebugConfig.list[itemIndex].lastExecuted = new Date().toISOString();
474
- apiDebugConfig.list[itemIndex].success = false;
475
- apiDebugConfig.list[itemIndex].error = requestError.message;
476
- saveApiConfig(apiDebugConfig);
477
- } catch (saveErr) {
478
- console.error('Failed to save request error information:', saveErr.message);
83
+ // 自动判断:对象默认使用 JSON 格式
84
+ finalHeaders['Content-Type'] = 'application/json';
85
+ requestBody = JSON.stringify(body);
479
86
  }
480
87
  }
481
-
482
- if (success && response) {
483
- return {
484
- success: true,
485
- message: `Successfully executed API: ${apiItem.description || apiItem.url}`,
486
- request: {
487
- url: finalUrl,
488
- method: apiItem.method || 'GET',
489
- headers: headers,
490
- body: body
491
- },
492
- response: {
493
- status: response.status,
494
- statusText: response.statusText,
495
- headers: Object.fromEntries(response.headers.entries()),
496
- data: responseData
497
- },
498
- timestamp: new Date().toISOString()
499
- };
500
- } else {
501
- return {
502
- success: false,
503
- message: `Failed to execute API: ${apiItem.description || apiItem.url}`,
504
- request: {
505
- url: finalUrl,
506
- method: apiItem.method || 'GET',
507
- headers: headers,
508
- body: body
509
- },
510
- error: error || (response ? `HTTP ${response.status}: ${response.statusText}` : 'Request failed'),
511
- timestamp: new Date().toISOString()
512
- };
513
- }
514
- } catch (err) {
515
- // 如果是在保存配置时出错,也要尝试记录错误信息
516
- try {
517
- const apiDebugConfig = loadApiConfig();
518
- const itemIndex = apiDebugConfig.list.findIndex(item => item.url === url);
519
- if (apiDebugConfig.list && itemIndex >= 0) {
520
- apiDebugConfig.list[itemIndex].lastExecuted = new Date().toISOString();
521
- apiDebugConfig.list[itemIndex].success = false;
522
- apiDebugConfig.list[itemIndex].error = err.message;
523
- saveApiConfig(apiDebugConfig);
524
- }
525
- } catch (saveErr) {
526
- // 如果连保存都失败了,记录到控制台
527
- console.error('Failed to save error information:', saveErr.message);
528
- }
529
-
530
- throw new Error(`Failed to execute API: ${err.message}`);
531
88
  }
532
- } else if (action === 'updateBaseUrl') {
533
- const { baseUrl } = params;
534
- if (!baseUrl) {
535
- throw new Error('Missing baseUrl parameter for updateBaseUrl action');
89
+
90
+ // 处理查询参数
91
+ let queryString = '';
92
+ if (query && Object.keys(query).length > 0) {
93
+ const queryParams = new URLSearchParams();
94
+ Object.entries(query).forEach(([key, value]) => {
95
+ if (value !== null && value !== undefined) {
96
+ queryParams.append(key, value);
97
+ }
98
+ });
99
+ queryString = queryParams.toString();
536
100
  }
537
101
 
102
+ const finalRequestUrl = queryString ? `${fullUrl}?${queryString}` : fullUrl;
103
+
104
+ let success = true;
105
+ let response;
106
+ let responseData;
107
+ let error = null;
108
+
538
109
  try {
539
- const apiDebugConfig = loadApiConfig();
540
- apiDebugConfig.baseUrl = baseUrl;
541
- const saved = saveApiConfig(apiDebugConfig);
542
- if (!saved) {
543
- throw new Error('Failed to save API configuration');
110
+ // 执行请求
111
+ response = await fetch(finalRequestUrl, {
112
+ method: requestMethod,
113
+ headers: finalHeaders,
114
+ body: requestBody
115
+ });
116
+
117
+ // 获取响应数据
118
+ const responseContentType = response.headers.get('content-type');
119
+
120
+ if (responseContentType && responseContentType.includes('application/json')) {
121
+ responseData = await response.json();
122
+ } else {
123
+ responseData = await response.text();
544
124
  }
545
125
 
546
- return {
547
- success: true,
548
- message: `Successfully updated base URL to: ${baseUrl}`,
549
- baseUrl: baseUrl,
550
- timestamp: new Date().toISOString()
551
- };
552
- } catch (err) {
553
- throw new Error(`Failed to update base URL: ${err.message}`);
554
- }
555
- } else if (action === 'updateHeaders') {
556
- const { headers } = params;
557
- if (!headers || typeof headers !== 'object') {
558
- throw new Error('Missing or invalid headers parameter for updateHeaders action');
126
+ // 判断请求是否成功(HTTP 状态码 200-299 为成功)
127
+ const isHttpSuccess = response.status >= 200 && response.status < 300;
128
+ success = isHttpSuccess;
129
+
130
+ } catch (requestError) {
131
+ error = requestError.message;
132
+ success = false;
559
133
  }
560
134
 
561
- try {
562
- const apiDebugConfig = loadApiConfig();
563
- apiDebugConfig.headers = { ...apiDebugConfig.headers, ...headers };
564
- const saved = saveApiConfig(apiDebugConfig);
565
- if (!saved) {
566
- throw new Error('Failed to save API configuration');
567
- }
568
-
135
+ if (success && response) {
569
136
  return {
570
137
  success: true,
571
- message: 'Successfully updated headers',
572
- headers: apiDebugConfig.headers,
138
+ message: `Successfully executed API: ${url}`,
139
+ request: {
140
+ url: finalRequestUrl,
141
+ method: requestMethod,
142
+ headers: finalHeaders,
143
+ body: requestBody
144
+ },
145
+ response: {
146
+ status: response.status,
147
+ statusText: response.statusText,
148
+ headers: Object.fromEntries(response.headers.entries()),
149
+ data: responseData
150
+ },
573
151
  timestamp: new Date().toISOString()
574
152
  };
575
- } catch (err) {
576
- throw new Error(`Failed to update headers: ${err.message}`);
577
- }
578
- } else if (action === 'deleteHeader') {
579
- const { headerName } = params;
580
- if (!headerName) {
581
- throw new Error('Missing headerName parameter for deleteHeader action');
582
- }
583
-
584
- try {
585
- const apiDebugConfig = loadApiConfig();
586
- if (apiDebugConfig.headers && apiDebugConfig.headers[headerName]) {
587
- delete apiDebugConfig.headers[headerName];
588
- const saved = saveApiConfig(apiDebugConfig);
589
- if (!saved) {
590
- throw new Error('Failed to save API configuration');
591
- }
592
-
593
- return {
594
- success: true,
595
- message: `Successfully deleted header: ${headerName}`,
596
- headers: apiDebugConfig.headers,
597
- timestamp: new Date().toISOString()
598
- };
599
- } else {
600
- return {
601
- success: false,
602
- message: `Header '${headerName}' not found`,
603
- headers: apiDebugConfig.headers,
604
- timestamp: new Date().toISOString()
605
- };
606
- }
607
- } catch (err) {
608
- throw new Error(`Failed to delete header: ${err.message}`);
609
- }
610
- } else if (action === 'search') {
611
- const { keyword } = params;
612
- if (!keyword) {
613
- throw new Error('Missing keyword parameter for search action');
614
- }
615
-
616
- try {
617
- const apiDebugConfig = loadApiConfig();
618
- let searchResults = [];
619
-
620
- if (apiDebugConfig.list && Array.isArray(apiDebugConfig.list)) {
621
- searchResults = apiDebugConfig.list.filter((item) => {
622
- return item.url.toLowerCase().includes(keyword.toLowerCase()) || item.description.toLowerCase().includes(keyword.toLowerCase());
623
- });
624
- }
625
-
153
+ } else {
626
154
  return {
627
- success: true,
628
- message: `Found ${searchResults.length} matching API(s) for keyword: "${keyword}"`,
629
- keyword: keyword,
630
- results: searchResults,
631
- totalCount: searchResults.length,
155
+ success: false,
156
+ message: `Failed to execute API: ${url}`,
157
+ request: {
158
+ url: finalRequestUrl,
159
+ method: requestMethod,
160
+ headers: finalHeaders,
161
+ body: requestBody
162
+ },
163
+ error: error || (response ? `HTTP ${response.status}: ${response.statusText}` : 'Request failed'),
632
164
  timestamp: new Date().toISOString()
633
-
634
-
635
- }
636
-
637
- } catch (err) {
638
- throw new Error(`Failed to search APIs: ${err.message}`);
165
+ };
639
166
  }
640
- } else {
641
- throw new Error('Invalid action. Must be "get", "set", "delete", "execute", "updateBaseUrl", "updateHeaders", "deleteHeader", or "search"');
167
+ } catch (err) {
168
+ throw new Error(`Failed to execute API: ${err.message}`);
642
169
  }
643
170
  }
644
171
 
645
-
646
172
  module.exports = api_debug;