├── .cursorignore
├── .gitignore
├── LICENSE
├── README.md
├── package.json
├── src
└── index.ts
├── test_cat_image.png
├── test_cat_image_edited.png
├── test_cat_with_moustache.png
├── tsconfig.json
└── yarn.lock
/.cursorignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | dist/
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .env
3 | /dist
4 | .DS_Store
5 | /dist
6 | /build
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024
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.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # openai-gpt-image-mcp
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ---
12 |
13 | A Model Context Protocol (MCP) tool server for OpenAI's GPT-4o/gpt-image-1 image generation and editing APIs.
14 |
15 | - **Generate images** from text prompts using OpenAI's latest models.
16 | - **Edit images** (inpainting, outpainting, compositing) with advanced prompt control.
17 | - **Supports**: Claude Desktop, Cursor, VSCode, Windsurf, and any MCP-compatible client.
18 |
19 | ---
20 |
21 | ## ✨ Features
22 |
23 | - **create-image**: Generate images from a prompt, with advanced options (size, quality, background, etc).
24 | - **edit-image**: Edit or extend images using a prompt and optional mask, supporting both file paths and base64 input.
25 | - **File output**: Save generated images directly to disk, or receive as base64.
26 |
27 | ---
28 |
29 | ## 🚀 Installation
30 |
31 | ```sh
32 | git clone https://github.com/SureScaleAI/openai-gpt-image-mcp.git
33 | cd openai-gpt-image-mcp
34 | yarn install
35 | yarn build
36 | ```
37 |
38 | ---
39 |
40 | ## 🔑 Configuration
41 |
42 | Add to Claude Desktop or VSCode (including Cursor/Windsurf) config:
43 |
44 | ```json
45 | {
46 | "mcpServers": {
47 | "openai-gpt-image-mcp": {
48 | "command": "node",
49 | "args": ["/absolute/path/to/dist/index.js"],
50 | "env": { "OPENAI_API_KEY": "sk-..." }
51 | }
52 | }
53 | }
54 | ```
55 |
56 | Also supports Azure deployments:
57 |
58 | ```json
59 | {
60 | "mcpServers": {
61 | "openai-gpt-image-mcp": {
62 | "command": "node",
63 | "args": ["/absolute/path/to/dist/index.js"],
64 | "env": {
65 | "AZURE_OPENAI_API_KEY": "sk-...",
66 | "AZURE_OPENAI_ENDPOINT": "my.endpoint.com",
67 | "OPENAI_API_VERSION": "2024-12-01-preview"
68 | }
69 | }
70 | }
71 | }
72 | ```
73 |
74 | Also supports supplying an environment files:
75 |
76 | ```json
77 | {
78 | "mcpServers": {
79 | "openai-gpt-image-mcp": {
80 | "command": "node",
81 | "args": ["/absolute/path/to/dist/index.js", "--env-file", "./deployment/.env"]
82 | }
83 | }
84 | }
85 | ```
86 |
87 | ---
88 |
89 | ## ⚡ Advanced
90 |
91 | - For `create-image`, set `n` to generate up to 10 images at once.
92 | - For `edit-image`, provide a mask image (file path or base64) to control where edits are applied.
93 | - Provide an environment file with `--env-file path/to/file/.env`
94 | - See `src/index.ts` for all options.
95 |
96 | ---
97 |
98 | ## 🧑💻 Development
99 |
100 | - TypeScript source: `src/index.ts`
101 | - Build: `yarn build`
102 | - Run: `node dist/index.js`
103 |
104 | ---
105 |
106 | ## 📝 License
107 |
108 | MIT
109 |
110 | ---
111 |
112 | ## 🩺 Troubleshooting
113 |
114 | - Make sure your `OPENAI_API_KEY` is valid and has image API access.
115 | - You must have a [verified OpenAI organization](https://platform.openai.com/account/organization). After verifying, it can take 15–20 minutes for image API access to activate.
116 | - File paths must be absolute.
117 | - **Unix/macOS/Linux**: Starting with `/` (e.g., `/path/to/image.png`)
118 | - **Windows**: Drive letter followed by `:` (e.g., `C:/path/to/image.png` or `C:\path\to\image.png`)
119 | - For file output, ensure the directory is writable.
120 | - If you see errors about file types, check your image file extensions and formats.
121 |
122 | ---
123 |
124 | ## ⚠️ Limitations & Large File Handling
125 |
126 | - **1MB Payload Limit:** MCP clients (including Claude Desktop) have a hard 1MB limit for tool responses. Large images (especially high-res or multiple images) can easily exceed this limit if returned as base64.
127 | - **Auto-Switch to File Output:** If the total image size exceeds 1MB, the tool will automatically save images to disk and return the file path(s) instead of base64. This ensures compatibility and prevents errors like `result exceeds maximum length of 1048576`.
128 | - **Default File Location:** If you do not specify a `file_output` path, images will be saved to `/tmp` (or the directory set by the `MCP_HF_WORK_DIR` environment variable) with a unique filename.
129 | - **Environment Variable:**
130 | - `MCP_HF_WORK_DIR`: Set this to control where large images and file outputs are saved. Example: `export MCP_HF_WORK_DIR=/your/desired/dir`
131 | - **Best Practice:** For large or production images, always use file output and ensure your client is configured to handle file paths.
132 |
133 | ---
134 |
135 | ## 📚 References
136 |
137 | - [OpenAI Images API Documentation](https://platform.openai.com/docs/api-reference/images)
138 |
139 | ---
140 |
141 | ## 🙏 Credits
142 |
143 | - Built with [@modelcontextprotocol/sdk](https://www.npmjs.com/package/@modelcontextprotocol/sdk)
144 | - Uses [openai](https://www.npmjs.com/package/openai) Node.js SDK
145 | - Built by [SureScale.ai](https://surescale.ai)
146 | - Contributions from [Axle Research and Technology](https://axleinfo.com/)
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "openai-gpt-image-mcp",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "license": "MIT",
6 | "devDependencies": {
7 | "@types/node": "^22.15.2",
8 | "typescript": "^5.8.3"
9 | },
10 | "dependencies": {
11 | "@modelcontextprotocol/sdk": "^1.10.2",
12 | "openai": "^4.96.0"
13 | },
14 | "scripts": {
15 | "build": "tsc"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | // Suppress all Node.js warnings (including deprecation)
2 | (process as any).emitWarning = () => { };
3 |
4 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6 | import { z } from "zod";
7 | import { OpenAI, AzureOpenAI, toFile } from "openai";
8 | import fs from "fs";
9 | import path from "path";
10 |
11 | // Function to load environment variables from a file
12 | const loadEnvFile = (filePath: string) => {
13 | try {
14 | const envConfig = fs.readFileSync(filePath, "utf8");
15 | envConfig.split("\n").forEach((line) => {
16 | const trimmedLine = line.trim();
17 | if (trimmedLine && !trimmedLine.startsWith("#")) {
18 | const [key, ...valueParts] = trimmedLine.split("=");
19 | const value = valueParts.join("=").trim();
20 | if (key) {
21 | // Remove surrounding quotes if present
22 | process.env[key.trim()] = value.startsWith("'") && value.endsWith("'") || value.startsWith("\"") && value.endsWith("\"")
23 | ? value.slice(1, -1)
24 | : value;
25 | }
26 | }
27 | });
28 | console.log(`Loaded environment variables from ${filePath}`);
29 | } catch (error) {
30 | console.warn(`Warning: Could not read environment file at ${filePath}:`, error);
31 | }
32 | };
33 |
34 | // Parse command line arguments for --env-file
35 | const cmdArgs = process.argv.slice(2);
36 | const envFileArgIndex = cmdArgs.findIndex(arg => arg === "--env-file");
37 | if (envFileArgIndex !== -1 && cmdArgs[envFileArgIndex + 1]) {
38 | console.log("Loading environment variables from file:", cmdArgs[envFileArgIndex + 1]);
39 | const envFilePath = cmdArgs[envFileArgIndex + 1];
40 | loadEnvFile(envFilePath);
41 | } else {
42 | console.log("No environment file provided");
43 | }
44 |
45 | (async () => {
46 | const server = new McpServer({
47 | name: "openai-gpt-image-mcp",
48 | version: "1.0.0"
49 | }, {
50 | capabilities: {
51 | tools: { listChanged: false }
52 | }
53 | });
54 |
55 | // Zod schema for create-image tool input
56 | const createImageSchema = z.object({
57 | prompt: z.string().max(32000),
58 | background: z.enum(["transparent", "opaque", "auto"]).optional(),
59 | model: z.literal("gpt-image-1").default("gpt-image-1"),
60 | moderation: z.enum(["auto", "low"]).optional(),
61 | n: z.number().int().min(1).max(10).optional(),
62 | output_compression: z.number().int().min(0).max(100).optional(),
63 | output_format: z.enum(["png", "jpeg", "webp"]).optional(),
64 | quality: z.enum(["auto", "high", "medium", "low"]).optional(),
65 | size: z.enum(["1024x1024", "1536x1024", "1024x1536", "auto"]).optional(),
66 | user: z.string().optional(),
67 | output: z.enum(["base64", "file_output"]).default("base64"),
68 | file_output: z.string().optional().refine(
69 | (val) => {
70 | if (!val) return true;
71 | // Check for Unix/Linux/macOS absolute paths
72 | if (val.startsWith("/")) return true;
73 | // Check for Windows absolute paths (C:/, D:\, etc.)
74 | if (/^[a-zA-Z]:[/\\]/.test(val)) return true;
75 | return false;
76 | },
77 | { message: "file_output must be an absolute path" }
78 | ).describe("Absolute path to save the image file, including the desired file extension (e.g., /path/to/image.png). If multiple images are generated (n > 1), an index will be appended (e.g., /path/to/image_1.png)."),
79 | }).refine(
80 | (data) => {
81 | if (data.output !== "file_output") return true;
82 | if (typeof data.file_output !== "string") return false;
83 | // Check for Unix/Linux/macOS absolute paths
84 | if (data.file_output.startsWith("/")) return true;
85 | // Check for Windows absolute paths (C:/, D:\, etc.)
86 | if (/^[a-zA-Z]:[/\\]/.test(data.file_output)) return true;
87 | return false;
88 | },
89 | { message: "file_output must be an absolute path when output is 'file_output'", path: ["file_output"] }
90 | );
91 |
92 | // Use ._def.schema.shape to get the raw shape for server.tool due to Zod refinements
93 | server.tool(
94 | "create-image",
95 | (createImageSchema as any)._def.schema.shape,
96 | async (args, _extra) => {
97 | // If AZURE_OPENAI_API_KEY is defined, use the AzureOpenAI class
98 | const openai = process.env.AZURE_OPENAI_API_KEY ? new AzureOpenAI() : new OpenAI();
99 |
100 | // Only allow gpt-image-1
101 | const {
102 | prompt,
103 | background,
104 | model = "gpt-image-1",
105 | moderation,
106 | n,
107 | output_compression,
108 | output_format,
109 | quality,
110 | size,
111 | user,
112 | output = "base64",
113 | file_output: file_outputRaw,
114 | } = args;
115 | const file_output: string | undefined = file_outputRaw;
116 |
117 | // Enforce: if background is 'transparent', output_format must be 'png' or 'webp'
118 | if (background === "transparent" && output_format && !["png", "webp"].includes(output_format)) {
119 | throw new Error("If background is 'transparent', output_format must be 'png' or 'webp'");
120 | }
121 |
122 | // Only include output_compression if output_format is webp or jpeg
123 | const imageParams: any = {
124 | prompt,
125 | model,
126 | ...(background ? { background } : {}),
127 | ...(moderation ? { moderation } : {}),
128 | ...(n ? { n } : {}),
129 | ...(output_format ? { output_format } : {}),
130 | ...(quality ? { quality } : {}),
131 | ...(size ? { size } : {}),
132 | ...(user ? { user } : {}),
133 | };
134 | if (
135 | typeof output_compression !== "undefined" &&
136 | output_format &&
137 | ["webp", "jpeg"].includes(output_format)
138 | ) {
139 | imageParams.output_compression = output_compression;
140 | }
141 |
142 | const result = await openai.images.generate(imageParams);
143 |
144 | // gpt-image-1 always returns base64 images in data[].b64_json
145 | const images = (result.data ?? []).map((img: any) => ({
146 | b64: img.b64_json,
147 | mimeType: output_format === "jpeg" ? "image/jpeg" : output_format === "webp" ? "image/webp" : "image/png",
148 | ext: output_format === "jpeg" ? "jpg" : output_format === "webp" ? "webp" : "png",
149 | }));
150 |
151 | // Auto-switch to file_output if total base64 size exceeds 1MB
152 | const MAX_RESPONSE_SIZE = 1048576; // 1MB
153 | const totalBase64Size = images.reduce((sum, img) => sum + Buffer.byteLength(img.b64, "base64"), 0);
154 | let effectiveOutput = output;
155 | let effectiveFileOutput = file_output;
156 | if (output === "base64" && totalBase64Size > MAX_RESPONSE_SIZE) {
157 | effectiveOutput = "file_output";
158 | if (!file_output) {
159 | // Use /tmp or MCP_HF_WORK_DIR if set
160 | const tmpDir = process.env.MCP_HF_WORK_DIR || "/tmp";
161 | const unique = Date.now();
162 | effectiveFileOutput = path.join(tmpDir, `openai_image_${unique}.${images[0]?.ext ?? "png"}`);
163 | }
164 | }
165 |
166 | if (effectiveOutput === "file_output") {
167 | const fs = await import("fs/promises");
168 | const path = await import("path");
169 | // If multiple images, append index to filename
170 | const basePath = effectiveFileOutput!;
171 | const responses = [];
172 | for (let i = 0; i < images.length; i++) {
173 | const img = images[i];
174 | let filePath = basePath;
175 | if (images.length > 1) {
176 | const parsed = path.parse(basePath);
177 | filePath = path.join(parsed.dir, `${parsed.name}_${i + 1}.${img.ext ?? "png"}`);
178 | } else {
179 | // Ensure correct extension
180 | const parsed = path.parse(basePath);
181 | filePath = path.join(parsed.dir, `${parsed.name}.${img.ext ?? "png"}`);
182 | }
183 | await fs.writeFile(filePath, Buffer.from(img.b64, "base64"));
184 | responses.push({ type: "text", text: `Image saved to: file://${filePath}` });
185 | }
186 | return { content: responses };
187 | } else {
188 | // Default: base64
189 | return {
190 | content: images.map((img) => ({
191 | type: "image",
192 | data: img.b64,
193 | mimeType: img.mimeType,
194 | })),
195 | };
196 | }
197 | }
198 | );
199 |
200 | // Zod schema for edit-image tool input (gpt-image-1 only)
201 | const absolutePathCheck = (val: string | undefined) => {
202 | if (!val) return true;
203 | // Check for Unix/Linux/macOS absolute paths
204 | if (val.startsWith("/")) return true;
205 | // Check for Windows absolute paths (C:/, D:\, etc.)
206 | if (/^[a-zA-Z]:[/\\]/.test(val)) return true;
207 | return false;
208 | };
209 | const base64Check = (val: string | undefined) => !!val && (/^([A-Za-z0-9+/=\r\n]+)$/.test(val) || val.startsWith("data:image/"));
210 | const imageInputSchema = z.string().refine(
211 | (val) => absolutePathCheck(val) || base64Check(val),
212 | { message: "Must be an absolute path or a base64-encoded string (optionally as a data URL)" }
213 | ).describe("Absolute path to an image file (png, jpg, webp < 25MB) or a base64-encoded image string.");
214 |
215 | // Base schema without refinement for server.tool signature
216 | const editImageBaseSchema = z.object({
217 | image: z.string().describe("Absolute image path or base64 string to edit."),
218 | prompt: z.string().max(32000).describe("A text description of the desired edit. Max 32000 chars."),
219 | mask: z.string().optional().describe("Optional absolute path or base64 string for a mask image (png < 4MB, same dimensions as the first image). Fully transparent areas indicate where to edit."),
220 | model: z.literal("gpt-image-1").default("gpt-image-1"),
221 | n: z.number().int().min(1).max(10).optional().describe("Number of images to generate (1-10)."),
222 | quality: z.enum(["auto", "high", "medium", "low"]).optional().describe("Quality (high, medium, low) - only for gpt-image-1."),
223 | size: z.enum(["1024x1024", "1536x1024", "1024x1536", "auto"]).optional().describe("Size of the generated images."),
224 | user: z.string().optional().describe("Optional user identifier for OpenAI monitoring."),
225 | output: z.enum(["base64", "file_output"]).default("base64").describe("Output format: base64 or file path."),
226 | file_output: z.string().refine(absolutePathCheck, { message: "Path must be absolute" }).optional()
227 | .describe("Absolute path to save the output image file, including the desired file extension (e.g., /path/to/image.png). If n > 1, an index is appended."),
228 | });
229 |
230 | // Full schema with refinement for validation inside the handler
231 | const editImageSchema = editImageBaseSchema.refine(
232 | (data) => {
233 | if (data.output !== "file_output") return true;
234 | if (typeof data.file_output !== "string") return false;
235 | return absolutePathCheck(data.file_output);
236 | },
237 | { message: "file_output must be an absolute path when output is 'file_output'", path: ["file_output"] }
238 | );
239 |
240 | // Edit Image Tool (gpt-image-1 only)
241 | server.tool(
242 | "edit-image",
243 | editImageBaseSchema.shape, // <-- Use the base schema shape here
244 | async (args, _extra) => {
245 | // Validate arguments using the full schema with refinements
246 | const validatedArgs = editImageSchema.parse(args);
247 |
248 | // Explicitly validate image and mask inputs here
249 | if (!absolutePathCheck(validatedArgs.image) && !base64Check(validatedArgs.image)) {
250 | throw new Error("Invalid 'image' input: Must be an absolute path or a base64-encoded string.");
251 | }
252 | if (validatedArgs.mask && !absolutePathCheck(validatedArgs.mask) && !base64Check(validatedArgs.mask)) {
253 | throw new Error("Invalid 'mask' input: Must be an absolute path or a base64-encoded string.");
254 | }
255 |
256 | const openai = process.env.AZURE_OPENAI_API_KEY ? new AzureOpenAI() : new OpenAI();
257 | const {
258 | image: imageInput,
259 | prompt,
260 | mask: maskInput,
261 | model = "gpt-image-1",
262 | n,
263 | quality,
264 | size,
265 | user,
266 | output = "base64",
267 | file_output: file_outputRaw,
268 | } = validatedArgs; // <-- Use validatedArgs here
269 | const file_output: string | undefined = file_outputRaw;
270 |
271 | // Helper to convert input (path or base64) to toFile
272 | async function inputToFile(input: string, idx = 0) {
273 | if (absolutePathCheck(input)) {
274 | // File path: infer mime type from extension
275 | const ext = input.split('.').pop()?.toLowerCase();
276 | let mime = "image/png";
277 | if (ext === "jpg" || ext === "jpeg") mime = "image/jpeg";
278 | else if (ext === "webp") mime = "image/webp";
279 | else if (ext === "png") mime = "image/png";
280 | // else default to png
281 | return await toFile(fs.createReadStream(input), undefined, { type: mime });
282 | } else {
283 | // Base64 or data URL
284 | let base64 = input;
285 | let mime = "image/png";
286 | if (input.startsWith("data:image/")) {
287 | // data URL
288 | const match = input.match(/^data:(image\/\w+);base64,(.*)$/);
289 | if (match) {
290 | mime = match[1];
291 | base64 = match[2];
292 | }
293 | }
294 | const buffer = Buffer.from(base64, "base64");
295 | return await toFile(buffer, `input_${idx}.${mime.split("/")[1] || "png"}`, { type: mime });
296 | }
297 | }
298 |
299 | // Prepare image input
300 | const imageFile = await inputToFile(imageInput, 0);
301 |
302 | // Prepare mask input
303 | const maskFile = maskInput ? await inputToFile(maskInput, 1) : undefined;
304 |
305 | // Construct parameters for OpenAI API
306 | const editParams: any = {
307 | image: imageFile,
308 | prompt,
309 | model, // Always gpt-image-1
310 | ...(maskFile ? { mask: maskFile } : {}),
311 | ...(n ? { n } : {}),
312 | ...(quality ? { quality } : {}),
313 | ...(size ? { size } : {}),
314 | ...(user ? { user } : {}),
315 | // response_format is not applicable for gpt-image-1 (always b64_json)
316 | };
317 |
318 | const result = await openai.images.edit(editParams);
319 |
320 | // gpt-image-1 always returns base64 images in data[].b64_json
321 | // We need to determine the output mime type and extension based on input/defaults
322 | // Since OpenAI doesn't return this for edits, we'll default to png
323 | const images = (result.data ?? []).map((img: any) => ({
324 | b64: img.b64_json,
325 | mimeType: "image/png",
326 | ext: "png",
327 | }));
328 |
329 | // Auto-switch to file_output if total base64 size exceeds 1MB
330 | const MAX_RESPONSE_SIZE = 1048576; // 1MB
331 | const totalBase64Size = images.reduce((sum, img) => sum + Buffer.byteLength(img.b64, "base64"), 0);
332 | let effectiveOutput = output;
333 | let effectiveFileOutput = file_output;
334 | if (output === "base64" && totalBase64Size > MAX_RESPONSE_SIZE) {
335 | effectiveOutput = "file_output";
336 | if (!file_output) {
337 | // Use /tmp or MCP_HF_WORK_DIR if set
338 | const tmpDir = process.env.MCP_HF_WORK_DIR || "/tmp";
339 | const unique = Date.now();
340 | effectiveFileOutput = path.join(tmpDir, `openai_image_edit_${unique}.png`);
341 | }
342 | }
343 |
344 | if (effectiveOutput === "file_output") {
345 | if (!effectiveFileOutput) {
346 | throw new Error("file_output path is required when output is 'file_output'");
347 | }
348 | // Use fs/promises and path (already imported)
349 | const basePath = effectiveFileOutput!;
350 | const responses = [];
351 | for (let i = 0; i < images.length; i++) {
352 | const img = images[i];
353 | let filePath = basePath;
354 | if (images.length > 1) {
355 | const parsed = path.parse(basePath);
356 | // Append index before the original extension if it exists, otherwise just append index and .png
357 | const ext = parsed.ext || `.${img.ext}`;
358 | filePath = path.join(parsed.dir, `${parsed.name}_${i + 1}${ext}`);
359 | } else {
360 | // Ensure the extension from the path is used, or default to .png
361 | const parsed = path.parse(basePath);
362 | const ext = parsed.ext || `.${img.ext}`;
363 | filePath = path.join(parsed.dir, `${parsed.name}${ext}`);
364 | }
365 | await fs.promises.writeFile(filePath, Buffer.from(img.b64, "base64"));
366 | // Workaround: Return file path as text
367 | responses.push({ type: "text", text: `Image saved to: file://${filePath}` });
368 | }
369 | return { content: responses };
370 | } else {
371 | // Default: base64
372 | return {
373 | content: images.map((img) => ({
374 | type: "image",
375 | data: img.b64,
376 | mimeType: img.mimeType, // Should be image/png
377 | })),
378 | };
379 | }
380 | }
381 | );
382 |
383 | const transport = new StdioServerTransport();
384 | await server.connect(transport);
385 | })();
--------------------------------------------------------------------------------
/test_cat_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SureScaleAI/openai-gpt-image-mcp/558265a1c92d4ab51efdd03135286b727487204c/test_cat_image.png
--------------------------------------------------------------------------------
/test_cat_image_edited.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SureScaleAI/openai-gpt-image-mcp/558265a1c92d4ab51efdd03135286b727487204c/test_cat_image_edited.png
--------------------------------------------------------------------------------
/test_cat_with_moustache.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SureScaleAI/openai-gpt-image-mcp/558265a1c92d4ab51efdd03135286b727487204c/test_cat_with_moustache.png
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Visit https://aka.ms/tsconfig to read more about this file */
4 |
5 | /* Projects */
6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
12 |
13 | /* Language and Environment */
14 | "target": "es2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
16 | // "jsx": "preserve", /* Specify what JSX code is generated. */
17 | // "libReplacement": true, /* Enable lib replacement. */
18 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
19 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
20 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
21 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
22 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
23 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
24 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
25 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
26 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
27 |
28 | /* Modules */
29 | "module": "commonjs", /* Specify what module code is generated. */
30 | "rootDir": "src", /* Specify the root folder within your source files. */
31 | // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
32 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
33 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
34 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
35 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
36 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */
37 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
38 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
39 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
40 | // "rewriteRelativeImportExtensions": true, /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */
41 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
42 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
43 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
44 | // "noUncheckedSideEffectImports": true, /* Check side effect imports. */
45 | // "resolveJsonModule": true, /* Enable importing .json files. */
46 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
47 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */
48 |
49 | /* JavaScript Support */
50 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
51 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
52 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
53 |
54 | /* Emit */
55 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
56 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */
57 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
58 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */
59 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
60 | // "noEmit": true, /* Disable emitting files from a compilation. */
61 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
62 | "outDir": "dist", /* Specify an output folder for all emitted files. */
63 | // "removeComments": true, /* Disable emitting comments. */
64 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
65 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
66 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
67 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
68 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
69 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
70 | // "newLine": "crlf", /* Set the newline character for emitting files. */
71 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
72 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
73 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
74 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
75 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */
76 |
77 | /* Interop Constraints */
78 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
79 | // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
80 | // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */
81 | // "erasableSyntaxOnly": true, /* Do not allow runtime constructs that are not part of ECMAScript. */
82 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
83 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
84 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
85 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
86 |
87 | /* Type Checking */
88 | "strict": false, /* Enable all strict type-checking options. */
89 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
90 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
91 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
92 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
93 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
94 | // "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */
95 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
96 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
97 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
98 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
99 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
100 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
101 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
102 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
103 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
104 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
105 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
106 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
107 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
108 |
109 | /* Completeness */
110 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
111 | "skipLibCheck": true /* Skip type checking all .d.ts files. */
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@modelcontextprotocol/sdk@^1.10.2":
6 | version "1.10.2"
7 | resolved "https://registry.yarnpkg.com/@modelcontextprotocol/sdk/-/sdk-1.10.2.tgz#50cdfbf0b6fbea23420388a7b00e64c13adabac8"
8 | integrity sha512-rb6AMp2DR4SN+kc6L1ta2NCpApyA9WYNx3CrTSZvGxq9wH71bRur+zRqPfg0vQ9mjywR7qZdX2RGHOPq3ss+tA==
9 | dependencies:
10 | content-type "^1.0.5"
11 | cors "^2.8.5"
12 | cross-spawn "^7.0.3"
13 | eventsource "^3.0.2"
14 | express "^5.0.1"
15 | express-rate-limit "^7.5.0"
16 | pkce-challenge "^5.0.0"
17 | raw-body "^3.0.0"
18 | zod "^3.23.8"
19 | zod-to-json-schema "^3.24.1"
20 |
21 | "@types/node-fetch@^2.6.4":
22 | version "2.6.12"
23 | resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.12.tgz#8ab5c3ef8330f13100a7479e2cd56d3386830a03"
24 | integrity sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==
25 | dependencies:
26 | "@types/node" "*"
27 | form-data "^4.0.0"
28 |
29 | "@types/node@*", "@types/node@^22.15.2":
30 | version "22.15.2"
31 | resolved "https://registry.yarnpkg.com/@types/node/-/node-22.15.2.tgz#1db55aa64618ee93a58c8912f74beefe44aca905"
32 | integrity sha512-uKXqKN9beGoMdBfcaTY1ecwz6ctxuJAcUlwE55938g0ZJ8lRxwAZqRz2AJ4pzpt5dHdTPMB863UZ0ESiFUcP7A==
33 | dependencies:
34 | undici-types "~6.21.0"
35 |
36 | "@types/node@^18.11.18":
37 | version "18.19.87"
38 | resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.87.tgz#690f000cc51e3c7f48bc00f7e86fac6eb550b709"
39 | integrity sha512-OIAAu6ypnVZHmsHCeJ+7CCSub38QNBS9uceMQeg7K5Ur0Jr+wG9wEOEvvMbhp09pxD5czIUy/jND7s7Tb6Nw7A==
40 | dependencies:
41 | undici-types "~5.26.4"
42 |
43 | abort-controller@^3.0.0:
44 | version "3.0.0"
45 | resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392"
46 | integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==
47 | dependencies:
48 | event-target-shim "^5.0.0"
49 |
50 | accepts@^2.0.0:
51 | version "2.0.0"
52 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-2.0.0.tgz#bbcf4ba5075467f3f2131eab3cffc73c2f5d7895"
53 | integrity sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==
54 | dependencies:
55 | mime-types "^3.0.0"
56 | negotiator "^1.0.0"
57 |
58 | agentkeepalive@^4.2.1:
59 | version "4.6.0"
60 | resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.6.0.tgz#35f73e94b3f40bf65f105219c623ad19c136ea6a"
61 | integrity sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==
62 | dependencies:
63 | humanize-ms "^1.2.1"
64 |
65 | asynckit@^0.4.0:
66 | version "0.4.0"
67 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
68 | integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
69 |
70 | body-parser@^2.2.0:
71 | version "2.2.0"
72 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-2.2.0.tgz#f7a9656de305249a715b549b7b8fd1ab9dfddcfa"
73 | integrity sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==
74 | dependencies:
75 | bytes "^3.1.2"
76 | content-type "^1.0.5"
77 | debug "^4.4.0"
78 | http-errors "^2.0.0"
79 | iconv-lite "^0.6.3"
80 | on-finished "^2.4.1"
81 | qs "^6.14.0"
82 | raw-body "^3.0.0"
83 | type-is "^2.0.0"
84 |
85 | bytes@3.1.2, bytes@^3.1.2:
86 | version "3.1.2"
87 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
88 | integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
89 |
90 | call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2:
91 | version "1.0.2"
92 | resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6"
93 | integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==
94 | dependencies:
95 | es-errors "^1.3.0"
96 | function-bind "^1.1.2"
97 |
98 | call-bound@^1.0.2:
99 | version "1.0.4"
100 | resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a"
101 | integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==
102 | dependencies:
103 | call-bind-apply-helpers "^1.0.2"
104 | get-intrinsic "^1.3.0"
105 |
106 | combined-stream@^1.0.8:
107 | version "1.0.8"
108 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
109 | integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
110 | dependencies:
111 | delayed-stream "~1.0.0"
112 |
113 | content-disposition@^1.0.0:
114 | version "1.0.0"
115 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-1.0.0.tgz#844426cb398f934caefcbb172200126bc7ceace2"
116 | integrity sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==
117 | dependencies:
118 | safe-buffer "5.2.1"
119 |
120 | content-type@^1.0.5:
121 | version "1.0.5"
122 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
123 | integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
124 |
125 | cookie-signature@^1.2.1:
126 | version "1.2.2"
127 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.2.2.tgz#57c7fc3cc293acab9fec54d73e15690ebe4a1793"
128 | integrity sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==
129 |
130 | cookie@^0.7.1:
131 | version "0.7.2"
132 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7"
133 | integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==
134 |
135 | cors@^2.8.5:
136 | version "2.8.5"
137 | resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
138 | integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
139 | dependencies:
140 | object-assign "^4"
141 | vary "^1"
142 |
143 | cross-spawn@^7.0.3:
144 | version "7.0.6"
145 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
146 | integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
147 | dependencies:
148 | path-key "^3.1.0"
149 | shebang-command "^2.0.0"
150 | which "^2.0.1"
151 |
152 | debug@^4.3.5, debug@^4.4.0:
153 | version "4.4.0"
154 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a"
155 | integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==
156 | dependencies:
157 | ms "^2.1.3"
158 |
159 | delayed-stream@~1.0.0:
160 | version "1.0.0"
161 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
162 | integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
163 |
164 | depd@2.0.0, depd@^2.0.0:
165 | version "2.0.0"
166 | resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
167 | integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
168 |
169 | dunder-proto@^1.0.1:
170 | version "1.0.1"
171 | resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a"
172 | integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==
173 | dependencies:
174 | call-bind-apply-helpers "^1.0.1"
175 | es-errors "^1.3.0"
176 | gopd "^1.2.0"
177 |
178 | ee-first@1.1.1:
179 | version "1.1.1"
180 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
181 | integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
182 |
183 | encodeurl@^2.0.0:
184 | version "2.0.0"
185 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58"
186 | integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==
187 |
188 | es-define-property@^1.0.1:
189 | version "1.0.1"
190 | resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa"
191 | integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==
192 |
193 | es-errors@^1.3.0:
194 | version "1.3.0"
195 | resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
196 | integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
197 |
198 | es-object-atoms@^1.0.0, es-object-atoms@^1.1.1:
199 | version "1.1.1"
200 | resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1"
201 | integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==
202 | dependencies:
203 | es-errors "^1.3.0"
204 |
205 | es-set-tostringtag@^2.1.0:
206 | version "2.1.0"
207 | resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d"
208 | integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==
209 | dependencies:
210 | es-errors "^1.3.0"
211 | get-intrinsic "^1.2.6"
212 | has-tostringtag "^1.0.2"
213 | hasown "^2.0.2"
214 |
215 | escape-html@^1.0.3:
216 | version "1.0.3"
217 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
218 | integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
219 |
220 | etag@^1.8.1:
221 | version "1.8.1"
222 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
223 | integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
224 |
225 | event-target-shim@^5.0.0:
226 | version "5.0.1"
227 | resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
228 | integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
229 |
230 | eventsource-parser@^3.0.1:
231 | version "3.0.1"
232 | resolved "https://registry.yarnpkg.com/eventsource-parser/-/eventsource-parser-3.0.1.tgz#5e358dba9a55ba64ca90da883c4ca35bd82467bd"
233 | integrity sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==
234 |
235 | eventsource@^3.0.2:
236 | version "3.0.6"
237 | resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-3.0.6.tgz#5c4b24cd70c0323eed2651a5ee07bd4bc391e656"
238 | integrity sha512-l19WpE2m9hSuyP06+FbuUUf1G+R0SFLrtQfbRb9PRr+oimOfxQhgGCbVaXg5IvZyyTThJsxh6L/srkMiCeBPDA==
239 | dependencies:
240 | eventsource-parser "^3.0.1"
241 |
242 | express-rate-limit@^7.5.0:
243 | version "7.5.0"
244 | resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-7.5.0.tgz#6a67990a724b4fbbc69119419feef50c51e8b28f"
245 | integrity sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==
246 |
247 | express@^5.0.1:
248 | version "5.1.0"
249 | resolved "https://registry.yarnpkg.com/express/-/express-5.1.0.tgz#d31beaf715a0016f0d53f47d3b4d7acf28c75cc9"
250 | integrity sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==
251 | dependencies:
252 | accepts "^2.0.0"
253 | body-parser "^2.2.0"
254 | content-disposition "^1.0.0"
255 | content-type "^1.0.5"
256 | cookie "^0.7.1"
257 | cookie-signature "^1.2.1"
258 | debug "^4.4.0"
259 | encodeurl "^2.0.0"
260 | escape-html "^1.0.3"
261 | etag "^1.8.1"
262 | finalhandler "^2.1.0"
263 | fresh "^2.0.0"
264 | http-errors "^2.0.0"
265 | merge-descriptors "^2.0.0"
266 | mime-types "^3.0.0"
267 | on-finished "^2.4.1"
268 | once "^1.4.0"
269 | parseurl "^1.3.3"
270 | proxy-addr "^2.0.7"
271 | qs "^6.14.0"
272 | range-parser "^1.2.1"
273 | router "^2.2.0"
274 | send "^1.1.0"
275 | serve-static "^2.2.0"
276 | statuses "^2.0.1"
277 | type-is "^2.0.1"
278 | vary "^1.1.2"
279 |
280 | finalhandler@^2.1.0:
281 | version "2.1.0"
282 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-2.1.0.tgz#72306373aa89d05a8242ed569ed86a1bff7c561f"
283 | integrity sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==
284 | dependencies:
285 | debug "^4.4.0"
286 | encodeurl "^2.0.0"
287 | escape-html "^1.0.3"
288 | on-finished "^2.4.1"
289 | parseurl "^1.3.3"
290 | statuses "^2.0.1"
291 |
292 | form-data-encoder@1.7.2:
293 | version "1.7.2"
294 | resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-1.7.2.tgz#1f1ae3dccf58ed4690b86d87e4f57c654fbab040"
295 | integrity sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==
296 |
297 | form-data@^4.0.0:
298 | version "4.0.2"
299 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.2.tgz#35cabbdd30c3ce73deb2c42d3c8d3ed9ca51794c"
300 | integrity sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==
301 | dependencies:
302 | asynckit "^0.4.0"
303 | combined-stream "^1.0.8"
304 | es-set-tostringtag "^2.1.0"
305 | mime-types "^2.1.12"
306 |
307 | formdata-node@^4.3.2:
308 | version "4.4.1"
309 | resolved "https://registry.yarnpkg.com/formdata-node/-/formdata-node-4.4.1.tgz#23f6a5cb9cb55315912cbec4ff7b0f59bbd191e2"
310 | integrity sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==
311 | dependencies:
312 | node-domexception "1.0.0"
313 | web-streams-polyfill "4.0.0-beta.3"
314 |
315 | forwarded@0.2.0:
316 | version "0.2.0"
317 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
318 | integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
319 |
320 | fresh@^2.0.0:
321 | version "2.0.0"
322 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-2.0.0.tgz#8dd7df6a1b3a1b3a5cf186c05a5dd267622635a4"
323 | integrity sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==
324 |
325 | function-bind@^1.1.2:
326 | version "1.1.2"
327 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
328 | integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
329 |
330 | get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.3.0:
331 | version "1.3.0"
332 | resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01"
333 | integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==
334 | dependencies:
335 | call-bind-apply-helpers "^1.0.2"
336 | es-define-property "^1.0.1"
337 | es-errors "^1.3.0"
338 | es-object-atoms "^1.1.1"
339 | function-bind "^1.1.2"
340 | get-proto "^1.0.1"
341 | gopd "^1.2.0"
342 | has-symbols "^1.1.0"
343 | hasown "^2.0.2"
344 | math-intrinsics "^1.1.0"
345 |
346 | get-proto@^1.0.1:
347 | version "1.0.1"
348 | resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1"
349 | integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==
350 | dependencies:
351 | dunder-proto "^1.0.1"
352 | es-object-atoms "^1.0.0"
353 |
354 | gopd@^1.2.0:
355 | version "1.2.0"
356 | resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1"
357 | integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==
358 |
359 | has-symbols@^1.0.3, has-symbols@^1.1.0:
360 | version "1.1.0"
361 | resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338"
362 | integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==
363 |
364 | has-tostringtag@^1.0.2:
365 | version "1.0.2"
366 | resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc"
367 | integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==
368 | dependencies:
369 | has-symbols "^1.0.3"
370 |
371 | hasown@^2.0.2:
372 | version "2.0.2"
373 | resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
374 | integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
375 | dependencies:
376 | function-bind "^1.1.2"
377 |
378 | http-errors@2.0.0, http-errors@^2.0.0:
379 | version "2.0.0"
380 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
381 | integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
382 | dependencies:
383 | depd "2.0.0"
384 | inherits "2.0.4"
385 | setprototypeof "1.2.0"
386 | statuses "2.0.1"
387 | toidentifier "1.0.1"
388 |
389 | humanize-ms@^1.2.1:
390 | version "1.2.1"
391 | resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed"
392 | integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==
393 | dependencies:
394 | ms "^2.0.0"
395 |
396 | iconv-lite@0.6.3, iconv-lite@^0.6.3:
397 | version "0.6.3"
398 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
399 | integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
400 | dependencies:
401 | safer-buffer ">= 2.1.2 < 3.0.0"
402 |
403 | inherits@2.0.4:
404 | version "2.0.4"
405 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
406 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
407 |
408 | ipaddr.js@1.9.1:
409 | version "1.9.1"
410 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
411 | integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
412 |
413 | is-promise@^4.0.0:
414 | version "4.0.0"
415 | resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-4.0.0.tgz#42ff9f84206c1991d26debf520dd5c01042dd2f3"
416 | integrity sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==
417 |
418 | isexe@^2.0.0:
419 | version "2.0.0"
420 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
421 | integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
422 |
423 | math-intrinsics@^1.1.0:
424 | version "1.1.0"
425 | resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9"
426 | integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==
427 |
428 | media-typer@^1.1.0:
429 | version "1.1.0"
430 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-1.1.0.tgz#6ab74b8f2d3320f2064b2a87a38e7931ff3a5561"
431 | integrity sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==
432 |
433 | merge-descriptors@^2.0.0:
434 | version "2.0.0"
435 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-2.0.0.tgz#ea922f660635a2249ee565e0449f951e6b603808"
436 | integrity sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==
437 |
438 | mime-db@1.52.0:
439 | version "1.52.0"
440 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
441 | integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
442 |
443 | mime-db@^1.54.0:
444 | version "1.54.0"
445 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5"
446 | integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==
447 |
448 | mime-types@^2.1.12:
449 | version "2.1.35"
450 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
451 | integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
452 | dependencies:
453 | mime-db "1.52.0"
454 |
455 | mime-types@^3.0.0, mime-types@^3.0.1:
456 | version "3.0.1"
457 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-3.0.1.tgz#b1d94d6997a9b32fd69ebaed0db73de8acb519ce"
458 | integrity sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==
459 | dependencies:
460 | mime-db "^1.54.0"
461 |
462 | ms@^2.0.0, ms@^2.1.3:
463 | version "2.1.3"
464 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
465 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
466 |
467 | negotiator@^1.0.0:
468 | version "1.0.0"
469 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a"
470 | integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==
471 |
472 | node-domexception@1.0.0:
473 | version "1.0.0"
474 | resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5"
475 | integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==
476 |
477 | node-fetch@^2.6.7:
478 | version "2.7.0"
479 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
480 | integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
481 | dependencies:
482 | whatwg-url "^5.0.0"
483 |
484 | object-assign@^4:
485 | version "4.1.1"
486 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
487 | integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
488 |
489 | object-inspect@^1.13.3:
490 | version "1.13.4"
491 | resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213"
492 | integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==
493 |
494 | on-finished@^2.4.1:
495 | version "2.4.1"
496 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
497 | integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
498 | dependencies:
499 | ee-first "1.1.1"
500 |
501 | once@^1.4.0:
502 | version "1.4.0"
503 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
504 | integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
505 | dependencies:
506 | wrappy "1"
507 |
508 | openai@^4.96.0:
509 | version "4.96.0"
510 | resolved "https://registry.yarnpkg.com/openai/-/openai-4.96.0.tgz#d1a821e99949ac2c55709f4e28e18bb1d9fd8ef9"
511 | integrity sha512-dKoW56i02Prv2XQolJ9Rl9Svqubqkzg3QpwEOBuSVZLk05Shelu7s+ErRTwFc1Bs3JZ2qBqBfVpXQiJhwOGG8A==
512 | dependencies:
513 | "@types/node" "^18.11.18"
514 | "@types/node-fetch" "^2.6.4"
515 | abort-controller "^3.0.0"
516 | agentkeepalive "^4.2.1"
517 | form-data-encoder "1.7.2"
518 | formdata-node "^4.3.2"
519 | node-fetch "^2.6.7"
520 |
521 | parseurl@^1.3.3:
522 | version "1.3.3"
523 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
524 | integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
525 |
526 | path-key@^3.1.0:
527 | version "3.1.1"
528 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
529 | integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
530 |
531 | path-to-regexp@^8.0.0:
532 | version "8.2.0"
533 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-8.2.0.tgz#73990cc29e57a3ff2a0d914095156df5db79e8b4"
534 | integrity sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==
535 |
536 | pkce-challenge@^5.0.0:
537 | version "5.0.0"
538 | resolved "https://registry.yarnpkg.com/pkce-challenge/-/pkce-challenge-5.0.0.tgz#c3a405cb49e272094a38e890a2b51da0228c4d97"
539 | integrity sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==
540 |
541 | proxy-addr@^2.0.7:
542 | version "2.0.7"
543 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
544 | integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
545 | dependencies:
546 | forwarded "0.2.0"
547 | ipaddr.js "1.9.1"
548 |
549 | qs@^6.14.0:
550 | version "6.14.0"
551 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.0.tgz#c63fa40680d2c5c941412a0e899c89af60c0a930"
552 | integrity sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==
553 | dependencies:
554 | side-channel "^1.1.0"
555 |
556 | range-parser@^1.2.1:
557 | version "1.2.1"
558 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
559 | integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
560 |
561 | raw-body@^3.0.0:
562 | version "3.0.0"
563 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-3.0.0.tgz#25b3476f07a51600619dae3fe82ddc28a36e5e0f"
564 | integrity sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==
565 | dependencies:
566 | bytes "3.1.2"
567 | http-errors "2.0.0"
568 | iconv-lite "0.6.3"
569 | unpipe "1.0.0"
570 |
571 | router@^2.2.0:
572 | version "2.2.0"
573 | resolved "https://registry.yarnpkg.com/router/-/router-2.2.0.tgz#019be620b711c87641167cc79b99090f00b146ef"
574 | integrity sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==
575 | dependencies:
576 | debug "^4.4.0"
577 | depd "^2.0.0"
578 | is-promise "^4.0.0"
579 | parseurl "^1.3.3"
580 | path-to-regexp "^8.0.0"
581 |
582 | safe-buffer@5.2.1:
583 | version "5.2.1"
584 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
585 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
586 |
587 | "safer-buffer@>= 2.1.2 < 3.0.0":
588 | version "2.1.2"
589 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
590 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
591 |
592 | send@^1.1.0, send@^1.2.0:
593 | version "1.2.0"
594 | resolved "https://registry.yarnpkg.com/send/-/send-1.2.0.tgz#32a7554fb777b831dfa828370f773a3808d37212"
595 | integrity sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==
596 | dependencies:
597 | debug "^4.3.5"
598 | encodeurl "^2.0.0"
599 | escape-html "^1.0.3"
600 | etag "^1.8.1"
601 | fresh "^2.0.0"
602 | http-errors "^2.0.0"
603 | mime-types "^3.0.1"
604 | ms "^2.1.3"
605 | on-finished "^2.4.1"
606 | range-parser "^1.2.1"
607 | statuses "^2.0.1"
608 |
609 | serve-static@^2.2.0:
610 | version "2.2.0"
611 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-2.2.0.tgz#9c02564ee259bdd2251b82d659a2e7e1938d66f9"
612 | integrity sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==
613 | dependencies:
614 | encodeurl "^2.0.0"
615 | escape-html "^1.0.3"
616 | parseurl "^1.3.3"
617 | send "^1.2.0"
618 |
619 | setprototypeof@1.2.0:
620 | version "1.2.0"
621 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
622 | integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
623 |
624 | shebang-command@^2.0.0:
625 | version "2.0.0"
626 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
627 | integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
628 | dependencies:
629 | shebang-regex "^3.0.0"
630 |
631 | shebang-regex@^3.0.0:
632 | version "3.0.0"
633 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
634 | integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
635 |
636 | side-channel-list@^1.0.0:
637 | version "1.0.0"
638 | resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad"
639 | integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==
640 | dependencies:
641 | es-errors "^1.3.0"
642 | object-inspect "^1.13.3"
643 |
644 | side-channel-map@^1.0.1:
645 | version "1.0.1"
646 | resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42"
647 | integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==
648 | dependencies:
649 | call-bound "^1.0.2"
650 | es-errors "^1.3.0"
651 | get-intrinsic "^1.2.5"
652 | object-inspect "^1.13.3"
653 |
654 | side-channel-weakmap@^1.0.2:
655 | version "1.0.2"
656 | resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea"
657 | integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==
658 | dependencies:
659 | call-bound "^1.0.2"
660 | es-errors "^1.3.0"
661 | get-intrinsic "^1.2.5"
662 | object-inspect "^1.13.3"
663 | side-channel-map "^1.0.1"
664 |
665 | side-channel@^1.1.0:
666 | version "1.1.0"
667 | resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9"
668 | integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==
669 | dependencies:
670 | es-errors "^1.3.0"
671 | object-inspect "^1.13.3"
672 | side-channel-list "^1.0.0"
673 | side-channel-map "^1.0.1"
674 | side-channel-weakmap "^1.0.2"
675 |
676 | statuses@2.0.1, statuses@^2.0.1:
677 | version "2.0.1"
678 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
679 | integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
680 |
681 | toidentifier@1.0.1:
682 | version "1.0.1"
683 | resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
684 | integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
685 |
686 | tr46@~0.0.3:
687 | version "0.0.3"
688 | resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
689 | integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
690 |
691 | type-is@^2.0.0, type-is@^2.0.1:
692 | version "2.0.1"
693 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-2.0.1.tgz#64f6cf03f92fce4015c2b224793f6bdd4b068c97"
694 | integrity sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==
695 | dependencies:
696 | content-type "^1.0.5"
697 | media-typer "^1.1.0"
698 | mime-types "^3.0.0"
699 |
700 | typescript@^5.8.3:
701 | version "5.8.3"
702 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e"
703 | integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==
704 |
705 | undici-types@~5.26.4:
706 | version "5.26.5"
707 | resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
708 | integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
709 |
710 | undici-types@~6.21.0:
711 | version "6.21.0"
712 | resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb"
713 | integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==
714 |
715 | unpipe@1.0.0:
716 | version "1.0.0"
717 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
718 | integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
719 |
720 | vary@^1, vary@^1.1.2:
721 | version "1.1.2"
722 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
723 | integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
724 |
725 | web-streams-polyfill@4.0.0-beta.3:
726 | version "4.0.0-beta.3"
727 | resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz#2898486b74f5156095e473efe989dcf185047a38"
728 | integrity sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==
729 |
730 | webidl-conversions@^3.0.0:
731 | version "3.0.1"
732 | resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
733 | integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
734 |
735 | whatwg-url@^5.0.0:
736 | version "5.0.0"
737 | resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
738 | integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
739 | dependencies:
740 | tr46 "~0.0.3"
741 | webidl-conversions "^3.0.0"
742 |
743 | which@^2.0.1:
744 | version "2.0.2"
745 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
746 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
747 | dependencies:
748 | isexe "^2.0.0"
749 |
750 | wrappy@1:
751 | version "1.0.2"
752 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
753 | integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
754 |
755 | zod-to-json-schema@^3.24.1:
756 | version "3.24.5"
757 | resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz#d1095440b147fb7c2093812a53c54df8d5df50a3"
758 | integrity sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==
759 |
760 | zod@^3.23.8:
761 | version "3.24.3"
762 | resolved "https://registry.yarnpkg.com/zod/-/zod-3.24.3.tgz#1f40f750a05e477396da64438e0e1c0995dafd87"
763 | integrity sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==
764 |
--------------------------------------------------------------------------------