|
5 | 5 | * especially useful for AI agent integration and non-interactive usage. |
6 | 6 | */ |
7 | 7 |
|
| 8 | +/** |
| 9 | + * Safely serialize data, handling non-JSON serializable values |
| 10 | + * @param {any} data Data to serialize |
| 11 | + * @returns {any} Safely serializable value |
| 12 | + */ |
| 13 | +function safeSerialize(data) { |
| 14 | + const seen = new WeakSet(); |
| 15 | + |
| 16 | + return JSON.parse(JSON.stringify(data, (key, value) => { |
| 17 | + // Handle undefined |
| 18 | + if (value === undefined) return null; |
| 19 | + |
| 20 | + // Handle functions |
| 21 | + if (typeof value === 'function') return '[Function]'; |
| 22 | + |
| 23 | + // Handle error objects |
| 24 | + if (value instanceof Error) { |
| 25 | + return { |
| 26 | + name: value.name, |
| 27 | + message: value.message, |
| 28 | + stack: value.stack |
| 29 | + }; |
| 30 | + } |
| 31 | + |
| 32 | + // Handle circular references |
| 33 | + if (typeof value === 'object' && value !== null) { |
| 34 | + if (seen.has(value)) { |
| 35 | + return '[Circular]'; |
| 36 | + } |
| 37 | + seen.add(value); |
| 38 | + } |
| 39 | + |
| 40 | + return value; |
| 41 | + })); |
| 42 | +} |
| 43 | + |
8 | 44 | /** |
9 | 45 | * Format a result into a standardized JSON structure |
10 | 46 | * @param {any} data Result data to format |
11 | 47 | * @param {object} options Formatting options |
12 | 48 | * @returns {object} Standardized JSON object |
13 | 49 | */ |
14 | 50 | function formatJsonResult(data, options = {}) { |
15 | | - // Check if data already has a standardized format |
16 | | - if (data && typeof data === 'object' && 'success' in data) { |
17 | | - // Just ensure consistent structure |
| 51 | + try { |
| 52 | + // Check if data already has a standardized format |
| 53 | + if (data && typeof data === 'object' && 'success' in data) { |
| 54 | + // Just ensure consistent structure |
| 55 | + return { |
| 56 | + success: !!data.success, |
| 57 | + data: safeSerialize(data.data || data.result || null), |
| 58 | + error: data.error || null, |
| 59 | + metadata: { |
| 60 | + ...safeSerialize(data.metadata || {}), |
| 61 | + timestamp: new Date().toISOString() |
| 62 | + } |
| 63 | + }; |
| 64 | + } |
| 65 | + |
| 66 | + // Format data into standardized structure |
| 67 | + return { |
| 68 | + success: !options.error, |
| 69 | + data: safeSerialize(data), |
| 70 | + error: options.error || null, |
| 71 | + metadata: { |
| 72 | + timestamp: new Date().toISOString(), |
| 73 | + ...safeSerialize(options.metadata || {}) |
| 74 | + } |
| 75 | + }; |
| 76 | + } catch (error) { |
| 77 | + // Provide a fallback if serialization fails |
18 | 78 | return { |
19 | | - success: !!data.success, |
20 | | - data: data.data || data.result || null, |
21 | | - error: data.error || null, |
| 79 | + success: false, |
| 80 | + data: null, |
| 81 | + error: `Failed to serialize data: ${error.message}`, |
22 | 82 | metadata: { |
23 | | - ...data.metadata, |
24 | | - timestamp: new Date().toISOString() |
| 83 | + timestamp: new Date().toISOString(), |
| 84 | + originalDataType: data === null ? 'null' : typeof data, |
| 85 | + isArray: Array.isArray(data) |
25 | 86 | } |
26 | 87 | }; |
27 | 88 | } |
28 | | - |
29 | | - // Format data into standardized structure |
30 | | - return { |
31 | | - success: !options.error, |
32 | | - data: data, |
33 | | - error: options.error || null, |
34 | | - metadata: { |
35 | | - timestamp: new Date().toISOString(), |
36 | | - ...options.metadata |
37 | | - } |
38 | | - }; |
39 | 89 | } |
40 | 90 |
|
41 | 91 | /** |
|
0 commit comments