@elliotding/ai-agent-mcp 0.1.25 → 0.1.26

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 (237) hide show
  1. package/package.json +4 -1
  2. package/.prompt-cache/cmd-cmd-client-sdk-ai-hub-generate-testcase.md +0 -101
  3. package/.prompt-cache/cmd-cmd-client-sdk-ai-hub-submit_zct_job.md +0 -158
  4. package/.prompt-cache/skill-skill-client-sdk-ai-hub-analyze-conf-status.md +0 -311
  5. package/.prompt-cache/skill-skill-client-sdk-ai-hub-analyze-sdk-log.md +0 -64
  6. package/.prompt-cache/skill-skill-client-sdk-ai-hub-analyze-zmb-log-errors.md +0 -84
  7. package/ai-resource-telemetry.json +0 -40
  8. package/dist/api/cached-client.d.ts +0 -48
  9. package/dist/api/cached-client.d.ts.map +0 -1
  10. package/dist/api/cached-client.js +0 -126
  11. package/dist/api/cached-client.js.map +0 -1
  12. package/dist/api/client.d.ts +0 -281
  13. package/dist/api/client.d.ts.map +0 -1
  14. package/dist/api/client.js +0 -371
  15. package/dist/api/client.js.map +0 -1
  16. package/dist/auth/index.d.ts +0 -8
  17. package/dist/auth/index.d.ts.map +0 -1
  18. package/dist/auth/index.js +0 -26
  19. package/dist/auth/index.js.map +0 -1
  20. package/dist/auth/middleware.d.ts +0 -36
  21. package/dist/auth/middleware.d.ts.map +0 -1
  22. package/dist/auth/middleware.js +0 -194
  23. package/dist/auth/middleware.js.map +0 -1
  24. package/dist/auth/permissions.d.ts +0 -60
  25. package/dist/auth/permissions.d.ts.map +0 -1
  26. package/dist/auth/permissions.js +0 -262
  27. package/dist/auth/permissions.js.map +0 -1
  28. package/dist/auth/token-validator.d.ts +0 -52
  29. package/dist/auth/token-validator.d.ts.map +0 -1
  30. package/dist/auth/token-validator.js +0 -215
  31. package/dist/auth/token-validator.js.map +0 -1
  32. package/dist/cache/cache-manager.d.ts +0 -49
  33. package/dist/cache/cache-manager.d.ts.map +0 -1
  34. package/dist/cache/cache-manager.js +0 -191
  35. package/dist/cache/cache-manager.js.map +0 -1
  36. package/dist/cache/index.d.ts +0 -6
  37. package/dist/cache/index.d.ts.map +0 -1
  38. package/dist/cache/index.js +0 -12
  39. package/dist/cache/index.js.map +0 -1
  40. package/dist/cache/redis-client.d.ts +0 -45
  41. package/dist/cache/redis-client.d.ts.map +0 -1
  42. package/dist/cache/redis-client.js +0 -210
  43. package/dist/cache/redis-client.js.map +0 -1
  44. package/dist/config/constants.d.ts +0 -28
  45. package/dist/config/constants.d.ts.map +0 -1
  46. package/dist/config/constants.js +0 -31
  47. package/dist/config/constants.js.map +0 -1
  48. package/dist/config/index.d.ts +0 -71
  49. package/dist/config/index.d.ts.map +0 -1
  50. package/dist/config/index.js +0 -190
  51. package/dist/config/index.js.map +0 -1
  52. package/dist/filesystem/manager.d.ts +0 -45
  53. package/dist/filesystem/manager.d.ts.map +0 -1
  54. package/dist/filesystem/manager.js +0 -246
  55. package/dist/filesystem/manager.js.map +0 -1
  56. package/dist/git/multi-source-manager.d.ts +0 -78
  57. package/dist/git/multi-source-manager.d.ts.map +0 -1
  58. package/dist/git/multi-source-manager.js +0 -577
  59. package/dist/git/multi-source-manager.js.map +0 -1
  60. package/dist/git/operations.d.ts +0 -27
  61. package/dist/git/operations.d.ts.map +0 -1
  62. package/dist/git/operations.js +0 -83
  63. package/dist/git/operations.js.map +0 -1
  64. package/dist/index.d.ts +0 -6
  65. package/dist/index.d.ts.map +0 -1
  66. package/dist/index.js +0 -122
  67. package/dist/index.js.map +0 -1
  68. package/dist/monitoring/health.d.ts +0 -35
  69. package/dist/monitoring/health.d.ts.map +0 -1
  70. package/dist/monitoring/health.js +0 -105
  71. package/dist/monitoring/health.js.map +0 -1
  72. package/dist/prompts/cache.d.ts +0 -69
  73. package/dist/prompts/cache.d.ts.map +0 -1
  74. package/dist/prompts/cache.js +0 -163
  75. package/dist/prompts/cache.js.map +0 -1
  76. package/dist/prompts/generator.d.ts +0 -49
  77. package/dist/prompts/generator.d.ts.map +0 -1
  78. package/dist/prompts/generator.js +0 -160
  79. package/dist/prompts/generator.js.map +0 -1
  80. package/dist/prompts/index.d.ts +0 -13
  81. package/dist/prompts/index.d.ts.map +0 -1
  82. package/dist/prompts/index.js +0 -24
  83. package/dist/prompts/index.js.map +0 -1
  84. package/dist/prompts/manager.d.ts +0 -207
  85. package/dist/prompts/manager.d.ts.map +0 -1
  86. package/dist/prompts/manager.js +0 -566
  87. package/dist/prompts/manager.js.map +0 -1
  88. package/dist/resources/index.d.ts +0 -6
  89. package/dist/resources/index.d.ts.map +0 -1
  90. package/dist/resources/index.js +0 -10
  91. package/dist/resources/index.js.map +0 -1
  92. package/dist/resources/loader.d.ts +0 -88
  93. package/dist/resources/loader.d.ts.map +0 -1
  94. package/dist/resources/loader.js +0 -492
  95. package/dist/resources/loader.js.map +0 -1
  96. package/dist/server/http.d.ts +0 -57
  97. package/dist/server/http.d.ts.map +0 -1
  98. package/dist/server/http.js +0 -435
  99. package/dist/server/http.js.map +0 -1
  100. package/dist/server.d.ts +0 -13
  101. package/dist/server.d.ts.map +0 -1
  102. package/dist/server.js +0 -201
  103. package/dist/server.js.map +0 -1
  104. package/dist/session/manager.d.ts +0 -91
  105. package/dist/session/manager.d.ts.map +0 -1
  106. package/dist/session/manager.js +0 -251
  107. package/dist/session/manager.js.map +0 -1
  108. package/dist/telemetry/index.d.ts +0 -3
  109. package/dist/telemetry/index.d.ts.map +0 -1
  110. package/dist/telemetry/index.js +0 -7
  111. package/dist/telemetry/index.js.map +0 -1
  112. package/dist/telemetry/manager.d.ts +0 -151
  113. package/dist/telemetry/manager.d.ts.map +0 -1
  114. package/dist/telemetry/manager.js +0 -367
  115. package/dist/telemetry/manager.js.map +0 -1
  116. package/dist/tools/index.d.ts +0 -13
  117. package/dist/tools/index.d.ts.map +0 -1
  118. package/dist/tools/index.js +0 -29
  119. package/dist/tools/index.js.map +0 -1
  120. package/dist/tools/manage-subscription.d.ts +0 -47
  121. package/dist/tools/manage-subscription.d.ts.map +0 -1
  122. package/dist/tools/manage-subscription.js +0 -317
  123. package/dist/tools/manage-subscription.js.map +0 -1
  124. package/dist/tools/registry.d.ts +0 -40
  125. package/dist/tools/registry.d.ts.map +0 -1
  126. package/dist/tools/registry.js +0 -85
  127. package/dist/tools/registry.js.map +0 -1
  128. package/dist/tools/resolve-prompt-content.d.ts +0 -35
  129. package/dist/tools/resolve-prompt-content.d.ts.map +0 -1
  130. package/dist/tools/resolve-prompt-content.js +0 -99
  131. package/dist/tools/resolve-prompt-content.js.map +0 -1
  132. package/dist/tools/search-resources.d.ts +0 -35
  133. package/dist/tools/search-resources.d.ts.map +0 -1
  134. package/dist/tools/search-resources.js +0 -159
  135. package/dist/tools/search-resources.js.map +0 -1
  136. package/dist/tools/sync-resources.d.ts +0 -54
  137. package/dist/tools/sync-resources.d.ts.map +0 -1
  138. package/dist/tools/sync-resources.js +0 -735
  139. package/dist/tools/sync-resources.js.map +0 -1
  140. package/dist/tools/track-usage.d.ts +0 -63
  141. package/dist/tools/track-usage.d.ts.map +0 -1
  142. package/dist/tools/track-usage.js +0 -90
  143. package/dist/tools/track-usage.js.map +0 -1
  144. package/dist/tools/uninstall-resource.d.ts +0 -30
  145. package/dist/tools/uninstall-resource.d.ts.map +0 -1
  146. package/dist/tools/uninstall-resource.js +0 -174
  147. package/dist/tools/uninstall-resource.js.map +0 -1
  148. package/dist/tools/upload-resource.d.ts +0 -81
  149. package/dist/tools/upload-resource.d.ts.map +0 -1
  150. package/dist/tools/upload-resource.js +0 -393
  151. package/dist/tools/upload-resource.js.map +0 -1
  152. package/dist/transport/sse.d.ts +0 -29
  153. package/dist/transport/sse.d.ts.map +0 -1
  154. package/dist/transport/sse.js +0 -271
  155. package/dist/transport/sse.js.map +0 -1
  156. package/dist/types/errors.d.ts +0 -60
  157. package/dist/types/errors.d.ts.map +0 -1
  158. package/dist/types/errors.js +0 -112
  159. package/dist/types/errors.js.map +0 -1
  160. package/dist/types/index.d.ts +0 -7
  161. package/dist/types/index.d.ts.map +0 -1
  162. package/dist/types/index.js +0 -23
  163. package/dist/types/index.js.map +0 -1
  164. package/dist/types/mcp.d.ts +0 -50
  165. package/dist/types/mcp.d.ts.map +0 -1
  166. package/dist/types/mcp.js +0 -6
  167. package/dist/types/mcp.js.map +0 -1
  168. package/dist/types/resources.d.ts +0 -109
  169. package/dist/types/resources.d.ts.map +0 -1
  170. package/dist/types/resources.js +0 -7
  171. package/dist/types/resources.js.map +0 -1
  172. package/dist/types/tools.d.ts +0 -253
  173. package/dist/types/tools.d.ts.map +0 -1
  174. package/dist/types/tools.js +0 -6
  175. package/dist/types/tools.js.map +0 -1
  176. package/dist/utils/cursor-paths.d.ts +0 -84
  177. package/dist/utils/cursor-paths.d.ts.map +0 -1
  178. package/dist/utils/cursor-paths.js +0 -166
  179. package/dist/utils/cursor-paths.js.map +0 -1
  180. package/dist/utils/log-cleaner.d.ts +0 -18
  181. package/dist/utils/log-cleaner.d.ts.map +0 -1
  182. package/dist/utils/log-cleaner.js +0 -112
  183. package/dist/utils/log-cleaner.js.map +0 -1
  184. package/dist/utils/logger.d.ts +0 -59
  185. package/dist/utils/logger.d.ts.map +0 -1
  186. package/dist/utils/logger.js +0 -292
  187. package/dist/utils/logger.js.map +0 -1
  188. package/dist/utils/validation.d.ts +0 -58
  189. package/dist/utils/validation.d.ts.map +0 -1
  190. package/dist/utils/validation.js +0 -214
  191. package/dist/utils/validation.js.map +0 -1
  192. package/src/api/cached-client.ts +0 -144
  193. package/src/api/client.ts +0 -697
  194. package/src/auth/index.ts +0 -11
  195. package/src/auth/middleware.ts +0 -244
  196. package/src/auth/permissions.ts +0 -323
  197. package/src/auth/token-validator.ts +0 -292
  198. package/src/cache/cache-manager.ts +0 -243
  199. package/src/cache/index.ts +0 -6
  200. package/src/cache/redis-client.ts +0 -249
  201. package/src/config/constants.ts +0 -33
  202. package/src/config/index.ts +0 -269
  203. package/src/filesystem/manager.ts +0 -235
  204. package/src/git/multi-source-manager.ts +0 -654
  205. package/src/git/operations.ts +0 -93
  206. package/src/index.ts +0 -157
  207. package/src/monitoring/health.ts +0 -132
  208. package/src/prompts/cache.ts +0 -140
  209. package/src/prompts/generator.ts +0 -143
  210. package/src/prompts/index.ts +0 -20
  211. package/src/prompts/manager.ts +0 -718
  212. package/src/resources/index.ts +0 -13
  213. package/src/resources/loader.ts +0 -563
  214. package/src/server/http.ts +0 -549
  215. package/src/server.ts +0 -206
  216. package/src/session/manager.ts +0 -296
  217. package/src/telemetry/index.ts +0 -10
  218. package/src/telemetry/manager.ts +0 -419
  219. package/src/tools/index.ts +0 -13
  220. package/src/tools/manage-subscription.ts +0 -388
  221. package/src/tools/registry.ts +0 -97
  222. package/src/tools/resolve-prompt-content.ts +0 -113
  223. package/src/tools/search-resources.ts +0 -185
  224. package/src/tools/sync-resources.ts +0 -829
  225. package/src/tools/track-usage.ts +0 -113
  226. package/src/tools/uninstall-resource.ts +0 -199
  227. package/src/tools/upload-resource.ts +0 -431
  228. package/src/transport/sse.ts +0 -308
  229. package/src/types/errors.ts +0 -146
  230. package/src/types/index.ts +0 -7
  231. package/src/types/mcp.ts +0 -61
  232. package/src/types/resources.ts +0 -141
  233. package/src/types/tools.ts +0 -305
  234. package/src/utils/cursor-paths.ts +0 -135
  235. package/src/utils/log-cleaner.ts +0 -92
  236. package/src/utils/logger.ts +0 -333
  237. package/src/utils/validation.ts +0 -262
@@ -1,333 +0,0 @@
1
- /**
2
- * Logging Module
3
- * Structured logging using pino with daily file rotation.
4
- *
5
- * Files are named app-YYYY-MM-DD.log. Rotation is implemented by:
6
- * 1. Starting pino/file pointing at today's file (fixed fd, opened at startup).
7
- * 2. A midnight timer in the main thread spawns a fresh child process for the
8
- * next day's file via a second pino instance — but that would mean two loggers.
9
- *
10
- * Practical solution used here:
11
- * - Use pino-roll (daily, dateFormat: 'yyyy-MM-dd').
12
- * - pino-roll produces Logs/app.YYYY-MM-DD.1.log (date + sequential counter).
13
- * - At midnight + 2 s we rename the *previous* day's app.YYYY-MM-DD.1.log
14
- * → app-YYYY-MM-DD.log so the canonical name is clean.
15
- * - The active (today's) file keeps the pino-roll name until it rotates.
16
- * - log-cleaner scans by mtime so it handles both naming conventions.
17
- */
18
-
19
- import pino from 'pino';
20
- import * as path from 'path';
21
- import * as fs from 'fs';
22
- import { config } from '../config';
23
-
24
- // Ensure logs directory exists (relative to project root)
25
- const logsDir = path.resolve(process.cwd(), config.logging.dir);
26
- if (!fs.existsSync(logsDir)) {
27
- fs.mkdirSync(logsDir, { recursive: true });
28
- }
29
-
30
- /** ms until the next local midnight + 1 s buffer. */
31
- function msUntilMidnight(): number {
32
- const now = new Date();
33
- const next = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 0, 0, 1);
34
- return next.getTime() - now.getTime();
35
- }
36
-
37
- /**
38
- * Rename yesterday's pino-roll file (app.YYYY-MM-DD.1.log)
39
- * to the canonical name (app-YYYY-MM-DD.log) once it has been rotated away.
40
- */
41
- function renameYesterdayLog(): void {
42
- const d = new Date();
43
- d.setDate(d.getDate() - 1);
44
- const dateStr = [
45
- d.getFullYear(),
46
- String(d.getMonth() + 1).padStart(2, '0'),
47
- String(d.getDate()).padStart(2, '0'),
48
- ].join('-');
49
-
50
- const src = path.join(logsDir, `app.${dateStr}.1.log`);
51
- const dst = path.join(logsDir, `app-${dateStr}.log`);
52
- if (fs.existsSync(src) && !fs.existsSync(dst)) {
53
- try { fs.renameSync(src, dst); } catch { /* non-fatal */ }
54
- }
55
- }
56
-
57
- // Fire rename at midnight + 2 s, then every 24 h.
58
- setTimeout(() => {
59
- renameYesterdayLog();
60
- setInterval(renameYesterdayLog, 24 * 60 * 60 * 1000).unref();
61
- }, msUntilMidnight() + 2000).unref();
62
-
63
- // Create pino logger with multi-target transport
64
- export const logger = pino({
65
- level: config.logLevel,
66
- timestamp: pino.stdTimeFunctions.isoTime,
67
- base: {
68
- service: 'csp-ai-agent-mcp',
69
- },
70
- transport: {
71
- targets: [
72
- // Console output (pretty format in development)
73
- {
74
- target: 'pino-pretty',
75
- level: config.logLevel,
76
- options: {
77
- colorize: true,
78
- translateTime: 'SYS:standard',
79
- ignore: 'pid,hostname',
80
- singleLine: false,
81
- },
82
- },
83
- // Daily-rotating file output.
84
- // Active file: Logs/app.YYYY-MM-DD.1.log
85
- // After midnight rename: Logs/app-YYYY-MM-DD.log
86
- {
87
- target: 'pino-roll',
88
- level: config.logLevel,
89
- options: {
90
- file: path.join(logsDir, 'app'),
91
- frequency: 'daily',
92
- dateFormat: 'yyyy-MM-dd',
93
- mkdir: true,
94
- sync: false,
95
- },
96
- },
97
- ],
98
- },
99
- });
100
-
101
- /**
102
- * Log MCP Tool call
103
- */
104
- export function logToolCall(
105
- toolName: string,
106
- userId: string,
107
- params: Record<string, unknown>,
108
- durationMs: number
109
- ): void {
110
- logger.info(
111
- {
112
- type: 'tool_call',
113
- toolName,
114
- userId,
115
- params,
116
- durationMs,
117
- },
118
- `Tool ${toolName} called by ${userId} (${durationMs}ms)`
119
- );
120
- }
121
-
122
- /**
123
- * Log error with context
124
- */
125
- export function logError(error: Error, context?: Record<string, unknown>): void {
126
- logger.error(
127
- {
128
- type: 'error',
129
- error: {
130
- message: error.message,
131
- stack: error.stack,
132
- name: error.name,
133
- },
134
- ...context,
135
- },
136
- error.message
137
- );
138
- }
139
-
140
- /**
141
- * Log performance metrics
142
- */
143
- export function logPerformance(
144
- operation: string,
145
- durationMs: number,
146
- metadata?: Record<string, unknown>
147
- ): void {
148
- logger.info(
149
- {
150
- type: 'performance',
151
- operation,
152
- durationMs,
153
- ...metadata,
154
- },
155
- `${operation} completed in ${durationMs}ms`
156
- );
157
- }
158
-
159
- /**
160
- * Log API request with detailed information
161
- */
162
- export function logApiRequest(
163
- method: string,
164
- url: string,
165
- statusCode: number,
166
- durationMs: number,
167
- requestData?: unknown,
168
- responseData?: unknown,
169
- headers?: Record<string, string>
170
- ): void {
171
- logger.info(
172
- {
173
- type: 'api_request',
174
- method,
175
- url,
176
- statusCode,
177
- durationMs,
178
- requestData: requestData ? JSON.stringify(requestData).substring(0, 500) : undefined,
179
- responseData: responseData ? JSON.stringify(responseData).substring(0, 1000) : undefined,
180
- headers: headers ? sanitizeHeaders(headers) : undefined,
181
- },
182
- `${method} ${url} - ${statusCode} (${durationMs}ms)`
183
- );
184
- }
185
-
186
- /**
187
- * Log API error with full details
188
- */
189
- export function logApiError(
190
- method: string,
191
- url: string,
192
- error: Error,
193
- requestData?: unknown,
194
- statusCode?: number
195
- ): void {
196
- logger.error(
197
- {
198
- type: 'api_error',
199
- method,
200
- url,
201
- statusCode,
202
- requestData: requestData ? JSON.stringify(requestData).substring(0, 500) : undefined,
203
- error: {
204
- message: error.message,
205
- stack: error.stack,
206
- name: error.name,
207
- },
208
- },
209
- `API Error: ${method} ${url} - ${error.message}`
210
- );
211
- }
212
-
213
- /**
214
- * Log tool execution step
215
- */
216
- export function logToolStep(
217
- toolName: string,
218
- step: string,
219
- details?: Record<string, unknown>
220
- ): void {
221
- logger.debug(
222
- {
223
- type: 'tool_step',
224
- toolName,
225
- step,
226
- ...details,
227
- },
228
- `[${toolName}] ${step}`
229
- );
230
- }
231
-
232
- /**
233
- * Log tool execution result
234
- */
235
- export function logToolResult(
236
- toolName: string,
237
- success: boolean,
238
- result?: unknown,
239
- error?: Error
240
- ): void {
241
- const level = success ? 'info' : 'error';
242
- logger[level](
243
- {
244
- type: 'tool_result',
245
- toolName,
246
- success,
247
- result: result ? JSON.stringify(result).substring(0, 1000) : undefined,
248
- error: error ? {
249
- message: error.message,
250
- stack: error.stack,
251
- name: error.name,
252
- } : undefined,
253
- },
254
- `[${toolName}] ${success ? 'Success' : 'Failed'}`
255
- );
256
- }
257
-
258
- /**
259
- * Log authentication attempt
260
- */
261
- export function logAuthAttempt(
262
- type: 'token_validation' | 'permission_check',
263
- success: boolean,
264
- details?: Record<string, unknown>
265
- ): void {
266
- const level = success ? 'info' : 'warn';
267
- logger[level](
268
- {
269
- type: 'auth',
270
- operation: type,
271
- success,
272
- ...details,
273
- },
274
- `Auth ${type}: ${success ? 'Success' : 'Failed'}`
275
- );
276
- }
277
-
278
- /**
279
- * Log cache operation
280
- */
281
- export function logCacheOperation(
282
- operation: 'get' | 'set' | 'delete' | 'hit' | 'miss',
283
- key: string,
284
- details?: Record<string, unknown>
285
- ): void {
286
- logger.debug(
287
- {
288
- type: 'cache',
289
- operation,
290
- key,
291
- ...details,
292
- },
293
- `Cache ${operation}: ${key}`
294
- );
295
- }
296
-
297
- /**
298
- * Sanitize headers to remove sensitive information
299
- */
300
- function sanitizeHeaders(headers: Record<string, string>): Record<string, string> {
301
- const sanitized = { ...headers };
302
-
303
- // Mask Authorization header
304
- if (sanitized['Authorization'] || sanitized['authorization']) {
305
- const authKey = sanitized['Authorization'] ? 'Authorization' : 'authorization';
306
- const authValue = sanitized[authKey];
307
- if (authValue && authValue.startsWith('Bearer ')) {
308
- const token = authValue.substring(7);
309
- sanitized[authKey] = `Bearer ${token.substring(0, 10)}...${token.substring(token.length - 10)}`;
310
- }
311
- }
312
-
313
- return sanitized;
314
- }
315
-
316
- /**
317
- * Log Git operation
318
- */
319
- export function logGitOperation(
320
- operation: string,
321
- details: Record<string, unknown>,
322
- durationMs: number
323
- ): void {
324
- logger.info(
325
- {
326
- type: 'git_operation',
327
- operation,
328
- ...details,
329
- durationMs,
330
- },
331
- `Git ${operation} completed (${durationMs}ms)`
332
- );
333
- }
@@ -1,262 +0,0 @@
1
- /**
2
- * Request Validation Utilities
3
- * Enhanced validation with clear error messages
4
- */
5
-
6
- export interface ValidationError {
7
- field: string;
8
- message: string;
9
- expected?: string;
10
- received?: any;
11
- suggestion?: string;
12
- }
13
-
14
- export class RequestValidationError extends Error {
15
- public errors: ValidationError[];
16
- public statusCode: number;
17
-
18
- constructor(errors: ValidationError[], statusCode = 400) {
19
- const message = errors.map(e => `${e.field}: ${e.message}`).join('; ');
20
- super(message);
21
- this.name = 'RequestValidationError';
22
- this.errors = errors;
23
- this.statusCode = statusCode;
24
- }
25
-
26
- toJSON() {
27
- return {
28
- error: 'Validation Error',
29
- message: this.message,
30
- details: this.errors,
31
- };
32
- }
33
- }
34
-
35
- /**
36
- * Validate required field
37
- */
38
- export function validateRequired(
39
- value: any,
40
- fieldName: string
41
- ): ValidationError | null {
42
- if (value === undefined || value === null || value === '') {
43
- return {
44
- field: fieldName,
45
- message: `Missing required field: '${fieldName}'`,
46
- expected: 'non-empty value',
47
- received: typeof value,
48
- };
49
- }
50
- return null;
51
- }
52
-
53
- /**
54
- * Validate string type
55
- */
56
- export function validateString(
57
- value: any,
58
- fieldName: string
59
- ): ValidationError | null {
60
- if (typeof value !== 'string') {
61
- return {
62
- field: fieldName,
63
- message: `Field '${fieldName}' must be a string`,
64
- expected: 'string',
65
- received: typeof value,
66
- };
67
- }
68
- return null;
69
- }
70
-
71
- /**
72
- * Validate enum value
73
- */
74
- export function validateEnum(
75
- value: any,
76
- fieldName: string,
77
- allowedValues: readonly string[]
78
- ): ValidationError | null {
79
- if (!allowedValues.includes(value)) {
80
- // Find closest match for suggestion
81
- const suggestion = findClosestMatch(value, allowedValues);
82
-
83
- return {
84
- field: fieldName,
85
- message: `Field '${fieldName}' has invalid value`,
86
- expected: `one of: ${allowedValues.map(v => `'${v}'`).join(', ')}`,
87
- received: value,
88
- suggestion: suggestion ? `Did you mean '${suggestion}'?` : undefined,
89
- };
90
- }
91
- return null;
92
- }
93
-
94
- /**
95
- * Validate array type
96
- */
97
- export function validateArray(
98
- value: any,
99
- fieldName: string
100
- ): ValidationError | null {
101
- if (!Array.isArray(value)) {
102
- return {
103
- field: fieldName,
104
- message: `Field '${fieldName}' must be an array`,
105
- expected: 'array',
106
- received: typeof value,
107
- };
108
- }
109
- return null;
110
- }
111
-
112
- /**
113
- * Validate object type
114
- */
115
- export function validateObject(
116
- value: any,
117
- fieldName: string
118
- ): ValidationError | null {
119
- if (typeof value !== 'object' || value === null || Array.isArray(value)) {
120
- return {
121
- field: fieldName,
122
- message: `Field '${fieldName}' must be an object`,
123
- expected: 'object',
124
- received: Array.isArray(value) ? 'array' : typeof value,
125
- };
126
- }
127
- return null;
128
- }
129
-
130
- /**
131
- * Validate boolean type
132
- */
133
- export function validateBoolean(
134
- value: any,
135
- fieldName: string
136
- ): ValidationError | null {
137
- if (typeof value !== 'boolean') {
138
- return {
139
- field: fieldName,
140
- message: `Field '${fieldName}' must be a boolean`,
141
- expected: 'boolean (true or false)',
142
- received: typeof value,
143
- };
144
- }
145
- return null;
146
- }
147
-
148
- /**
149
- * Validate number type
150
- */
151
- export function validateNumber(
152
- value: any,
153
- fieldName: string
154
- ): ValidationError | null {
155
- if (typeof value !== 'number' || isNaN(value)) {
156
- return {
157
- field: fieldName,
158
- message: `Field '${fieldName}' must be a number`,
159
- expected: 'number',
160
- received: typeof value,
161
- };
162
- }
163
- return null;
164
- }
165
-
166
- /**
167
- * Find closest string match (simple Levenshtein distance)
168
- */
169
- function findClosestMatch(
170
- value: string,
171
- candidates: readonly string[]
172
- ): string | null {
173
- if (!value || typeof value !== 'string') {
174
- return null;
175
- }
176
-
177
- let minDistance = Infinity;
178
- let closest: string | null = null;
179
-
180
- for (const candidate of candidates) {
181
- const distance = levenshteinDistance(
182
- value.toLowerCase(),
183
- candidate.toLowerCase()
184
- );
185
- if (distance < minDistance && distance <= 2) {
186
- // Only suggest if distance is small
187
- minDistance = distance;
188
- closest = candidate;
189
- }
190
- }
191
-
192
- return closest;
193
- }
194
-
195
- /**
196
- * Calculate Levenshtein distance between two strings
197
- */
198
- function levenshteinDistance(a: string, b: string): number {
199
- const matrix: number[][] = [];
200
-
201
- for (let i = 0; i <= b.length; i++) {
202
- matrix[i] = [i];
203
- }
204
-
205
- for (let j = 0; j <= a.length; j++) {
206
- matrix[0]![j] = j;
207
- }
208
-
209
- for (let i = 1; i <= b.length; i++) {
210
- for (let j = 1; j <= a.length; j++) {
211
- if (b.charAt(i - 1) === a.charAt(j - 1)) {
212
- matrix[i]![j] = matrix[i - 1]![j - 1]!;
213
- } else {
214
- matrix[i]![j] = Math.min(
215
- matrix[i - 1]![j - 1]! + 1, // substitution
216
- matrix[i]![j - 1]! + 1, // insertion
217
- matrix[i - 1]![j]! + 1 // deletion
218
- );
219
- }
220
- }
221
- }
222
-
223
- return matrix[b.length]![a.length]!;
224
- }
225
-
226
- /**
227
- * Validate SSE connection parameters
228
- */
229
- export function validateSSEConnectionParams(_body: any): ValidationError[] {
230
- const errors: ValidationError[] = [];
231
-
232
- // Validate Authorization header (will be checked in middleware)
233
- // No body parameters required for SSE connection
234
-
235
- return errors;
236
- }
237
-
238
- /**
239
- * Validate message parameters
240
- */
241
- export function validateMessageParams(body: any): ValidationError[] {
242
- const errors: ValidationError[] = [];
243
-
244
- // sessionId is required
245
- const sessionIdError = validateRequired(body.sessionId, 'sessionId');
246
- if (sessionIdError) {
247
- errors.push(sessionIdError);
248
- } else {
249
- const sessionIdTypeError = validateString(body.sessionId, 'sessionId');
250
- if (sessionIdTypeError) {
251
- errors.push(sessionIdTypeError);
252
- }
253
- }
254
-
255
- // message is required
256
- const messageError = validateRequired(body.message, 'message');
257
- if (messageError) {
258
- errors.push(messageError);
259
- }
260
-
261
- return errors;
262
- }