mcp-image 0.1.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.
- package/LICENSE +21 -0
- package/README.md +163 -0
- package/dist/api/geminiClient.d.ts +55 -0
- package/dist/api/geminiClient.d.ts.map +1 -0
- package/dist/api/geminiClient.js +194 -0
- package/dist/api/geminiClient.js.map +1 -0
- package/dist/api/urlContextClient.d.ts +149 -0
- package/dist/api/urlContextClient.d.ts.map +1 -0
- package/dist/api/urlContextClient.js +320 -0
- package/dist/api/urlContextClient.js.map +1 -0
- package/dist/business/errorHandler.d.ts +97 -0
- package/dist/business/errorHandler.d.ts.map +1 -0
- package/dist/business/errorHandler.js +511 -0
- package/dist/business/errorHandler.js.map +1 -0
- package/dist/business/fileManager.d.ts +20 -0
- package/dist/business/fileManager.d.ts.map +1 -0
- package/dist/business/fileManager.js +112 -0
- package/dist/business/fileManager.js.map +1 -0
- package/dist/business/imageGenerator.d.ts +64 -0
- package/dist/business/imageGenerator.d.ts.map +1 -0
- package/dist/business/imageGenerator.js +147 -0
- package/dist/business/imageGenerator.js.map +1 -0
- package/dist/business/imageGeneratorRobust.d.ts +60 -0
- package/dist/business/imageGeneratorRobust.d.ts.map +1 -0
- package/dist/business/imageGeneratorRobust.js +242 -0
- package/dist/business/imageGeneratorRobust.js.map +1 -0
- package/dist/business/inputValidator.d.ts +29 -0
- package/dist/business/inputValidator.d.ts.map +1 -0
- package/dist/business/inputValidator.js +132 -0
- package/dist/business/inputValidator.js.map +1 -0
- package/dist/business/performanceManager.d.ts +88 -0
- package/dist/business/performanceManager.d.ts.map +1 -0
- package/dist/business/performanceManager.js +142 -0
- package/dist/business/performanceManager.js.map +1 -0
- package/dist/business/responseBuilder.d.ts +20 -0
- package/dist/business/responseBuilder.d.ts.map +1 -0
- package/dist/business/responseBuilder.js +162 -0
- package/dist/business/responseBuilder.js.map +1 -0
- package/dist/business/secureFileManager.d.ts +56 -0
- package/dist/business/secureFileManager.d.ts.map +1 -0
- package/dist/business/secureFileManager.js +185 -0
- package/dist/business/secureFileManager.js.map +1 -0
- package/dist/business/urlExtractor.d.ts +60 -0
- package/dist/business/urlExtractor.d.ts.map +1 -0
- package/dist/business/urlExtractor.js +144 -0
- package/dist/business/urlExtractor.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/server/concurrencyManager.d.ts +56 -0
- package/dist/server/concurrencyManager.d.ts.map +1 -0
- package/dist/server/concurrencyManager.js +133 -0
- package/dist/server/concurrencyManager.js.map +1 -0
- package/dist/server/errorHandler.d.ts +29 -0
- package/dist/server/errorHandler.d.ts.map +1 -0
- package/dist/server/errorHandler.js +93 -0
- package/dist/server/errorHandler.js.map +1 -0
- package/dist/server/mcpServer.d.ts +111 -0
- package/dist/server/mcpServer.d.ts.map +1 -0
- package/dist/server/mcpServer.js +353 -0
- package/dist/server/mcpServer.js.map +1 -0
- package/dist/types/mcp.d.ts +72 -0
- package/dist/types/mcp.d.ts.map +1 -0
- package/dist/types/mcp.js +7 -0
- package/dist/types/mcp.js.map +1 -0
- package/dist/types/result.d.ts +27 -0
- package/dist/types/result.d.ts.map +1 -0
- package/dist/types/result.js +31 -0
- package/dist/types/result.js.map +1 -0
- package/dist/utils/config.d.ts +26 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +53 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/errors.d.ts +84 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +218 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/logger.d.ts +80 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +223 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/security.d.ts +50 -0
- package/dist/utils/security.d.ts.map +1 -0
- package/dist/utils/security.js +153 -0
- package/dist/utils/security.js.map +1 -0
- package/package.json +73 -0
- package/vitest.config.mjs +47 -0
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comprehensive Error Handler for complete error management
|
|
3
|
+
* Provides error classification, recovery mechanisms, and structured response generation
|
|
4
|
+
*/
|
|
5
|
+
import { Err } from '../types/result';
|
|
6
|
+
import { BaseError, ConcurrencyError, FileOperationError, GeminiAPIError, InternalError, NetworkError, SecurityError, ValidationError, } from '../utils/errors';
|
|
7
|
+
import { Logger } from '../utils/logger';
|
|
8
|
+
/**
|
|
9
|
+
* Comprehensive error handler with classification and recovery capabilities
|
|
10
|
+
*/
|
|
11
|
+
export class ComprehensiveErrorHandler {
|
|
12
|
+
constructor(logger) {
|
|
13
|
+
this.logger = logger || new Logger();
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Handle any error and convert it to a structured BaseError Result
|
|
17
|
+
* @param error Error or unknown value to handle
|
|
18
|
+
* @param context Context string for logging
|
|
19
|
+
* @param operation Operation name for logging
|
|
20
|
+
* @returns Result with structured error
|
|
21
|
+
*/
|
|
22
|
+
handleError(error, context, operation) {
|
|
23
|
+
let structuredError;
|
|
24
|
+
if (error instanceof BaseError) {
|
|
25
|
+
structuredError = error;
|
|
26
|
+
}
|
|
27
|
+
else if (error instanceof Error) {
|
|
28
|
+
structuredError = this.classifyError(error, context);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
structuredError = new InternalError(`Unknown error type: ${String(error)}`, {
|
|
32
|
+
originalError: error,
|
|
33
|
+
context,
|
|
34
|
+
operation,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
// Log error with filtered sensitive information
|
|
38
|
+
this.logger.error(context, `${operation} failed`, structuredError, {
|
|
39
|
+
errorCode: structuredError.code,
|
|
40
|
+
suggestion: structuredError.suggestion,
|
|
41
|
+
timestamp: structuredError.timestamp,
|
|
42
|
+
// Don't include full context to avoid logging sensitive data
|
|
43
|
+
});
|
|
44
|
+
return Err(structuredError);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Classify a generic Error into appropriate BaseError subclass
|
|
48
|
+
* @param error Original error to classify
|
|
49
|
+
* @param context Context for additional information
|
|
50
|
+
* @returns Classified BaseError
|
|
51
|
+
*/
|
|
52
|
+
classifyError(error, context) {
|
|
53
|
+
const message = error.message.toLowerCase();
|
|
54
|
+
const stack = error.stack?.toLowerCase() || '';
|
|
55
|
+
const name = error.name.toLowerCase();
|
|
56
|
+
// Create base context for all classified errors
|
|
57
|
+
const baseContext = {
|
|
58
|
+
originalStack: error.stack,
|
|
59
|
+
originalName: error.name,
|
|
60
|
+
context,
|
|
61
|
+
};
|
|
62
|
+
// API related errors
|
|
63
|
+
if (this.isAPIError(message, stack, name)) {
|
|
64
|
+
return new GeminiAPIError(error.message, baseContext);
|
|
65
|
+
}
|
|
66
|
+
// Network related errors
|
|
67
|
+
if (this.isNetworkError(message, stack, name)) {
|
|
68
|
+
return new NetworkError(error.message, baseContext);
|
|
69
|
+
}
|
|
70
|
+
// File operation errors
|
|
71
|
+
if (this.isFileError(message, stack, name)) {
|
|
72
|
+
return new FileOperationError(error.message, baseContext);
|
|
73
|
+
}
|
|
74
|
+
// Concurrency errors
|
|
75
|
+
if (this.isConcurrencyError(message, stack, name)) {
|
|
76
|
+
return new ConcurrencyError(error.message, baseContext);
|
|
77
|
+
}
|
|
78
|
+
// Security errors
|
|
79
|
+
if (this.isSecurityError(message, stack, name)) {
|
|
80
|
+
return new SecurityError(error.message, baseContext);
|
|
81
|
+
}
|
|
82
|
+
// Validation errors
|
|
83
|
+
if (this.isValidationError(message, stack, name)) {
|
|
84
|
+
return new ValidationError(error.message, baseContext);
|
|
85
|
+
}
|
|
86
|
+
// Default to internal error
|
|
87
|
+
return new InternalError(error.message, baseContext);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Check if error is API-related with enhanced pattern matching
|
|
91
|
+
*/
|
|
92
|
+
isAPIError(message, stack, name) {
|
|
93
|
+
const apiIndicators = [
|
|
94
|
+
// Authentication and authorization
|
|
95
|
+
'api',
|
|
96
|
+
'authentication',
|
|
97
|
+
'authorization',
|
|
98
|
+
'auth',
|
|
99
|
+
'unauthorized',
|
|
100
|
+
'forbidden',
|
|
101
|
+
'access_denied',
|
|
102
|
+
'invalid_token',
|
|
103
|
+
// API specific
|
|
104
|
+
'quota',
|
|
105
|
+
'rate limit',
|
|
106
|
+
'rate-limit',
|
|
107
|
+
'ratelimit',
|
|
108
|
+
'gemini',
|
|
109
|
+
'model',
|
|
110
|
+
'endpoint',
|
|
111
|
+
// HTTP status patterns
|
|
112
|
+
'400',
|
|
113
|
+
'401',
|
|
114
|
+
'403',
|
|
115
|
+
'429',
|
|
116
|
+
'500',
|
|
117
|
+
'502',
|
|
118
|
+
'503',
|
|
119
|
+
'504',
|
|
120
|
+
// Request/response patterns
|
|
121
|
+
'request',
|
|
122
|
+
'response',
|
|
123
|
+
'payload',
|
|
124
|
+
'json',
|
|
125
|
+
'parse error',
|
|
126
|
+
// Service specific
|
|
127
|
+
'service unavailable',
|
|
128
|
+
'bad gateway',
|
|
129
|
+
'gateway timeout',
|
|
130
|
+
];
|
|
131
|
+
return (apiIndicators.some((indicator) => message.includes(indicator) ||
|
|
132
|
+
message.includes(indicator.replace(' ', '_')) ||
|
|
133
|
+
message.includes(indicator.replace('_', ' '))) ||
|
|
134
|
+
stack.includes('gemini') ||
|
|
135
|
+
stack.includes('api') ||
|
|
136
|
+
stack.includes('http') ||
|
|
137
|
+
name.includes('api') ||
|
|
138
|
+
name.includes('http'));
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Check if error is network-related with enhanced pattern matching
|
|
142
|
+
*/
|
|
143
|
+
isNetworkError(message, stack, name) {
|
|
144
|
+
const networkIndicators = [
|
|
145
|
+
// Connection errors
|
|
146
|
+
'network',
|
|
147
|
+
'connection',
|
|
148
|
+
'connect',
|
|
149
|
+
'econnrefused',
|
|
150
|
+
'econnreset',
|
|
151
|
+
'econnaborted',
|
|
152
|
+
'connection refused',
|
|
153
|
+
'connection reset',
|
|
154
|
+
'connection aborted',
|
|
155
|
+
// Timeout errors
|
|
156
|
+
'timeout',
|
|
157
|
+
'etimedout',
|
|
158
|
+
'timed out',
|
|
159
|
+
'request timeout',
|
|
160
|
+
'read timeout',
|
|
161
|
+
'connect timeout',
|
|
162
|
+
// DNS errors
|
|
163
|
+
'dns',
|
|
164
|
+
'enotfound',
|
|
165
|
+
'getaddrinfo',
|
|
166
|
+
'hostname',
|
|
167
|
+
'resolution',
|
|
168
|
+
'dns_probe',
|
|
169
|
+
// Network infrastructure
|
|
170
|
+
'proxy',
|
|
171
|
+
'tunnel',
|
|
172
|
+
'firewall',
|
|
173
|
+
'blocked',
|
|
174
|
+
'unreachable',
|
|
175
|
+
'host unreachable',
|
|
176
|
+
'network unreachable',
|
|
177
|
+
// SSL/TLS errors
|
|
178
|
+
'ssl',
|
|
179
|
+
'tls',
|
|
180
|
+
'certificate',
|
|
181
|
+
'cert',
|
|
182
|
+
'handshake',
|
|
183
|
+
'protocol',
|
|
184
|
+
// Socket errors
|
|
185
|
+
'socket',
|
|
186
|
+
'esocktimedout',
|
|
187
|
+
'eaddrnotavail',
|
|
188
|
+
'enetdown',
|
|
189
|
+
'enetunreach',
|
|
190
|
+
'ehostdown',
|
|
191
|
+
'ehostunreach',
|
|
192
|
+
// HTTP client errors (not server errors which are API)
|
|
193
|
+
'client_error',
|
|
194
|
+
'fetch_error',
|
|
195
|
+
'request_error',
|
|
196
|
+
];
|
|
197
|
+
return (networkIndicators.some((indicator) => message.includes(indicator) ||
|
|
198
|
+
message.includes(indicator.replace(' ', '_')) ||
|
|
199
|
+
message.includes(indicator.replace('_', ' '))) ||
|
|
200
|
+
networkIndicators.some((indicator) => stack.includes(indicator)) ||
|
|
201
|
+
name.includes('network') ||
|
|
202
|
+
name.includes('timeout') ||
|
|
203
|
+
name.includes('dns') ||
|
|
204
|
+
name.includes('socket'));
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Check if error is file operation related
|
|
208
|
+
*/
|
|
209
|
+
isFileError(message, stack, name) {
|
|
210
|
+
const fileIndicators = [
|
|
211
|
+
'file',
|
|
212
|
+
'directory',
|
|
213
|
+
'permission',
|
|
214
|
+
'eacces',
|
|
215
|
+
'enoent',
|
|
216
|
+
'enospc',
|
|
217
|
+
'emfile',
|
|
218
|
+
'access denied',
|
|
219
|
+
'no such file',
|
|
220
|
+
'disk full',
|
|
221
|
+
'readonly',
|
|
222
|
+
'read-only',
|
|
223
|
+
];
|
|
224
|
+
return (fileIndicators.some((indicator) => message.includes(indicator)) ||
|
|
225
|
+
fileIndicators.some((indicator) => stack.includes(indicator)) ||
|
|
226
|
+
name.includes('file') ||
|
|
227
|
+
name.includes('fs'));
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Check if error is concurrency-related
|
|
231
|
+
*/
|
|
232
|
+
isConcurrencyError(message, stack, name) {
|
|
233
|
+
const concurrencyIndicators = [
|
|
234
|
+
'concurrent',
|
|
235
|
+
'busy',
|
|
236
|
+
'queue',
|
|
237
|
+
'limit',
|
|
238
|
+
'maximum',
|
|
239
|
+
'overload',
|
|
240
|
+
'throttle',
|
|
241
|
+
];
|
|
242
|
+
return (concurrencyIndicators.some((indicator) => message.includes(indicator)) ||
|
|
243
|
+
concurrencyIndicators.some((indicator) => stack.includes(indicator)) ||
|
|
244
|
+
name.includes('concurrency'));
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Check if error is security-related
|
|
248
|
+
*/
|
|
249
|
+
isSecurityError(message, stack, name) {
|
|
250
|
+
const securityIndicators = [
|
|
251
|
+
'security',
|
|
252
|
+
'path',
|
|
253
|
+
'traversal',
|
|
254
|
+
'forbidden',
|
|
255
|
+
'unauthorized',
|
|
256
|
+
'malicious',
|
|
257
|
+
'suspicious',
|
|
258
|
+
'..',
|
|
259
|
+
'filetype',
|
|
260
|
+
'extension',
|
|
261
|
+
];
|
|
262
|
+
return (securityIndicators.some((indicator) => message.includes(indicator)) ||
|
|
263
|
+
securityIndicators.some((indicator) => stack.includes(indicator)) ||
|
|
264
|
+
name.includes('security'));
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Check if error is validation-related
|
|
268
|
+
*/
|
|
269
|
+
isValidationError(message, stack, name) {
|
|
270
|
+
const validationIndicators = [
|
|
271
|
+
'validation',
|
|
272
|
+
'invalid',
|
|
273
|
+
'parameter',
|
|
274
|
+
'argument',
|
|
275
|
+
'format',
|
|
276
|
+
'parse',
|
|
277
|
+
'schema',
|
|
278
|
+
'type',
|
|
279
|
+
];
|
|
280
|
+
return (validationIndicators.some((indicator) => message.includes(indicator)) ||
|
|
281
|
+
validationIndicators.some((indicator) => stack.includes(indicator)) ||
|
|
282
|
+
name.includes('validation') ||
|
|
283
|
+
name.includes('type'));
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Convert BaseError to MCP tool response format
|
|
287
|
+
* @param error BaseError to convert
|
|
288
|
+
* @returns MCP tool response
|
|
289
|
+
*/
|
|
290
|
+
convertToMcpResponse(error) {
|
|
291
|
+
const structuredError = error.toStructuredError();
|
|
292
|
+
// Filter sensitive information from context
|
|
293
|
+
const safeContext = this.sanitizeContext(structuredError.context);
|
|
294
|
+
const safeStructuredError = {
|
|
295
|
+
...structuredError,
|
|
296
|
+
context: safeContext,
|
|
297
|
+
};
|
|
298
|
+
return {
|
|
299
|
+
content: [
|
|
300
|
+
{
|
|
301
|
+
type: 'text',
|
|
302
|
+
text: JSON.stringify({
|
|
303
|
+
error: safeStructuredError,
|
|
304
|
+
}),
|
|
305
|
+
},
|
|
306
|
+
],
|
|
307
|
+
isError: true,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Sanitize error context to prevent sensitive information leakage
|
|
312
|
+
* @param context Original context object
|
|
313
|
+
* @returns Sanitized context object
|
|
314
|
+
*/
|
|
315
|
+
sanitizeContext(context) {
|
|
316
|
+
if (!context)
|
|
317
|
+
return undefined;
|
|
318
|
+
const sanitized = {};
|
|
319
|
+
const sensitiveKeys = [
|
|
320
|
+
'password',
|
|
321
|
+
'token',
|
|
322
|
+
'key',
|
|
323
|
+
'secret',
|
|
324
|
+
'credential',
|
|
325
|
+
'auth',
|
|
326
|
+
'api_key',
|
|
327
|
+
'authorization',
|
|
328
|
+
];
|
|
329
|
+
for (const [key, value] of Object.entries(context)) {
|
|
330
|
+
const lowerKey = key.toLowerCase();
|
|
331
|
+
if (sensitiveKeys.some((sensitive) => lowerKey.includes(sensitive))) {
|
|
332
|
+
sanitized[key] = '[REDACTED]';
|
|
333
|
+
}
|
|
334
|
+
else if (typeof value === 'string' && value.length > 1000) {
|
|
335
|
+
// Truncate very long strings to prevent log spam
|
|
336
|
+
sanitized[key] = `${value.substring(0, 1000)}...[TRUNCATED]`;
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
sanitized[key] = value;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return sanitized;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Check if an error is retryable with enhanced retry logic
|
|
346
|
+
* @param error Error to check
|
|
347
|
+
* @returns True if error should be retried
|
|
348
|
+
*/
|
|
349
|
+
isRetryableError(error) {
|
|
350
|
+
const message = error.message.toLowerCase();
|
|
351
|
+
// Network errors are generally retryable except for permanent failures
|
|
352
|
+
if (error instanceof NetworkError) {
|
|
353
|
+
// Non-retryable network errors (permanent failures)
|
|
354
|
+
const permanentFailures = [
|
|
355
|
+
'dns',
|
|
356
|
+
'enotfound',
|
|
357
|
+
'hostname',
|
|
358
|
+
'certificate',
|
|
359
|
+
'cert',
|
|
360
|
+
'ssl',
|
|
361
|
+
'tls',
|
|
362
|
+
'protocol',
|
|
363
|
+
'handshake',
|
|
364
|
+
'blocked',
|
|
365
|
+
'firewall',
|
|
366
|
+
'access denied',
|
|
367
|
+
'forbidden',
|
|
368
|
+
];
|
|
369
|
+
const isPermanent = permanentFailures.some((pattern) => message.includes(pattern));
|
|
370
|
+
return !isPermanent;
|
|
371
|
+
}
|
|
372
|
+
// API errors - retryable for temporary issues
|
|
373
|
+
if (error instanceof GeminiAPIError) {
|
|
374
|
+
// Retryable API errors (temporary issues)
|
|
375
|
+
const retryablePatterns = [
|
|
376
|
+
'timeout',
|
|
377
|
+
'timed out',
|
|
378
|
+
'rate limit',
|
|
379
|
+
'rate-limit',
|
|
380
|
+
'quota',
|
|
381
|
+
'busy',
|
|
382
|
+
'overload',
|
|
383
|
+
'throttle',
|
|
384
|
+
'429', // Too Many Requests
|
|
385
|
+
'500', // Internal Server Error
|
|
386
|
+
'502', // Bad Gateway
|
|
387
|
+
'503', // Service Unavailable
|
|
388
|
+
'504', // Gateway Timeout
|
|
389
|
+
'service unavailable',
|
|
390
|
+
'bad gateway',
|
|
391
|
+
'gateway timeout',
|
|
392
|
+
'temporarily unavailable',
|
|
393
|
+
'try again',
|
|
394
|
+
'retry',
|
|
395
|
+
];
|
|
396
|
+
return retryablePatterns.some((pattern) => message.includes(pattern));
|
|
397
|
+
}
|
|
398
|
+
// Concurrency errors are always retryable (just wait and retry)
|
|
399
|
+
if (error instanceof ConcurrencyError) {
|
|
400
|
+
return true;
|
|
401
|
+
}
|
|
402
|
+
// File operation errors - some are retryable
|
|
403
|
+
if (error instanceof FileOperationError) {
|
|
404
|
+
// Retryable file errors (temporary issues)
|
|
405
|
+
const retryableFilePatterns = [
|
|
406
|
+
'busy',
|
|
407
|
+
'locked',
|
|
408
|
+
'temporary',
|
|
409
|
+
'emfile', // Too many open files - temporary
|
|
410
|
+
'enfile', // File table overflow - temporary
|
|
411
|
+
];
|
|
412
|
+
return retryableFilePatterns.some((pattern) => message.includes(pattern));
|
|
413
|
+
}
|
|
414
|
+
// Security and validation errors are never retryable
|
|
415
|
+
if (error instanceof SecurityError || error instanceof ValidationError) {
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
// Internal errors might be retryable if they seem temporary
|
|
419
|
+
if (error instanceof InternalError) {
|
|
420
|
+
const temporaryPatterns = [
|
|
421
|
+
'temporary',
|
|
422
|
+
'transient',
|
|
423
|
+
'momentary',
|
|
424
|
+
'busy',
|
|
425
|
+
'overload',
|
|
426
|
+
'memory',
|
|
427
|
+
'resource',
|
|
428
|
+
];
|
|
429
|
+
return temporaryPatterns.some((pattern) => message.includes(pattern));
|
|
430
|
+
}
|
|
431
|
+
// Default to not retryable for unknown error types
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Get retry delay in milliseconds with adaptive exponential backoff
|
|
436
|
+
* @param attempt Current attempt number (1-based)
|
|
437
|
+
* @param error Optional error to adapt delay based on error type
|
|
438
|
+
* @param baseDelay Base delay in milliseconds (default: 1000)
|
|
439
|
+
* @returns Delay in milliseconds
|
|
440
|
+
*/
|
|
441
|
+
getRetryDelay(attempt, error, baseDelay = 1000) {
|
|
442
|
+
let adjustedBaseDelay = baseDelay;
|
|
443
|
+
// Adapt base delay based on error type
|
|
444
|
+
if (error) {
|
|
445
|
+
if (error instanceof NetworkError) {
|
|
446
|
+
// Network errors might need longer delays
|
|
447
|
+
const message = error.message.toLowerCase();
|
|
448
|
+
if (message.includes('timeout') || message.includes('timed out')) {
|
|
449
|
+
adjustedBaseDelay = baseDelay * 2; // Double delay for timeouts
|
|
450
|
+
}
|
|
451
|
+
else if (message.includes('connection')) {
|
|
452
|
+
adjustedBaseDelay = baseDelay * 1.5; // Increase delay for connection issues
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
else if (error instanceof GeminiAPIError) {
|
|
456
|
+
// API errors might have specific retry requirements
|
|
457
|
+
const message = error.message.toLowerCase();
|
|
458
|
+
if (message.includes('rate limit') || message.includes('quota')) {
|
|
459
|
+
adjustedBaseDelay = baseDelay * 3; // Much longer delay for rate limits
|
|
460
|
+
}
|
|
461
|
+
else if (message.includes('503') || message.includes('service unavailable')) {
|
|
462
|
+
adjustedBaseDelay = baseDelay * 2; // Longer delay for service unavailable
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
else if (error instanceof ConcurrencyError) {
|
|
466
|
+
// Concurrency errors need shorter delays since it's just queue management
|
|
467
|
+
adjustedBaseDelay = Math.max(500, baseDelay * 0.5);
|
|
468
|
+
}
|
|
469
|
+
else if (error instanceof FileOperationError) {
|
|
470
|
+
// File operations might need variable delays
|
|
471
|
+
const message = error.message.toLowerCase();
|
|
472
|
+
if (message.includes('locked') || message.includes('busy')) {
|
|
473
|
+
adjustedBaseDelay = baseDelay * 1.5;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
// Calculate exponential backoff with cap
|
|
478
|
+
const exponentialDelay = adjustedBaseDelay * 2 ** (attempt - 1);
|
|
479
|
+
const cappedDelay = Math.min(exponentialDelay, 30000); // Cap at 30 seconds
|
|
480
|
+
// Add jitter to prevent thundering herd
|
|
481
|
+
const jitterPercent = 0.1 + Math.random() * 0.2; // 10-30% jitter
|
|
482
|
+
const jitter = cappedDelay * jitterPercent;
|
|
483
|
+
const finalDelay = cappedDelay + (Math.random() > 0.5 ? jitter : -jitter);
|
|
484
|
+
return Math.max(100, Math.floor(finalDelay)); // Minimum 100ms delay
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Get human-readable retry advice based on error type and attempt
|
|
488
|
+
* @param error Error that occurred
|
|
489
|
+
* @param attempt Current attempt number
|
|
490
|
+
* @param maxAttempts Maximum retry attempts
|
|
491
|
+
* @returns Human-readable retry advice
|
|
492
|
+
*/
|
|
493
|
+
getRetryAdvice(error, attempt, maxAttempts) {
|
|
494
|
+
const remaining = maxAttempts - attempt;
|
|
495
|
+
if (remaining <= 0) {
|
|
496
|
+
return `All ${maxAttempts} retry attempts exhausted. ${error.suggestion}`;
|
|
497
|
+
}
|
|
498
|
+
let timeAdvice = 'shortly';
|
|
499
|
+
if (error instanceof GeminiAPIError && error.message.toLowerCase().includes('rate limit')) {
|
|
500
|
+
timeAdvice = 'after waiting for rate limit reset';
|
|
501
|
+
}
|
|
502
|
+
else if (error instanceof NetworkError) {
|
|
503
|
+
timeAdvice = 'when network connectivity improves';
|
|
504
|
+
}
|
|
505
|
+
else if (error instanceof ConcurrencyError) {
|
|
506
|
+
timeAdvice = 'when server capacity is available';
|
|
507
|
+
}
|
|
508
|
+
return `Attempt ${attempt}/${maxAttempts} failed. Will retry ${timeAdvice} (${remaining} attempts remaining).`;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
//# sourceMappingURL=errorHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errorHandler.js","sourceRoot":"","sources":["../../src/business/errorHandler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Manager for handling image file operations
|
|
3
|
+
* Provides functionality for saving images and managing directories
|
|
4
|
+
*/
|
|
5
|
+
import type { Result } from '../types/result';
|
|
6
|
+
import { FileOperationError } from '../utils/errors';
|
|
7
|
+
/**
|
|
8
|
+
* Interface for file management operations
|
|
9
|
+
*/
|
|
10
|
+
export interface FileManager {
|
|
11
|
+
saveImage(imageData: Buffer, outputPath: string, format?: string): Promise<Result<string, FileOperationError>>;
|
|
12
|
+
ensureDirectoryExists(dirPath: string): Result<void, FileOperationError>;
|
|
13
|
+
generateFileName(): string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Creates a file manager for image file operations
|
|
17
|
+
* @returns FileManager implementation
|
|
18
|
+
*/
|
|
19
|
+
export declare function createFileManager(): FileManager;
|
|
20
|
+
//# sourceMappingURL=fileManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileManager.d.ts","sourceRoot":"","sources":["../../src/business/fileManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAE7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAcpD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,SAAS,CACP,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAA;IAC9C,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAA;IACxE,gBAAgB,IAAI,MAAM,CAAA;CAC3B;AA+BD;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,WAAW,CAsC/C"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* File Manager for handling image file operations
|
|
4
|
+
* Provides functionality for saving images and managing directories
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.createFileManager = createFileManager;
|
|
41
|
+
const node_fs_1 = require("node:fs");
|
|
42
|
+
const path = __importStar(require("node:path"));
|
|
43
|
+
const result_1 = require("../types/result");
|
|
44
|
+
const errors_1 = require("../utils/errors");
|
|
45
|
+
// Constants for file naming and error messages
|
|
46
|
+
const FILE_NAME_PREFIX = 'image';
|
|
47
|
+
const DEFAULT_EXTENSION = '.png';
|
|
48
|
+
const RANDOM_RANGE = 1000;
|
|
49
|
+
const ERROR_MESSAGES = {
|
|
50
|
+
SAVE_FAILED: 'Failed to save image file',
|
|
51
|
+
DIRECTORY_CREATION_FAILED: 'Failed to create directory',
|
|
52
|
+
PERMISSION_SUGGESTION: 'Check output directory permissions and disk space',
|
|
53
|
+
PATH_SUGGESTION: 'Check directory path validity and write permissions',
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Ensures that the specified directory exists, creating it if necessary
|
|
57
|
+
* @param dirPath Path to the directory
|
|
58
|
+
* @returns Result indicating success or failure
|
|
59
|
+
*/
|
|
60
|
+
function ensureDirectoryExists(dirPath) {
|
|
61
|
+
try {
|
|
62
|
+
// Use mkdirSync with recursive option to create all necessary parent directories
|
|
63
|
+
(0, node_fs_1.mkdirSync)(dirPath, { recursive: true });
|
|
64
|
+
return (0, result_1.Ok)(undefined);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
return (0, result_1.Err)(new errors_1.FileOperationError(`${ERROR_MESSAGES.DIRECTORY_CREATION_FAILED}: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Generates a unique filename based on timestamp and random component
|
|
72
|
+
* @returns Generated filename in the format: gemini-image-{timestamp}.png
|
|
73
|
+
*/
|
|
74
|
+
function generateFileName() {
|
|
75
|
+
const timestamp = Date.now();
|
|
76
|
+
const random = Math.floor(Math.random() * RANDOM_RANGE);
|
|
77
|
+
return `${FILE_NAME_PREFIX}-${timestamp}-${random}${DEFAULT_EXTENSION}`;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Creates a file manager for image file operations
|
|
81
|
+
* @returns FileManager implementation
|
|
82
|
+
*/
|
|
83
|
+
function createFileManager() {
|
|
84
|
+
return {
|
|
85
|
+
/**
|
|
86
|
+
* Saves image data to the specified file path
|
|
87
|
+
* @param imageData Buffer containing the image data
|
|
88
|
+
* @param outputPath Absolute path where the image should be saved
|
|
89
|
+
* @param format Image format (used for validation)
|
|
90
|
+
* @returns Result containing the saved file path or an error
|
|
91
|
+
*/
|
|
92
|
+
async saveImage(imageData, outputPath, _format) {
|
|
93
|
+
try {
|
|
94
|
+
// Ensure the directory exists
|
|
95
|
+
const directory = path.dirname(outputPath);
|
|
96
|
+
const dirResult = ensureDirectoryExists(directory);
|
|
97
|
+
if (!dirResult.success) {
|
|
98
|
+
return (0, result_1.Err)(dirResult.error);
|
|
99
|
+
}
|
|
100
|
+
// Save the file
|
|
101
|
+
await node_fs_1.promises.writeFile(outputPath, imageData);
|
|
102
|
+
return (0, result_1.Ok)(outputPath);
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
return (0, result_1.Err)(new errors_1.FileOperationError(`${ERROR_MESSAGES.SAVE_FAILED}: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
ensureDirectoryExists,
|
|
109
|
+
generateFileName,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=fileManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileManager.js","sourceRoot":"","sources":["../../src/business/fileManager.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkEH,8CAsCC;AAtGD,qCAAmD;AACnD,gDAAiC;AAEjC,4CAAyC;AACzC,4CAAoD;AAEpD,+CAA+C;AAC/C,MAAM,gBAAgB,GAAG,OAAgB,CAAA;AACzC,MAAM,iBAAiB,GAAG,MAAe,CAAA;AACzC,MAAM,YAAY,GAAG,IAAa,CAAA;AAElC,MAAM,cAAc,GAAG;IACrB,WAAW,EAAE,2BAA2B;IACxC,yBAAyB,EAAE,4BAA4B;IACvD,qBAAqB,EAAE,mDAAmD;IAC1E,eAAe,EAAE,qDAAqD;CAC9D,CAAA;AAeV;;;;GAIG;AACH,SAAS,qBAAqB,CAAC,OAAe;IAC5C,IAAI,CAAC;QACH,iFAAiF;QACjF,IAAA,mBAAS,EAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACvC,OAAO,IAAA,WAAE,EAAC,SAAS,CAAC,CAAA;IACtB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,IAAA,YAAG,EACR,IAAI,2BAAkB,CACpB,GAAG,cAAc,CAAC,yBAAyB,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CAC3G,CACF,CAAA;IACH,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB;IACvB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,YAAY,CAAC,CAAA;IACvD,OAAO,GAAG,gBAAgB,IAAI,SAAS,IAAI,MAAM,GAAG,iBAAiB,EAAE,CAAA;AACzE,CAAC;AAED;;;GAGG;AACH,SAAgB,iBAAiB;IAC/B,OAAO;QACL;;;;;;WAMG;QACH,KAAK,CAAC,SAAS,CACb,SAAiB,EACjB,UAAkB,EAClB,OAAgB;YAEhB,IAAI,CAAC;gBACH,8BAA8B;gBAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;gBAC1C,MAAM,SAAS,GAAG,qBAAqB,CAAC,SAAS,CAAC,CAAA;gBAClD,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;oBACvB,OAAO,IAAA,YAAG,EAAC,SAAS,CAAC,KAAK,CAAC,CAAA;gBAC7B,CAAC;gBAED,gBAAgB;gBAChB,MAAM,kBAAE,CAAC,SAAS,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;gBAEzC,OAAO,IAAA,WAAE,EAAC,UAAU,CAAC,CAAA;YACvB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,IAAA,YAAG,EACR,IAAI,2BAAkB,CACpB,GAAG,cAAc,CAAC,WAAW,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CAC7F,CACF,CAAA;YACH,CAAC;QACH,CAAC;QAED,qBAAqB;QACrB,gBAAgB;KACjB,CAAA;AACH,CAAC"}
|