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.
Files changed (88) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +163 -0
  3. package/dist/api/geminiClient.d.ts +55 -0
  4. package/dist/api/geminiClient.d.ts.map +1 -0
  5. package/dist/api/geminiClient.js +194 -0
  6. package/dist/api/geminiClient.js.map +1 -0
  7. package/dist/api/urlContextClient.d.ts +149 -0
  8. package/dist/api/urlContextClient.d.ts.map +1 -0
  9. package/dist/api/urlContextClient.js +320 -0
  10. package/dist/api/urlContextClient.js.map +1 -0
  11. package/dist/business/errorHandler.d.ts +97 -0
  12. package/dist/business/errorHandler.d.ts.map +1 -0
  13. package/dist/business/errorHandler.js +511 -0
  14. package/dist/business/errorHandler.js.map +1 -0
  15. package/dist/business/fileManager.d.ts +20 -0
  16. package/dist/business/fileManager.d.ts.map +1 -0
  17. package/dist/business/fileManager.js +112 -0
  18. package/dist/business/fileManager.js.map +1 -0
  19. package/dist/business/imageGenerator.d.ts +64 -0
  20. package/dist/business/imageGenerator.d.ts.map +1 -0
  21. package/dist/business/imageGenerator.js +147 -0
  22. package/dist/business/imageGenerator.js.map +1 -0
  23. package/dist/business/imageGeneratorRobust.d.ts +60 -0
  24. package/dist/business/imageGeneratorRobust.d.ts.map +1 -0
  25. package/dist/business/imageGeneratorRobust.js +242 -0
  26. package/dist/business/imageGeneratorRobust.js.map +1 -0
  27. package/dist/business/inputValidator.d.ts +29 -0
  28. package/dist/business/inputValidator.d.ts.map +1 -0
  29. package/dist/business/inputValidator.js +132 -0
  30. package/dist/business/inputValidator.js.map +1 -0
  31. package/dist/business/performanceManager.d.ts +88 -0
  32. package/dist/business/performanceManager.d.ts.map +1 -0
  33. package/dist/business/performanceManager.js +142 -0
  34. package/dist/business/performanceManager.js.map +1 -0
  35. package/dist/business/responseBuilder.d.ts +20 -0
  36. package/dist/business/responseBuilder.d.ts.map +1 -0
  37. package/dist/business/responseBuilder.js +162 -0
  38. package/dist/business/responseBuilder.js.map +1 -0
  39. package/dist/business/secureFileManager.d.ts +56 -0
  40. package/dist/business/secureFileManager.d.ts.map +1 -0
  41. package/dist/business/secureFileManager.js +185 -0
  42. package/dist/business/secureFileManager.js.map +1 -0
  43. package/dist/business/urlExtractor.d.ts +60 -0
  44. package/dist/business/urlExtractor.d.ts.map +1 -0
  45. package/dist/business/urlExtractor.js +144 -0
  46. package/dist/business/urlExtractor.js.map +1 -0
  47. package/dist/index.d.ts +5 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +45 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/server/concurrencyManager.d.ts +56 -0
  52. package/dist/server/concurrencyManager.d.ts.map +1 -0
  53. package/dist/server/concurrencyManager.js +133 -0
  54. package/dist/server/concurrencyManager.js.map +1 -0
  55. package/dist/server/errorHandler.d.ts +29 -0
  56. package/dist/server/errorHandler.d.ts.map +1 -0
  57. package/dist/server/errorHandler.js +93 -0
  58. package/dist/server/errorHandler.js.map +1 -0
  59. package/dist/server/mcpServer.d.ts +111 -0
  60. package/dist/server/mcpServer.d.ts.map +1 -0
  61. package/dist/server/mcpServer.js +353 -0
  62. package/dist/server/mcpServer.js.map +1 -0
  63. package/dist/types/mcp.d.ts +72 -0
  64. package/dist/types/mcp.d.ts.map +1 -0
  65. package/dist/types/mcp.js +7 -0
  66. package/dist/types/mcp.js.map +1 -0
  67. package/dist/types/result.d.ts +27 -0
  68. package/dist/types/result.d.ts.map +1 -0
  69. package/dist/types/result.js +31 -0
  70. package/dist/types/result.js.map +1 -0
  71. package/dist/utils/config.d.ts +26 -0
  72. package/dist/utils/config.d.ts.map +1 -0
  73. package/dist/utils/config.js +53 -0
  74. package/dist/utils/config.js.map +1 -0
  75. package/dist/utils/errors.d.ts +84 -0
  76. package/dist/utils/errors.d.ts.map +1 -0
  77. package/dist/utils/errors.js +218 -0
  78. package/dist/utils/errors.js.map +1 -0
  79. package/dist/utils/logger.d.ts +80 -0
  80. package/dist/utils/logger.d.ts.map +1 -0
  81. package/dist/utils/logger.js +223 -0
  82. package/dist/utils/logger.js.map +1 -0
  83. package/dist/utils/security.d.ts +50 -0
  84. package/dist/utils/security.d.ts.map +1 -0
  85. package/dist/utils/security.js +153 -0
  86. package/dist/utils/security.js.map +1 -0
  87. package/package.json +73 -0
  88. package/vitest.config.mjs +47 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Shinsuke Kagawa
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,163 @@
1
+ # MCP Image Generator
2
+
3
+ A powerful MCP (Model Context Protocol) server that enables AI assistants to generate and edit images using Google's Gemini 2.5 Flash Image API. Seamlessly integrate advanced image generation capabilities into Claude Code, Cursor, and other MCP-compatible AI tools.
4
+
5
+ ## ✨ Features
6
+
7
+ - **AI-Powered Image Generation**: Create images from text prompts using Gemini 2.5 Flash Image Preview
8
+ - **Image Editing**: Transform existing images with natural language instructions
9
+ - **Advanced Options**:
10
+ - Multi-image blending for composite scenes
11
+ - Character consistency across generations
12
+ - World knowledge integration for accurate context
13
+ - **Multiple Output Formats**: PNG, JPEG, WebP support
14
+ - **File Output**: Images are saved as files for easy access and integration
15
+
16
+ ## 🔧 Prerequisites
17
+
18
+ - **Node.js** 20 or higher
19
+ - **Gemini API Key** - Get yours at [Google AI Studio](https://aistudio.google.com/apikey)
20
+ - **Claude Code** or **Cursor** (or any MCP-compatible AI tool)
21
+ - Basic terminal/command line knowledge
22
+
23
+ ## 🚀 Quick Start
24
+
25
+ ### 1. Get Your Gemini API Key
26
+
27
+ Get your API key from [Google AI Studio](https://aistudio.google.com/apikey)
28
+
29
+ ### 2. MCP Configuration
30
+
31
+ #### For Claude Code
32
+
33
+ ```bash
34
+ claude mcp add mcp-image --env GEMINI_API_KEY=your-api-key --env IMAGE_OUTPUT_DIR=/absolute/path/to/images -- npx -y mcp-image
35
+ ```
36
+
37
+ #### For Cursor
38
+
39
+ Add to your Cursor settings (`~/.cursor/mcp.json`):
40
+
41
+ ```json
42
+ {
43
+ "mcp": {
44
+ "servers": {
45
+ "mcp-image": {
46
+ "command": "npx",
47
+ "args": ["-y", "mcp-image"],
48
+ "env": {
49
+ "GEMINI_API_KEY": "your_gemini_api_key_here",
50
+ "IMAGE_OUTPUT_DIR": "/absolute/path/to/images"
51
+ }
52
+ }
53
+ }
54
+ }
55
+ }
56
+ ```
57
+
58
+ ⚠️ **Security Note**: Never commit your API key to version control. Keep it secure and use environment-specific configuration.
59
+
60
+ 📁 **Path Requirements**:
61
+ - `IMAGE_OUTPUT_DIR` must be an absolute path (e.g., `/Users/username/images`, not `./images`)
62
+ - Defaults to `./output` in the current working directory if not specified
63
+ - Directory will be created automatically if it doesn't exist
64
+
65
+ ## 📖 Usage Examples
66
+
67
+ Once configured, your AI assistant can generate images using natural language:
68
+
69
+ ### Basic Image Generation
70
+
71
+ ```
72
+ "Generate a serene mountain landscape at sunset with a lake reflection"
73
+ ```
74
+
75
+ ### Image Editing
76
+
77
+ ```
78
+ "Edit this image to make the person face right"
79
+ (with inputImagePath: "/path/to/image.jpg")
80
+ ```
81
+
82
+
83
+ ### Advanced Features
84
+
85
+ ```
86
+ "Generate a portrait of a medieval knight, maintaining character consistency for future variations"
87
+ (with maintainCharacterConsistency: true)
88
+ ```
89
+
90
+ ## 🔧 API Reference
91
+
92
+ ### `generate_image` Tool
93
+
94
+ The MCP server exposes a single tool for all image operations:
95
+
96
+ #### Parameters
97
+
98
+ | Parameter | Type | Required | Description |
99
+ |-----------|------|----------|-------------|
100
+ | `prompt` | string | ✅ | Text description or editing instruction |
101
+ | `inputImagePath` | string | ❌ | Absolute path to input image for editing |
102
+ | `fileName` | string | ❌ | Custom filename for output (auto-generated if not specified) |
103
+ | `blendImages` | boolean | ❌ | Enable multi-image blending |
104
+ | `maintainCharacterConsistency` | boolean | ❌ | Maintain character appearance across generations |
105
+ | `useWorldKnowledge` | boolean | ❌ | Use real-world knowledge for context |
106
+
107
+ #### Response
108
+
109
+ ```json
110
+ {
111
+ "type": "resource",
112
+ "resource": {
113
+ "uri": "file:///path/to/generated/image.png",
114
+ "name": "image-filename.png",
115
+ "mimeType": "image/png"
116
+ },
117
+ "metadata": {
118
+ "model": "gemini-2.5-flash-image-preview",
119
+ "processingTime": 5000,
120
+ "timestamp": "2024-01-01T12:00:00.000Z"
121
+ }
122
+ }
123
+ ```
124
+
125
+ ## 🛠️ Troubleshooting
126
+
127
+ ### Common Issues
128
+
129
+ **"API key not found"**
130
+ - Ensure `GEMINI_API_KEY` is set in your environment
131
+ - Verify the API key is valid and has image generation permissions
132
+
133
+ **"Input image file not found"**
134
+ - Use absolute file paths, not relative paths
135
+ - Ensure the file exists and is accessible
136
+ - Supported formats: PNG, JPEG, WebP (max 10MB)
137
+
138
+ **"No image data found in Gemini API response"**
139
+ - Try rephrasing your prompt with more specific details
140
+ - Ensure your prompt is appropriate for image generation
141
+ - Check if your API key has sufficient quota
142
+
143
+ ### Performance Tips
144
+
145
+ - Image generation: 30-60 seconds typical
146
+ - Image editing: 15-45 seconds typical
147
+ - Use specific, descriptive prompts for better results
148
+ - Consider enabling `useWorldKnowledge` for historical or factual subjects
149
+
150
+
151
+ ## 💰 Usage Notes
152
+
153
+ - This MCP server uses the paid Gemini API for image generation
154
+ - Check current pricing and rate limits at [Google AI Studio](https://aistudio.google.com/)
155
+ - Monitor your API usage to avoid unexpected charges
156
+
157
+ ## 📄 License
158
+
159
+ MIT License - see [LICENSE](LICENSE) for details.
160
+
161
+ ---
162
+
163
+ **Need help?** [Open an issue](https://github.com/shinpr/mcp-image/issues) or check the [troubleshooting section](#-troubleshooting) above.
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Gemini API client for image generation
3
+ * Integrates with Google's Gemini AI API using the official SDK
4
+ * Supports automatic URL Context processing and feature parameters
5
+ */
6
+ import type { Result } from '../types/result';
7
+ import type { Config } from '../utils/config';
8
+ import { GeminiAPIError, NetworkError } from '../utils/errors';
9
+ /**
10
+ * Metadata for generated images
11
+ */
12
+ export interface GeminiGenerationMetadata {
13
+ model: string;
14
+ prompt: string;
15
+ mimeType: string;
16
+ timestamp: Date;
17
+ inputImageProvided: boolean;
18
+ contextMethod: string;
19
+ /** Features usage metadata */
20
+ features?: {
21
+ blendImages: boolean;
22
+ maintainCharacterConsistency: boolean;
23
+ useWorldKnowledge: boolean;
24
+ };
25
+ }
26
+ /**
27
+ * Parameters for Gemini API image generation (with processed data)
28
+ */
29
+ export interface GeminiApiParams {
30
+ prompt: string;
31
+ inputImage?: Buffer;
32
+ blendImages?: boolean;
33
+ maintainCharacterConsistency?: boolean;
34
+ useWorldKnowledge?: boolean;
35
+ }
36
+ /**
37
+ * Result of image generation
38
+ */
39
+ export interface GeneratedImageResult {
40
+ imageData: Buffer;
41
+ metadata: GeminiGenerationMetadata;
42
+ }
43
+ /**
44
+ * Gemini API client interface
45
+ */
46
+ export interface GeminiClient {
47
+ generateImage(params: GeminiApiParams): Promise<Result<GeneratedImageResult, GeminiAPIError | NetworkError>>;
48
+ }
49
+ /**
50
+ * Creates a new Gemini API client
51
+ * @param config Configuration containing API key and other settings
52
+ * @returns Result containing the client or an error
53
+ */
54
+ export declare function createGeminiClient(config: Config): Result<GeminiClient, GeminiAPIError>;
55
+ //# sourceMappingURL=geminiClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geminiClient.d.ts","sourceRoot":"","sources":["../../src/api/geminiClient.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAE7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAiD9D;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,IAAI,CAAA;IACf,kBAAkB,EAAE,OAAO,CAAA;IAC3B,aAAa,EAAE,MAAM,CAAA;IACrB,8BAA8B;IAC9B,QAAQ,CAAC,EAAE;QACT,WAAW,EAAE,OAAO,CAAA;QACpB,4BAA4B,EAAE,OAAO,CAAA;QACrC,iBAAiB,EAAE,OAAO,CAAA;KAC3B,CAAA;CACF;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,4BAA4B,CAAC,EAAE,OAAO,CAAA;IACtC,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,wBAAwB,CAAA;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,aAAa,CACX,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,MAAM,CAAC,oBAAoB,EAAE,cAAc,GAAG,YAAY,CAAC,CAAC,CAAA;CACxE;AAwPD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,YAAY,EAAE,cAAc,CAAC,CAevF"}
@@ -0,0 +1,194 @@
1
+ "use strict";
2
+ /**
3
+ * Gemini API client for image generation
4
+ * Integrates with Google's Gemini AI API using the official SDK
5
+ * Supports automatic URL Context processing and feature parameters
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.createGeminiClient = createGeminiClient;
9
+ const genai_1 = require("@google/genai");
10
+ const result_1 = require("../types/result");
11
+ const errors_1 = require("../utils/errors");
12
+ /**
13
+ * URL pattern for automatic URL detection
14
+ */
15
+ const URL_PATTERN = /https?:\/\/(?:[-\w.])+(?:\.[a-zA-Z]{2,})+(?:\/[-\w._~:\/?#[\]@!$&'()*+,;=]*)?/g;
16
+ /**
17
+ * Implementation of Gemini API client
18
+ */
19
+ class GeminiClientImpl {
20
+ constructor(genai) {
21
+ this.genai = genai;
22
+ this.modelName = 'gemini-2.5-flash-image-preview';
23
+ }
24
+ async generateImage(params) {
25
+ try {
26
+ // Enhance prompt with structured parameters for better accuracy
27
+ let enhancedPrompt = params.prompt;
28
+ // Convert MCP parameters to structured prompt instructions
29
+ if (params.maintainCharacterConsistency) {
30
+ enhancedPrompt +=
31
+ ' [INSTRUCTION: Maintain exact character appearance, including facial features, hairstyle, clothing, and all physical characteristics consistent throughout the image]';
32
+ }
33
+ if (params.blendImages) {
34
+ enhancedPrompt +=
35
+ ' [INSTRUCTION: Seamlessly blend multiple visual elements into a natural, cohesive composition with smooth transitions]';
36
+ }
37
+ if (params.useWorldKnowledge) {
38
+ enhancedPrompt +=
39
+ ' [INSTRUCTION: Apply accurate real-world knowledge including historical facts, geographical accuracy, cultural contexts, and realistic depictions]';
40
+ }
41
+ // Prepare the request content with enhanced prompt
42
+ const requestContent = [enhancedPrompt];
43
+ // Add input image if provided
44
+ if (params.inputImage) {
45
+ requestContent.push({
46
+ inlineData: {
47
+ data: params.inputImage.toString('base64'),
48
+ mimeType: 'image/jpeg', // Assume JPEG for input images
49
+ },
50
+ });
51
+ }
52
+ // Prepare API configuration
53
+ const config = {};
54
+ // URL detection is maintained for potential future use
55
+ // Note: urlContext tool has been removed as it's not supported by the model
56
+ this.detectUrls(params.prompt);
57
+ // Note: Feature parameters are now handled via prompt enhancement
58
+ // The Gemini API does not directly support these as config parameters
59
+ // Generate content using Gemini API with official URL Context support
60
+ const response = await this.genai.models.generateContent({
61
+ model: this.modelName,
62
+ contents: requestContent,
63
+ config,
64
+ });
65
+ // Extract image data from response
66
+ if (!response || typeof response !== 'object') {
67
+ return (0, result_1.Err)(new errors_1.GeminiAPIError('Invalid response from Gemini API', 'The API returned an unexpected response format'));
68
+ }
69
+ // Handle different response structures
70
+ const candidates = response.response?.candidates ||
71
+ response.candidates;
72
+ if (!candidates || candidates.length === 0) {
73
+ return (0, result_1.Err)(new errors_1.GeminiAPIError('No image generated by Gemini API', 'Try rephrasing your prompt or check if the model supports your request type'));
74
+ }
75
+ const candidate = candidates[0];
76
+ if (!candidate) {
77
+ return (0, result_1.Err)(new errors_1.GeminiAPIError('No candidate found in Gemini API response', 'The API response was malformed. Try again or contact support if the issue persists'));
78
+ }
79
+ const parts = candidate.content?.parts;
80
+ if (!parts || parts.length === 0) {
81
+ return (0, result_1.Err)(new errors_1.GeminiAPIError('No image data in response from Gemini API', 'The API response was malformed. Try again or contact support if the issue persists'));
82
+ }
83
+ // Find the image part with proper type guards
84
+ const imagePart = parts.find((part) => {
85
+ const p = part;
86
+ return p.inlineData?.data;
87
+ });
88
+ if (!imagePart?.inlineData) {
89
+ return (0, result_1.Err)(new errors_1.GeminiAPIError('No image data found in Gemini API response', 'The model may not have generated an image. Try a different prompt'));
90
+ }
91
+ // Convert base64 image data to Buffer
92
+ const imageBuffer = Buffer.from(imagePart.inlineData.data, 'base64');
93
+ const mimeType = imagePart.inlineData.mimeType || 'image/png';
94
+ // Create metadata with features information
95
+ const metadata = {
96
+ model: this.modelName,
97
+ prompt: params.prompt, // Original prompt, not enhanced
98
+ mimeType,
99
+ timestamp: new Date(),
100
+ inputImageProvided: !!params.inputImage,
101
+ contextMethod: 'prompt_only',
102
+ };
103
+ // Add features usage information if any features are specified (including false)
104
+ if (params.blendImages !== undefined ||
105
+ params.maintainCharacterConsistency !== undefined ||
106
+ params.useWorldKnowledge !== undefined) {
107
+ metadata.features = {
108
+ blendImages: params.blendImages || false,
109
+ maintainCharacterConsistency: params.maintainCharacterConsistency || false,
110
+ useWorldKnowledge: params.useWorldKnowledge || false,
111
+ };
112
+ }
113
+ return (0, result_1.Ok)({
114
+ imageData: imageBuffer,
115
+ metadata,
116
+ });
117
+ }
118
+ catch (error) {
119
+ return this.handleError(error, params.prompt);
120
+ }
121
+ }
122
+ handleError(error, prompt) {
123
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
124
+ // Check if it's a network error
125
+ if (this.isNetworkError(error)) {
126
+ return (0, result_1.Err)(new errors_1.NetworkError(`Network error during image generation: ${errorMessage}`, 'Check your internet connection and try again', error instanceof Error ? error : undefined));
127
+ }
128
+ // Check if it's an API-specific error
129
+ if (this.isAPIError(error)) {
130
+ return (0, result_1.Err)(new errors_1.GeminiAPIError(`Failed to generate image: ${errorMessage}`, this.getAPIErrorSuggestion(errorMessage), this.extractStatusCode(error)));
131
+ }
132
+ // Generic API error
133
+ return (0, result_1.Err)(new errors_1.GeminiAPIError(`Failed to generate image with prompt "${prompt}": ${errorMessage}`, 'Check your API key, quota, and prompt validity. Try again with a different prompt'));
134
+ }
135
+ isNetworkError(error) {
136
+ if (error instanceof Error) {
137
+ const networkErrorCodes = ['ECONNRESET', 'ECONNREFUSED', 'ETIMEDOUT', 'ENOTFOUND'];
138
+ return networkErrorCodes.some((code) => error.message.includes(code) || error.code === code);
139
+ }
140
+ return false;
141
+ }
142
+ isAPIError(error) {
143
+ if (error instanceof Error) {
144
+ const apiErrorKeywords = ['quota', 'rate limit', 'unauthorized', 'forbidden', 'api key'];
145
+ return apiErrorKeywords.some((keyword) => error.message.toLowerCase().includes(keyword));
146
+ }
147
+ return false;
148
+ }
149
+ getAPIErrorSuggestion(errorMessage) {
150
+ const lowerMessage = errorMessage.toLowerCase();
151
+ if (lowerMessage.includes('quota') || lowerMessage.includes('rate limit')) {
152
+ return 'You have exceeded your API quota or rate limit. Wait before making more requests or upgrade your plan';
153
+ }
154
+ if (lowerMessage.includes('unauthorized') || lowerMessage.includes('api key')) {
155
+ return 'Check that your GEMINI_API_KEY is valid and has the necessary permissions';
156
+ }
157
+ if (lowerMessage.includes('forbidden')) {
158
+ return 'Your API key does not have permission for this operation';
159
+ }
160
+ return 'Check your API configuration and try again';
161
+ }
162
+ extractStatusCode(error) {
163
+ if (error && typeof error === 'object' && 'status' in error) {
164
+ return typeof error.status === 'number' ? error.status : undefined;
165
+ }
166
+ return undefined;
167
+ }
168
+ /**
169
+ * Detect URLs in prompt for automatic URL Context activation
170
+ * @param prompt The prompt text to analyze
171
+ * @returns True if URLs are detected, false otherwise
172
+ */
173
+ detectUrls(prompt) {
174
+ return URL_PATTERN.test(prompt);
175
+ }
176
+ }
177
+ /**
178
+ * Creates a new Gemini API client
179
+ * @param config Configuration containing API key and other settings
180
+ * @returns Result containing the client or an error
181
+ */
182
+ function createGeminiClient(config) {
183
+ try {
184
+ const genai = new genai_1.GoogleGenAI({
185
+ apiKey: config.geminiApiKey,
186
+ });
187
+ return (0, result_1.Ok)(new GeminiClientImpl(genai));
188
+ }
189
+ catch (error) {
190
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
191
+ return (0, result_1.Err)(new errors_1.GeminiAPIError(`Failed to initialize Gemini client: ${errorMessage}`, 'Verify your GEMINI_API_KEY is valid and the @google/genai package is properly installed'));
192
+ }
193
+ }
194
+ //# sourceMappingURL=geminiClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geminiClient.js","sourceRoot":"","sources":["../../src/api/geminiClient.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;AAgWH,gDAeC;AA7WD,yCAA2C;AAE3C,4CAAyC;AAEzC,4CAA8D;AAE9D;;GAEG;AACH,MAAM,WAAW,GAAG,gFAAgF,CAAA;AA0FpG;;GAEG;AACH,MAAM,gBAAgB;IAGpB,YAA6B,KAA2B;QAA3B,UAAK,GAAL,KAAK,CAAsB;QAFvC,cAAS,GAAG,gCAAgC,CAAA;IAEF,CAAC;IAE5D,KAAK,CAAC,aAAa,CACjB,MAAuB;QAEvB,IAAI,CAAC;YACH,gEAAgE;YAChE,IAAI,cAAc,GAAG,MAAM,CAAC,MAAM,CAAA;YAElC,2DAA2D;YAC3D,IAAI,MAAM,CAAC,4BAA4B,EAAE,CAAC;gBACxC,cAAc;oBACZ,uKAAuK,CAAA;YAC3K,CAAC;YAED,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;gBACvB,cAAc;oBACZ,wHAAwH,CAAA;YAC5H,CAAC;YAED,IAAI,MAAM,CAAC,iBAAiB,EAAE,CAAC;gBAC7B,cAAc;oBACZ,oJAAoJ,CAAA;YACxJ,CAAC;YAED,mDAAmD;YACnD,MAAM,cAAc,GAAc,CAAC,cAAc,CAAC,CAAA;YAElD,8BAA8B;YAC9B,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;gBACtB,cAAc,CAAC,IAAI,CAAC;oBAClB,UAAU,EAAE;wBACV,IAAI,EAAE,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC;wBAC1C,QAAQ,EAAE,YAAY,EAAE,+BAA+B;qBACxD;iBACF,CAAC,CAAA;YACJ,CAAC;YAED,4BAA4B;YAC5B,MAAM,MAAM,GAER,EAAE,CAAA;YAEN,uDAAuD;YACvD,4EAA4E;YAC5E,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YAE9B,kEAAkE;YAClE,sEAAsE;YAEtE,sEAAsE;YACtE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,eAAe,CAAC;gBACvD,KAAK,EAAE,IAAI,CAAC,SAAS;gBACrB,QAAQ,EAAE,cAAc;gBACxB,MAAM;aACP,CAAC,CAAA;YAEF,mCAAmC;YACnC,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBAC9C,OAAO,IAAA,YAAG,EACR,IAAI,uBAAc,CAChB,kCAAkC,EAClC,gDAAgD,CACjD,CACF,CAAA;YACH,CAAC;YAED,uCAAuC;YACvC,MAAM,UAAU,GACd,QAAQ,CAAC,QAAQ,EAAE,UAAU;gBAC5B,QAAkD,CAAC,UAAU,CAAA;YAChE,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC3C,OAAO,IAAA,YAAG,EACR,IAAI,uBAAc,CAChB,kCAAkC,EAClC,6EAA6E,CAC9E,CACF,CAAA;YACH,CAAC;YAED,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,CAAA;YAC/B,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO,IAAA,YAAG,EACR,IAAI,uBAAc,CAChB,2CAA2C,EAC3C,oFAAoF,CACrF,CACF,CAAA;YACH,CAAC;YACD,MAAM,KAAK,GAAI,SAA4D,CAAC,OAAO,EAAE,KAAK,CAAA;YAC1F,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACjC,OAAO,IAAA,YAAG,EACR,IAAI,uBAAc,CAChB,2CAA2C,EAC3C,oFAAoF,CACrF,CACF,CAAA;YACH,CAAC;YAED,8CAA8C;YAC9C,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAa,EAAE,EAAE;gBAC7C,MAAM,CAAC,GAAG,IAA2D,CAAA;gBACrE,OAAO,CAAC,CAAC,UAAU,EAAE,IAAI,CAAA;YAC3B,CAAC,CAAoE,CAAA;YAErE,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,CAAC;gBAC3B,OAAO,IAAA,YAAG,EACR,IAAI,uBAAc,CAChB,4CAA4C,EAC5C,mEAAmE,CACpE,CACF,CAAA;YACH,CAAC;YAED,sCAAsC;YACtC,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;YACpE,MAAM,QAAQ,GAAG,SAAS,CAAC,UAAU,CAAC,QAAQ,IAAI,WAAW,CAAA;YAE7D,4CAA4C;YAC5C,MAAM,QAAQ,GAA6B;gBACzC,KAAK,EAAE,IAAI,CAAC,SAAS;gBACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,gCAAgC;gBACvD,QAAQ;gBACR,SAAS,EAAE,IAAI,IAAI,EAAE;gBACrB,kBAAkB,EAAE,CAAC,CAAC,MAAM,CAAC,UAAU;gBACvC,aAAa,EAAE,aAAa;aAC7B,CAAA;YAED,iFAAiF;YACjF,IACE,MAAM,CAAC,WAAW,KAAK,SAAS;gBAChC,MAAM,CAAC,4BAA4B,KAAK,SAAS;gBACjD,MAAM,CAAC,iBAAiB,KAAK,SAAS,EACtC,CAAC;gBACD,QAAQ,CAAC,QAAQ,GAAG;oBAClB,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,KAAK;oBACxC,4BAA4B,EAAE,MAAM,CAAC,4BAA4B,IAAI,KAAK;oBAC1E,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,IAAI,KAAK;iBACrD,CAAA;YACH,CAAC;YAED,OAAO,IAAA,WAAE,EAAC;gBACR,SAAS,EAAE,WAAW;gBACtB,QAAQ;aACT,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;QAC/C,CAAC;IACH,CAAC;IAEO,WAAW,CACjB,KAAc,EACd,MAAc;QAEd,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAA;QAE7E,gCAAgC;QAChC,IAAI,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO,IAAA,YAAG,EACR,IAAI,qBAAY,CACd,0CAA0C,YAAY,EAAE,EACxD,8CAA8C,EAC9C,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAC3C,CACF,CAAA;QACH,CAAC;QAED,sCAAsC;QACtC,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO,IAAA,YAAG,EACR,IAAI,uBAAc,CAChB,6BAA6B,YAAY,EAAE,EAC3C,IAAI,CAAC,qBAAqB,CAAC,YAAY,CAAC,EACxC,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAC9B,CACF,CAAA;QACH,CAAC;QAED,oBAAoB;QACpB,OAAO,IAAA,YAAG,EACR,IAAI,uBAAc,CAChB,yCAAyC,MAAM,MAAM,YAAY,EAAE,EACnE,mFAAmF,CACpF,CACF,CAAA;IACH,CAAC;IAEO,cAAc,CAAC,KAAc;QACnC,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,MAAM,iBAAiB,GAAG,CAAC,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW,CAAC,CAAA;YAClF,OAAO,iBAAiB,CAAC,IAAI,CAC3B,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAK,KAAuB,CAAC,IAAI,KAAK,IAAI,CACjF,CAAA;QACH,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;IAEO,UAAU,CAAC,KAAc;QAC/B,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,MAAM,gBAAgB,GAAG,CAAC,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,CAAC,CAAA;YACxF,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAA;QAC1F,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;IAEO,qBAAqB,CAAC,YAAoB;QAChD,MAAM,YAAY,GAAG,YAAY,CAAC,WAAW,EAAE,CAAA;QAE/C,IAAI,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;YAC1E,OAAO,uGAAuG,CAAA;QAChH,CAAC;QAED,IAAI,YAAY,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YAC9E,OAAO,2EAA2E,CAAA;QACpF,CAAC;QAED,IAAI,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YACvC,OAAO,0DAA0D,CAAA;QACnE,CAAC;QAED,OAAO,4CAA4C,CAAA;IACrD,CAAC;IAEO,iBAAiB,CAAC,KAAc;QACtC,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,QAAQ,IAAI,KAAK,EAAE,CAAC;YAC5D,OAAO,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAA;QACpE,CAAC;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;IAED;;;;OAIG;IACK,UAAU,CAAC,MAAc;QAC/B,OAAO,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IACjC,CAAC;CACF;AAED;;;;GAIG;AACH,SAAgB,kBAAkB,CAAC,MAAc;IAC/C,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,mBAAW,CAAC;YAC5B,MAAM,EAAE,MAAM,CAAC,YAAY;SAC5B,CAAoC,CAAA;QACrC,OAAO,IAAA,WAAE,EAAC,IAAI,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAA;IACxC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAA;QAC7E,OAAO,IAAA,YAAG,EACR,IAAI,uBAAc,CAChB,uCAAuC,YAAY,EAAE,EACrD,yFAAyF,CAC1F,CACF,CAAA;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,149 @@
1
+ /**
2
+ * URL Context API client for processing URLs and extracting context
3
+ * Uses @google/genai SDK for URL context processing
4
+ */
5
+ import { type Result } from '../types/result';
6
+ import { NetworkError, URLContextError } from '../utils/errors';
7
+ /**
8
+ * Response from URL context processing
9
+ */
10
+ export interface UrlContextResponse {
11
+ /** Context content extracted from URLs */
12
+ contextContent: string;
13
+ /** Combined prompt with context and cleaned original prompt */
14
+ combinedPrompt: string;
15
+ /** Additional extracted information */
16
+ extractedInfo: Record<string, unknown>;
17
+ /** Success flag */
18
+ success: boolean;
19
+ }
20
+ /**
21
+ * Mock interface for text generation (to be replaced with real implementation later)
22
+ */
23
+ interface TextGenerationClient {
24
+ generateText(prompt: string): Promise<Result<{
25
+ text: string;
26
+ }, Error>>;
27
+ }
28
+ /**
29
+ * Client for processing URLs and extracting context
30
+ * Basic implementation for Phase 2 - will be enhanced in later phases
31
+ */
32
+ export declare class UrlContextClient {
33
+ private textClient;
34
+ /**
35
+ * Maximum number of URLs to process (performance consideration)
36
+ */
37
+ private static readonly MAX_URLS;
38
+ /**
39
+ * Maximum number of retry attempts
40
+ */
41
+ private readonly MAX_RETRIES;
42
+ /**
43
+ * Timeout for URL context processing in milliseconds
44
+ */
45
+ private readonly TIMEOUT_MS;
46
+ constructor(textClient: TextGenerationClient);
47
+ /**
48
+ * Process multiple URLs and extract context for image generation
49
+ * @param urls Array of URLs to process
50
+ * @param originalPrompt Original prompt containing URLs
51
+ * @returns Result containing URL context response with combined prompt or error
52
+ */
53
+ processUrls(urls: string[], originalPrompt: string): Promise<Result<UrlContextResponse, URLContextError | NetworkError>>;
54
+ /**
55
+ * Process URLs with retry mechanism and timeout
56
+ * @param urls Array of URLs to process
57
+ * @param originalPrompt Original prompt containing URLs
58
+ * @returns Result containing URL context response with retry information
59
+ */
60
+ processUrlsWithRetry(urls: string[], originalPrompt: string): Promise<Result<UrlContextResponse, URLContextError | NetworkError>>;
61
+ /**
62
+ * Process URLs with timeout protection
63
+ * @param urls Array of URLs to process
64
+ * @param originalPrompt Original prompt containing URLs
65
+ * @returns Result with timeout protection
66
+ */
67
+ private processUrlsWithTimeout;
68
+ /**
69
+ * Core URL processing logic without retry/timeout
70
+ * @param urls Array of URLs to process
71
+ * @param originalPrompt Original prompt containing URLs
72
+ * @returns Result containing URL context response
73
+ */
74
+ private processUrlsCore;
75
+ /**
76
+ * Build a context extraction prompt for Gemini API
77
+ * @param urls Array of URLs to process
78
+ * @param originalPrompt Original prompt containing URLs
79
+ * @returns Formatted prompt for context extraction
80
+ */
81
+ private buildContextPrompt;
82
+ /**
83
+ * Combine URL context with original prompt for image generation
84
+ * @param contextPrompts Array of context content from URLs
85
+ * @param originalPrompt Original prompt containing URLs
86
+ * @param urls Array of processed URLs
87
+ * @returns Combined prompt for image generation
88
+ */
89
+ private combineContextWithPrompt;
90
+ /**
91
+ * Remove URLs and clean up common action words from prompt
92
+ * @param originalPrompt Original prompt containing URLs
93
+ * @returns Cleaned prompt suitable for final instruction
94
+ */
95
+ private cleanPromptFromUrls;
96
+ /**
97
+ * Format and clean context content from multiple sources
98
+ * @param contextPrompts Array of raw context content
99
+ * @returns Formatted context content
100
+ */
101
+ private formatContextContent;
102
+ /**
103
+ * Format the final combined prompt with context and instruction sections
104
+ * @param urls Array of processed URLs
105
+ * @param contextContent Formatted context content
106
+ * @param finalPrompt Final instruction prompt
107
+ * @returns Complete combined prompt
108
+ */
109
+ private formatCombinedPrompt;
110
+ /**
111
+ * Create a standardized context error from API failure
112
+ * @param originalError The original error from text generation
113
+ * @returns Formatted URLContextError
114
+ */
115
+ private createContextError;
116
+ /**
117
+ * Create appropriate error based on error type
118
+ * @param error The original error that occurred
119
+ * @returns Formatted error (NetworkError or URLContextError)
120
+ */
121
+ private createProcessingError;
122
+ /**
123
+ * Parse extracted information from context content
124
+ * @param contextContent The context content to parse
125
+ * @param processedUrlCount Number of URLs that were processed
126
+ * @returns Structured extracted information
127
+ */
128
+ private parseExtractedInfo;
129
+ /**
130
+ * Check if an error is network-related
131
+ * @param error The error to check
132
+ * @returns True if it's a network error
133
+ */
134
+ private isNetworkError;
135
+ /**
136
+ * Check if an error is retryable
137
+ * @param error The error to check
138
+ * @returns True if the error should trigger a retry
139
+ */
140
+ private isRetryableError;
141
+ /**
142
+ * Add a delay for exponential backoff
143
+ * @param ms Milliseconds to delay
144
+ * @returns Promise that resolves after the delay
145
+ */
146
+ private delay;
147
+ }
148
+ export {};
149
+ //# sourceMappingURL=urlContextClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"urlContextClient.d.ts","sourceRoot":"","sources":["../../src/api/urlContextClient.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAE/D;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,0CAA0C;IAC1C,cAAc,EAAE,MAAM,CAAA;IACtB,+DAA+D;IAC/D,cAAc,EAAE,MAAM,CAAA;IACtB,uCAAuC;IACvC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACtC,mBAAmB;IACnB,OAAO,EAAE,OAAO,CAAA;CACjB;AAED;;GAEG;AACH,UAAU,oBAAoB;IAC5B,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,KAAK,CAAC,CAAC,CAAA;CACvE;AAED;;;GAGG;AACH,qBAAa,gBAAgB;IAgBf,OAAO,CAAC,UAAU;IAf9B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAK;IAErC;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAI;IAEhC;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;gBAEf,UAAU,EAAE,oBAAoB;IAEpD;;;;;OAKG;IACG,WAAW,CACf,IAAI,EAAE,MAAM,EAAE,EACd,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,eAAe,GAAG,YAAY,CAAC,CAAC;IAuBtE;;;;;OAKG;IACG,oBAAoB,CACxB,IAAI,EAAE,MAAM,EAAE,EACd,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,eAAe,GAAG,YAAY,CAAC,CAAC;IA0DtE;;;;;OAKG;YACW,sBAAsB;IA4BpC;;;;;OAKG;YACW,eAAe;IA2B7B;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAoB1B;;;;;;OAMG;IACH,OAAO,CAAC,wBAAwB;IAYhC;;;;OAIG;IACH,OAAO,CAAC,mBAAmB;IAkB3B;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;;;;;OAMG;IACH,OAAO,CAAC,oBAAoB;IAW5B;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAO1B;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IAmB7B;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAoB1B;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAqBtB;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAoBxB;;;;OAIG;YACW,KAAK;CAGpB"}