From 0e0b5c897e81ed97657c9631850f2dd94791ac63 Mon Sep 17 00:00:00 2001 From: Rudolf Raevskiy Date: Thu, 20 Mar 2025 14:09:01 +0100 Subject: [PATCH 1/2] Fixed types for create_merge_request and get_merge_request tools. --- schemas.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/schemas.ts b/schemas.ts index 19a7904..063a6bd 100644 --- a/schemas.ts +++ b/schemas.ts @@ -332,7 +332,7 @@ export const GitLabMergeRequestSchema = z.object({ assignees: z.array(GitLabUserSchema).optional(), source_branch: z.string(), target_branch: z.string(), - diff_refs: GitLabMergeRequestDiffRefSchema.optional(), + diff_refs: GitLabMergeRequestDiffRefSchema.nullable().optional(), web_url: z.string(), created_at: z.string(), updated_at: z.string(), @@ -345,10 +345,10 @@ export const GitLabMergeRequestSchema = z.object({ work_in_progress: z.boolean().optional(), blocking_discussions_resolved: z.boolean().optional(), should_remove_source_branch: z.boolean().nullable().optional(), - force_remove_source_branch: z.boolean().optional(), + force_remove_source_branch: z.boolean().nullable().optional(), allow_collaboration: z.boolean().optional(), allow_maintainer_to_push: z.boolean().optional(), - changes_count: z.string().optional(), + changes_count: z.string().nullable().optional(), merge_when_pipeline_succeeds: z.boolean().optional(), squash: z.boolean().optional(), labels: z.array(z.string()).optional(), From 5d1040141d20169420e63e67c438a9a942d157d6 Mon Sep 17 00:00:00 2001 From: Rudolf Raevskiy Date: Thu, 20 Mar 2025 14:25:52 +0100 Subject: [PATCH 2/2] Build upd. --- build/index.js | 205 +++++++++++++++++++++++++++--- build/schemas.js | 47 ++++++- build/test-note.js | 54 ++++++++ package-lock.json | 311 +++++---------------------------------------- 4 files changed, 313 insertions(+), 304 deletions(-) create mode 100644 build/test-note.js diff --git a/build/index.js b/build/index.js index 1e9961a..60cf960 100755 --- a/build/index.js +++ b/build/index.js @@ -9,7 +9,7 @@ import { fileURLToPath } from "url"; import { dirname } from "path"; import fs from "fs"; import path from "path"; -import { GitLabForkSchema, GitLabReferenceSchema, GitLabRepositorySchema, GitLabIssueSchema, GitLabMergeRequestSchema, GitLabContentSchema, GitLabCreateUpdateFileResponseSchema, GitLabSearchResponseSchema, GitLabTreeSchema, GitLabCommitSchema, GitLabNamespaceSchema, GitLabNamespaceExistsResponseSchema, GitLabProjectSchema, CreateOrUpdateFileSchema, SearchRepositoriesSchema, CreateRepositorySchema, GetFileContentsSchema, PushFilesSchema, CreateIssueSchema, CreateMergeRequestSchema, ForkRepositorySchema, CreateBranchSchema, GitLabMergeRequestDiffSchema, GetMergeRequestSchema, GetMergeRequestDiffsSchema, UpdateMergeRequestSchema, ListIssuesSchema, GetIssueSchema, UpdateIssueSchema, DeleteIssueSchema, GitLabIssueLinkSchema, GitLabIssueWithLinkDetailsSchema, ListIssueLinksSchema, GetIssueLinkSchema, CreateIssueLinkSchema, DeleteIssueLinkSchema, ListNamespacesSchema, GetNamespaceSchema, VerifyNamespaceSchema, GetProjectSchema, ListProjectsSchema, CreateNoteSchema, } from "./schemas.js"; +import { GitLabForkSchema, GitLabReferenceSchema, GitLabRepositorySchema, GitLabIssueSchema, GitLabMergeRequestSchema, GitLabContentSchema, GitLabCreateUpdateFileResponseSchema, GitLabSearchResponseSchema, GitLabTreeSchema, GitLabCommitSchema, GitLabNamespaceSchema, GitLabNamespaceExistsResponseSchema, GitLabProjectSchema, CreateOrUpdateFileSchema, SearchRepositoriesSchema, CreateRepositorySchema, GetFileContentsSchema, PushFilesSchema, CreateIssueSchema, CreateMergeRequestSchema, ForkRepositorySchema, CreateBranchSchema, GitLabMergeRequestDiffSchema, GetMergeRequestSchema, GetMergeRequestDiffsSchema, UpdateMergeRequestSchema, ListIssuesSchema, GetIssueSchema, UpdateIssueSchema, DeleteIssueSchema, GitLabIssueLinkSchema, GitLabIssueWithLinkDetailsSchema, ListIssueLinksSchema, GetIssueLinkSchema, CreateIssueLinkSchema, DeleteIssueLinkSchema, ListNamespacesSchema, GetNamespaceSchema, VerifyNamespaceSchema, GetProjectSchema, ListProjectsSchema, ListLabelsSchema, GetLabelSchema, CreateLabelSchema, UpdateLabelSchema, DeleteLabelSchema, CreateNoteSchema, } from "./schemas.js"; /** * Read version from package.json */ @@ -826,19 +826,139 @@ async function getProject(projectId, options = {}) { * @returns {Promise} List of projects */ async function listProjects(options = {}) { - const url = new URL(`${GITLAB_API_URL}/projects`); - // Add all the query parameters from options + // Construct the query parameters + const params = new URLSearchParams(); + for (const [key, value] of Object.entries(options)) { + if (value !== undefined && value !== null) { + if (typeof value === "boolean") { + params.append(key, value ? "true" : "false"); + } + else { + params.append(key, String(value)); + } + } + } + // Make the API request + const response = await fetch(`${GITLAB_API_URL}/projects?${params.toString()}`, { + method: "GET", + headers: DEFAULT_HEADERS, + }); + // Handle errors + await handleGitLabError(response); + // Parse and return the data + const data = await response.json(); + return z.array(GitLabProjectSchema).parse(data); +} +/** + * List labels for a project + * + * @param projectId The ID or URL-encoded path of the project + * @param options Optional parameters for listing labels + * @returns Array of GitLab labels + */ +async function listLabels(projectId, options = {}) { + // Construct the URL with project path + const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels`); + // Add query parameters Object.entries(options).forEach(([key, value]) => { if (value !== undefined) { - url.searchParams.append(key, value.toString()); + if (typeof value === "boolean") { + url.searchParams.append(key, value ? "true" : "false"); + } + else { + url.searchParams.append(key, String(value)); + } } }); + // Make the API request const response = await fetch(url.toString(), { headers: DEFAULT_HEADERS, }); + // Handle errors await handleGitLabError(response); + // Parse and return the data const data = await response.json(); - return z.array(GitLabRepositorySchema).parse(data); + return data; +} +/** + * Get a single label from a project + * + * @param projectId The ID or URL-encoded path of the project + * @param labelId The ID or name of the label + * @param includeAncestorGroups Whether to include ancestor groups + * @returns GitLab label + */ +async function getLabel(projectId, labelId, includeAncestorGroups) { + const url = new URL(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels/${encodeURIComponent(String(labelId))}`); + // Add query parameters + if (includeAncestorGroups !== undefined) { + url.searchParams.append("include_ancestor_groups", includeAncestorGroups ? "true" : "false"); + } + // Make the API request + const response = await fetch(url.toString(), { + headers: DEFAULT_HEADERS, + }); + // Handle errors + await handleGitLabError(response); + // Parse and return the data + const data = await response.json(); + return data; +} +/** + * Create a new label in a project + * + * @param projectId The ID or URL-encoded path of the project + * @param options Options for creating the label + * @returns Created GitLab label + */ +async function createLabel(projectId, options) { + // Make the API request + const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels`, { + method: "POST", + headers: DEFAULT_HEADERS, + body: JSON.stringify(options), + }); + // Handle errors + await handleGitLabError(response); + // Parse and return the data + const data = await response.json(); + return data; +} +/** + * Update an existing label in a project + * + * @param projectId The ID or URL-encoded path of the project + * @param labelId The ID or name of the label to update + * @param options Options for updating the label + * @returns Updated GitLab label + */ +async function updateLabel(projectId, labelId, options) { + // Make the API request + const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels/${encodeURIComponent(String(labelId))}`, { + method: "PUT", + headers: DEFAULT_HEADERS, + body: JSON.stringify(options), + }); + // Handle errors + await handleGitLabError(response); + // Parse and return the data + const data = await response.json(); + return data; +} +/** + * Delete a label from a project + * + * @param projectId The ID or URL-encoded path of the project + * @param labelId The ID or name of the label to delete + */ +async function deleteLabel(projectId, labelId) { + // Make the API request + const response = await fetch(`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/labels/${encodeURIComponent(String(labelId))}`, { + method: "DELETE", + headers: DEFAULT_HEADERS, + }); + // Handle errors + await handleGitLabError(response); } server.setRequestHandler(ListToolsRequestSchema, async () => { return { @@ -973,6 +1093,31 @@ server.setRequestHandler(ListToolsRequestSchema, async () => { description: "List projects accessible by the current user", inputSchema: zodToJsonSchema(ListProjectsSchema), }, + { + name: "list_labels", + description: "List labels for a project", + inputSchema: zodToJsonSchema(ListLabelsSchema), + }, + { + name: "get_label", + description: "Get a single label from a project", + inputSchema: zodToJsonSchema(GetLabelSchema), + }, + { + name: "create_label", + description: "Create a new label in a project", + inputSchema: zodToJsonSchema(CreateLabelSchema), + }, + { + name: "update_label", + description: "Update an existing label in a project", + inputSchema: zodToJsonSchema(UpdateLabelSchema), + }, + { + name: "delete_label", + description: "Delete a label from a project", + inputSchema: zodToJsonSchema(DeleteLabelSchema), + }, ], }; }); @@ -1162,19 +1307,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { } case "list_projects": { const args = ListProjectsSchema.parse(request.params.arguments); - const url = new URL(`${GITLAB_API_URL}/projects`); - // Add query parameters for filtering - Object.entries(args).forEach(([key, value]) => { - if (value !== undefined) { - url.searchParams.append(key, value.toString()); - } - }); - const response = await fetch(url.toString(), { - headers: DEFAULT_HEADERS, - }); - await handleGitLabError(response); - const data = await response.json(); - const projects = z.array(GitLabProjectSchema).parse(data); + const projects = await listProjects(args); return { content: [{ type: "text", text: JSON.stringify(projects, null, 2) }], }; @@ -1245,6 +1378,42 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { content: [{ type: "text", text: JSON.stringify({ status: "success", message: "Issue link deleted successfully" }, null, 2) }], }; } + case "list_labels": { + const args = ListLabelsSchema.parse(request.params.arguments); + const labels = await listLabels(args.project_id, args); + return { + content: [{ type: "text", text: JSON.stringify(labels, null, 2) }], + }; + } + case "get_label": { + const args = GetLabelSchema.parse(request.params.arguments); + const label = await getLabel(args.project_id, args.label_id, args.include_ancestor_groups); + return { + content: [{ type: "text", text: JSON.stringify(label, null, 2) }], + }; + } + case "create_label": { + const args = CreateLabelSchema.parse(request.params.arguments); + const label = await createLabel(args.project_id, args); + return { + content: [{ type: "text", text: JSON.stringify(label, null, 2) }], + }; + } + case "update_label": { + const args = UpdateLabelSchema.parse(request.params.arguments); + const { project_id, label_id, ...options } = args; + const label = await updateLabel(project_id, label_id, options); + return { + content: [{ type: "text", text: JSON.stringify(label, null, 2) }], + }; + } + case "delete_label": { + const args = DeleteLabelSchema.parse(request.params.arguments); + await deleteLabel(args.project_id, args.label_id); + return { + content: [{ type: "text", text: JSON.stringify({ status: "success", message: "Label deleted successfully" }, null, 2) }], + }; + } default: throw new Error(`Unknown tool: ${request.params.name}`); } diff --git a/build/schemas.js b/build/schemas.js index 7c061fc..9db4c94 100644 --- a/build/schemas.js +++ b/build/schemas.js @@ -207,7 +207,15 @@ export const GitLabLabelSchema = z.object({ id: z.number(), name: z.string(), color: z.string(), - description: z.string().optional(), + text_color: z.string(), + description: z.string().nullable(), + description_html: z.string().nullable(), + open_issues_count: z.number().optional(), + closed_issues_count: z.number().optional(), + open_merge_requests_count: z.number().optional(), + subscribed: z.boolean().optional(), + priority: z.number().nullable().optional(), + is_project_label: z.boolean().optional(), }); export const GitLabUserSchema = z.object({ username: z.string(), // Changed from login to match GitLab API @@ -295,7 +303,7 @@ export const GitLabMergeRequestSchema = z.object({ assignees: z.array(GitLabUserSchema).optional(), source_branch: z.string(), target_branch: z.string(), - diff_refs: GitLabMergeRequestDiffRefSchema.optional(), + diff_refs: GitLabMergeRequestDiffRefSchema.nullable().optional(), web_url: z.string(), created_at: z.string(), updated_at: z.string(), @@ -308,10 +316,10 @@ export const GitLabMergeRequestSchema = z.object({ work_in_progress: z.boolean().optional(), blocking_discussions_resolved: z.boolean().optional(), should_remove_source_branch: z.boolean().nullable().optional(), - force_remove_source_branch: z.boolean().optional(), + force_remove_source_branch: z.boolean().nullable().optional(), allow_collaboration: z.boolean().optional(), allow_maintainer_to_push: z.boolean().optional(), - changes_count: z.string().optional(), + changes_count: z.string().nullable().optional(), merge_when_pipeline_succeeds: z.boolean().optional(), squash: z.boolean().optional(), labels: z.array(z.string()).optional(), @@ -558,3 +566,34 @@ export const ListProjectsSchema = z.object({ with_merge_requests_enabled: z.boolean().optional().describe("Filter projects with merge requests feature enabled"), min_access_level: z.number().optional().describe("Filter by minimum access level"), }); +// Label operation schemas +export const ListLabelsSchema = z.object({ + project_id: z.string().describe("Project ID or URL-encoded path"), + with_counts: z.boolean().optional().describe("Whether or not to include issue and merge request counts"), + include_ancestor_groups: z.boolean().optional().describe("Include ancestor groups"), + search: z.string().optional().describe("Keyword to filter labels by"), +}); +export const GetLabelSchema = z.object({ + project_id: z.string().describe("Project ID or URL-encoded path"), + label_id: z.union([z.number(), z.string()]).describe("The ID or title of a project's label"), + include_ancestor_groups: z.boolean().optional().describe("Include ancestor groups"), +}); +export const CreateLabelSchema = z.object({ + project_id: z.string().describe("Project ID or URL-encoded path"), + name: z.string().describe("The name of the label"), + color: z.string().describe("The color of the label given in 6-digit hex notation with leading '#' sign"), + description: z.string().optional().describe("The description of the label"), + priority: z.number().nullable().optional().describe("The priority of the label"), +}); +export const UpdateLabelSchema = z.object({ + project_id: z.string().describe("Project ID or URL-encoded path"), + label_id: z.union([z.number(), z.string()]).describe("The ID or title of a project's label"), + new_name: z.string().optional().describe("The new name of the label"), + color: z.string().optional().describe("The color of the label given in 6-digit hex notation with leading '#' sign"), + description: z.string().optional().describe("The new description of the label"), + priority: z.number().nullable().optional().describe("The new priority of the label"), +}); +export const DeleteLabelSchema = z.object({ + project_id: z.string().describe("Project ID or URL-encoded path"), + label_id: z.union([z.number(), z.string()]).describe("The ID or title of a project's label"), +}); diff --git a/build/test-note.js b/build/test-note.js new file mode 100644 index 0000000..a66909f --- /dev/null +++ b/build/test-note.js @@ -0,0 +1,54 @@ +/** + * This test file verifies that the createNote function works correctly + * with the fixed endpoint URL construction that uses plural resource names + * (issues instead of issue, merge_requests instead of merge_request). + */ +import fetch from "node-fetch"; +// GitLab API configuration (replace with actual values when testing) +const GITLAB_API_URL = process.env.GITLAB_API_URL || "https://gitlab.com"; +const GITLAB_PERSONAL_ACCESS_TOKEN = process.env.GITLAB_TOKEN || ""; +const PROJECT_ID = process.env.PROJECT_ID || "your/project"; +const ISSUE_IID = Number(process.env.ISSUE_IID || "1"); +async function testCreateIssueNote() { + try { + // Using plural form "issues" in the URL + const url = new URL(`${GITLAB_API_URL}/api/v4/projects/${encodeURIComponent(PROJECT_ID)}/issues/${ISSUE_IID}/notes`); + const response = await fetch(url.toString(), { + method: "POST", + headers: { + Accept: "application/json", + "Content-Type": "application/json", + Authorization: `Bearer ${GITLAB_PERSONAL_ACCESS_TOKEN}`, + }, + body: JSON.stringify({ body: "Test note from API - with plural endpoint" }), + }); + if (!response.ok) { + const errorBody = await response.text(); + throw new Error(`GitLab API error: ${response.status} ${response.statusText}\n${errorBody}`); + } + const data = await response.json(); + console.log("Successfully created note:"); + console.log(JSON.stringify(data, null, 2)); + return true; + } + catch (error) { + console.error("Error creating note:", error); + return false; + } +} +// Only run the test if executed directly +if (require.main === module) { + console.log("Testing note creation with plural 'issues' endpoint..."); + testCreateIssueNote().then(success => { + if (success) { + console.log("✅ Test successful!"); + process.exit(0); + } + else { + console.log("❌ Test failed!"); + process.exit(1); + } + }); +} +// Export for use in other tests +export { testCreateIssueNote }; diff --git a/package-lock.json b/package-lock.json index f743abd..039c4c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,26 +1,29 @@ { - "name": "@modelcontextprotocol/server-gitlab", - "version": "0.6.2", + "name": "@zereight/mcp-gitlab", + "version": "1.0.20", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "@modelcontextprotocol/server-gitlab", - "version": "0.6.2", + "name": "@zereight/mcp-gitlab", + "version": "1.0.20", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "1.0.1", "@types/node-fetch": "^2.6.12", - "dotenv": "^16.4.7", "node-fetch": "^3.3.2", "zod-to-json-schema": "^3.23.5" }, "bin": { - "mcp-server-gitlab": "build/index.js" + "mcp-gitlab": "build/index.js" }, "devDependencies": { - "shx": "^0.3.4", - "typescript": "^5.6.2" + "@types/node": "^22.13.10", + "typescript": "^5.8.2", + "zod": "3.21.4" + }, + "engines": { + "node": ">=14" } }, "node_modules/@modelcontextprotocol/sdk": { @@ -34,10 +37,19 @@ "zod": "^3.23.8" } }, + "node_modules/@modelcontextprotocol/sdk/node_modules/zod": { + "version": "3.24.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", + "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/@types/node": { - "version": "22.13.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.1.tgz", - "integrity": "sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==", + "version": "22.13.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz", + "integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==", "license": "MIT", "dependencies": { "undici-types": "~6.20.0" @@ -59,24 +71,6 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -98,13 +92,6 @@ "node": ">= 0.8" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, "node_modules/content-type": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", @@ -141,18 +128,6 @@ "node": ">= 0.8" } }, - "node_modules/dotenv": { - "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, "node_modules/fetch-blob": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", @@ -202,58 +177,6 @@ "node": ">=12.20.0" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -282,50 +205,12 @@ "node": ">=0.10.0" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -347,29 +232,6 @@ "node": ">= 0.6" } }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -407,33 +269,6 @@ "url": "https://opencollective.com/node-fetch" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, "node_modules/raw-body": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", @@ -449,39 +284,6 @@ "node": ">= 0.8" } }, - "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", - "dev": true, - "dependencies": { - "resolve": "^1.1.6" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -494,41 +296,6 @@ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, - "node_modules/shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - }, - "bin": { - "shjs": "bin/shjs" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/shx": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", - "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.3", - "shelljs": "^0.8.5" - }, - "bin": { - "shx": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -538,19 +305,6 @@ "node": ">= 0.8" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -561,9 +315,9 @@ } }, "node_modules/typescript": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -598,17 +352,10 @@ "node": ">= 8" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, "node_modules/zod": { - "version": "3.24.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", - "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", + "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks"