From 361b9c3818d4ab89d5b089ee6ff545f105817b09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diego=20Garc=C3=ADa?= Date: Wed, 11 Jun 2025 15:24:20 +0200 Subject: [PATCH 1/4] feat: first setup --- .dockerignore | 14 + .gitignore | 2 + .prettierrc.js | 10 + DOCKER.md | 30 + Dockerfile | 39 + README.md | 66 + eslint.config.mjs | 37 + package-lock.json | 6793 +++++++++++++++++ package.json | 45 + src/clients/postman.ts | 49 + src/index.ts | 335 + src/servers/express.ts | 137 + src/tools/create_collection.ts | 5092 ++++++++++++ src/tools/create_collection_comment.ts | 71 + src/tools/create_collection_folder.ts | 55 + src/tools/create_collection_fork.ts | 50 + src/tools/create_collection_request.ts | 67 + src/tools/create_collection_response.ts | 55 + src/tools/create_environment.ts | 64 + src/tools/create_folder_comment.ts | 72 + src/tools/create_mock.ts | 64 + src/tools/create_monitor.ts | 165 + src/tools/create_request_comment.ts | 76 + src/tools/create_response_comment.ts | 72 + src/tools/create_spec.ts | 62 + src/tools/create_update_spec_file.ts | 47 + src/tools/create_workspace.ts | 58 + src/tools/delete_api_collection_comment.ts | 45 + src/tools/delete_collection.ts | 39 + src/tools/delete_collection_comment.ts | 44 + src/tools/delete_collection_folder.ts | 42 + src/tools/delete_collection_request.ts | 42 + src/tools/delete_collection_response.ts | 42 + src/tools/delete_environment.ts | 39 + src/tools/delete_folder_comment.ts | 45 + src/tools/delete_mock.ts | 39 + src/tools/delete_monitor.ts | 39 + src/tools/delete_pan_element_or_folder.ts | 48 + src/tools/delete_request_comment.ts | 45 + src/tools/delete_response_comment.ts | 45 + src/tools/delete_spec.ts | 41 + src/tools/delete_workspace.ts | 41 + src/tools/generate_collection.ts | 105 + src/tools/generate_spec_from_collection.ts | 53 + src/tools/get_all_elements_and_folders.ts | 133 + src/tools/get_all_pan_add_element_requests.ts | 106 + src/tools/get_all_specs.ts | 55 + src/tools/get_async_spec_task_status.ts | 43 + src/tools/get_authenticated_user.ts | 41 + src/tools/get_collection.ts | 57 + src/tools/get_collection_comments.ts | 41 + src/tools/get_collection_folder.ts | 54 + src/tools/get_collection_forks.ts | 63 + src/tools/get_collection_request.ts | 54 + src/tools/get_collection_response.ts | 54 + src/tools/get_collection_tags.ts | 41 + src/tools/get_collection_updates_tasks.ts | 39 + src/tools/get_collections.ts | 58 + src/tools/get_collections_forked_by_user.ts | 60 + src/tools/get_environment.ts | 39 + src/tools/get_environments.ts | 44 + src/tools/get_folder_comments.ts | 42 + src/tools/get_generated_collection_specs.ts | 42 + src/tools/get_mock.ts | 39 + src/tools/get_mocks.ts | 46 + src/tools/get_monitor.ts | 39 + src/tools/get_monitors.ts | 72 + src/tools/get_request_comments.ts | 46 + src/tools/get_response_comments.ts | 42 + src/tools/get_source_collection_status.ts | 41 + src/tools/get_spec.ts | 39 + src/tools/get_spec_collections.ts | 55 + src/tools/get_spec_definition.ts | 41 + src/tools/get_status_of_an_async_task.ts | 45 + src/tools/get_tagged_entities.ts | 74 + src/tools/get_workspace.ts | 50 + src/tools/get_workspace_global_variables.ts | 41 + src/tools/get_workspace_tags.ts | 39 + src/tools/get_workspaces.ts | 62 + src/tools/patch_collection.ts | 577 ++ src/tools/patch_environment.ts | 41 + src/tools/post_pan_element_or_folder.ts | 41 + src/tools/publish_documentation.ts | 148 + src/tools/publish_mock.ts | 41 + src/tools/pull_collection_changes.ts | 41 + src/tools/put_collection.ts | 5103 +++++++++++++ src/tools/put_environment.ts | 63 + src/tools/resolve_comment_thread.ts | 43 + src/tools/run_monitor.ts | 50 + src/tools/sync_collection_with_spec.ts | 45 + src/tools/sync_spec_with_collection.ts | 46 + src/tools/transfer_collection_folders.ts | 83 + src/tools/transfer_collection_requests.ts | 83 + src/tools/transfer_collection_responses.ts | 83 + src/tools/unpublish_documentation.ts | 43 + src/tools/unpublish_mock.ts | 41 + src/tools/update_api_collection_comment.ts | 65 + src/tools/update_collection_comment.ts | 64 + src/tools/update_collection_folder.ts | 51 + src/tools/update_collection_request.ts | 70 + src/tools/update_collection_response.ts | 57 + src/tools/update_collection_tags.ts | 63 + src/tools/update_folder_comment.ts | 65 + src/tools/update_mock.ts | 71 + src/tools/update_monitor.ts | 160 + src/tools/update_pan_element_or_folder.ts | 48 + src/tools/update_request_comment.ts | 65 + src/tools/update_response_comment.ts | 65 + src/tools/update_spec_properties.ts | 46 + src/tools/update_workspace.ts | 59 + .../update_workspace_global_variables.ts | 65 + src/tools/update_workspace_tags.ts | 63 + tsconfig.json | 25 + 113 files changed, 23932 insertions(+) create mode 100644 .dockerignore create mode 100644 .gitignore create mode 100644 .prettierrc.js create mode 100644 DOCKER.md create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 eslint.config.mjs create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/clients/postman.ts create mode 100644 src/index.ts create mode 100644 src/servers/express.ts create mode 100644 src/tools/create_collection.ts create mode 100644 src/tools/create_collection_comment.ts create mode 100644 src/tools/create_collection_folder.ts create mode 100644 src/tools/create_collection_fork.ts create mode 100644 src/tools/create_collection_request.ts create mode 100644 src/tools/create_collection_response.ts create mode 100644 src/tools/create_environment.ts create mode 100644 src/tools/create_folder_comment.ts create mode 100644 src/tools/create_mock.ts create mode 100644 src/tools/create_monitor.ts create mode 100644 src/tools/create_request_comment.ts create mode 100644 src/tools/create_response_comment.ts create mode 100644 src/tools/create_spec.ts create mode 100644 src/tools/create_update_spec_file.ts create mode 100644 src/tools/create_workspace.ts create mode 100644 src/tools/delete_api_collection_comment.ts create mode 100644 src/tools/delete_collection.ts create mode 100644 src/tools/delete_collection_comment.ts create mode 100644 src/tools/delete_collection_folder.ts create mode 100644 src/tools/delete_collection_request.ts create mode 100644 src/tools/delete_collection_response.ts create mode 100644 src/tools/delete_environment.ts create mode 100644 src/tools/delete_folder_comment.ts create mode 100644 src/tools/delete_mock.ts create mode 100644 src/tools/delete_monitor.ts create mode 100644 src/tools/delete_pan_element_or_folder.ts create mode 100644 src/tools/delete_request_comment.ts create mode 100644 src/tools/delete_response_comment.ts create mode 100644 src/tools/delete_spec.ts create mode 100644 src/tools/delete_workspace.ts create mode 100644 src/tools/generate_collection.ts create mode 100644 src/tools/generate_spec_from_collection.ts create mode 100644 src/tools/get_all_elements_and_folders.ts create mode 100644 src/tools/get_all_pan_add_element_requests.ts create mode 100644 src/tools/get_all_specs.ts create mode 100644 src/tools/get_async_spec_task_status.ts create mode 100644 src/tools/get_authenticated_user.ts create mode 100644 src/tools/get_collection.ts create mode 100644 src/tools/get_collection_comments.ts create mode 100644 src/tools/get_collection_folder.ts create mode 100644 src/tools/get_collection_forks.ts create mode 100644 src/tools/get_collection_request.ts create mode 100644 src/tools/get_collection_response.ts create mode 100644 src/tools/get_collection_tags.ts create mode 100644 src/tools/get_collection_updates_tasks.ts create mode 100644 src/tools/get_collections.ts create mode 100644 src/tools/get_collections_forked_by_user.ts create mode 100644 src/tools/get_environment.ts create mode 100644 src/tools/get_environments.ts create mode 100644 src/tools/get_folder_comments.ts create mode 100644 src/tools/get_generated_collection_specs.ts create mode 100644 src/tools/get_mock.ts create mode 100644 src/tools/get_mocks.ts create mode 100644 src/tools/get_monitor.ts create mode 100644 src/tools/get_monitors.ts create mode 100644 src/tools/get_request_comments.ts create mode 100644 src/tools/get_response_comments.ts create mode 100644 src/tools/get_source_collection_status.ts create mode 100644 src/tools/get_spec.ts create mode 100644 src/tools/get_spec_collections.ts create mode 100644 src/tools/get_spec_definition.ts create mode 100644 src/tools/get_status_of_an_async_task.ts create mode 100644 src/tools/get_tagged_entities.ts create mode 100644 src/tools/get_workspace.ts create mode 100644 src/tools/get_workspace_global_variables.ts create mode 100644 src/tools/get_workspace_tags.ts create mode 100644 src/tools/get_workspaces.ts create mode 100644 src/tools/patch_collection.ts create mode 100644 src/tools/patch_environment.ts create mode 100644 src/tools/post_pan_element_or_folder.ts create mode 100644 src/tools/publish_documentation.ts create mode 100644 src/tools/publish_mock.ts create mode 100644 src/tools/pull_collection_changes.ts create mode 100644 src/tools/put_collection.ts create mode 100644 src/tools/put_environment.ts create mode 100644 src/tools/resolve_comment_thread.ts create mode 100644 src/tools/run_monitor.ts create mode 100644 src/tools/sync_collection_with_spec.ts create mode 100644 src/tools/sync_spec_with_collection.ts create mode 100644 src/tools/transfer_collection_folders.ts create mode 100644 src/tools/transfer_collection_requests.ts create mode 100644 src/tools/transfer_collection_responses.ts create mode 100644 src/tools/unpublish_documentation.ts create mode 100644 src/tools/unpublish_mock.ts create mode 100644 src/tools/update_api_collection_comment.ts create mode 100644 src/tools/update_collection_comment.ts create mode 100644 src/tools/update_collection_folder.ts create mode 100644 src/tools/update_collection_request.ts create mode 100644 src/tools/update_collection_response.ts create mode 100644 src/tools/update_collection_tags.ts create mode 100644 src/tools/update_folder_comment.ts create mode 100644 src/tools/update_mock.ts create mode 100644 src/tools/update_monitor.ts create mode 100644 src/tools/update_pan_element_or_folder.ts create mode 100644 src/tools/update_request_comment.ts create mode 100644 src/tools/update_response_comment.ts create mode 100644 src/tools/update_spec_properties.ts create mode 100644 src/tools/update_workspace.ts create mode 100644 src/tools/update_workspace_global_variables.ts create mode 100644 src/tools/update_workspace_tags.ts create mode 100644 tsconfig.json diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..00aed96 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,14 @@ +# Docker specific +# --------------- +.git + +# OSX +# --- + +.DS_Store +.AppleDouble +.LSOverride + +node_modules +dist +.github diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..763301f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +dist/ +node_modules/ \ No newline at end of file diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000..dfff37e --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,10 @@ +export default { + printWidth: 100, + tabWidth: 2, + useTabs: false, + semi: true, + singleQuote: true, + trailingComma: 'es5', + bracketSpacing: true, + arrowParens: 'always', +}; diff --git a/DOCKER.md b/DOCKER.md new file mode 100644 index 0000000..2f6d388 --- /dev/null +++ b/DOCKER.md @@ -0,0 +1,30 @@ +# Docker Build Instructions + +This project uses a multi-stage Docker build to create either an HTTP API or STDIO version of the application. + +## Building with Docker + +### HTTP API Version (default) +```bash +docker build -t postman-api-mcp-server . +``` + +### STDIO Version +```bash +docker build --target production-stdio -t postman-api-mcp-stdio . +``` + +### Running the Docker Container + +#### STDIO Version +```bash +docker run -i -e POSTMAN_API_KEY="" postman-api-mcp-stdio +``` + +#### HTTP API Version +```bash +docker run -p 1337:1337 postman-api-mcp-server +``` + +### Accessing the HTTP API +You can access the HTTP API at `http://localhost:1337/mcp`. Use a tool like Postman or VS Code to connect to this endpoint (see the [README](./README.md) for VS Code integration). diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..01aadba --- /dev/null +++ b/Dockerfile @@ -0,0 +1,39 @@ +FROM node:22.16-alpine AS builder +RUN adduser -D app +USER app + +WORKDIR /app + +COPY ./package*.json ./ + +RUN npm ci + +COPY . ./ + +RUN npm run build + +FROM node:22.16-alpine AS production-base + +RUN adduser -D app +USER app +WORKDIR /app + +COPY --chown=app ./package*.json ./ + +RUN npm ci --only=production + +COPY --chown=app --from=builder /app/dist ./dist + +EXPOSE 1337 + +ENV NODE_ENV=production + +FROM production-base AS production-http + +ENTRYPOINT ["npm", "run", "start"] + +FROM production-base AS production-stdio + +ENTRYPOINT ["npm", "run", "start:stdio"] + +FROM production-http AS production diff --git a/README.md b/README.md new file mode 100644 index 0000000..cee675c --- /dev/null +++ b/README.md @@ -0,0 +1,66 @@ +# Postman API MCP Server + +This project was created with the [Postman Agent Generator](https://postman.com/explore/agent-generator), configured to [Model Context Provider (MCP)](https://modelcontextprotocol.io/introduction) Server output mode. It provides: + +- An MCP-compatible server (`dist/src/index.js`) using the [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http). +- Automatically generated JavaScript tools for each selected Postman API request. + +## 🧰 VS Code Integration + +You can integrate your MCP server with Visual Studio Code to use it with VS Code extensions that support MCP. + +1. Create a `.vscode/mcp.json` file in your project with the following configuration: + + ```json + { + "servers": { + "postman-api-mcp": { + "type": "stdio", + "command": "node", + "args": [ + "${workspaceFolder}/dist/src/index.js" + ], + "env": { + "POSTMAN_API_KEY": "${input:postman-api-key}" + } + }, + "postman-api-http-server": { + "type": "sse", + "url": "http://localhost:1337/sse", + "env": { + "POSTMAN_API_KEY": "${input:postman-api-key}" + } + } + }, + "inputs": [ + { + "id": "postman-api-key", + "type": "promptString", + "description": "Enter your Postman API key" + } + ] + } + ``` + +2. Install an MCP-compatible VS Code extension (such as GitHub Copilot, Claude for VS Code, or other AI assistants that support MCP). + +3. Configure your extension to use one of the MCP servers: + + - **postman-api-mcp**: Uses the local stdio-based server, running directly from your project files + - **postman-api-http-server**: Connects to the Postman cloud MCP server via [Streamable HTTP](https://github.com/modelcontextprotocol/typescript-sdk?tab=readme-ov-file#streamable-http) at the /mcp endpoint + +4. When prompted, enter your Postman API key. + +You can now use your Postman API tools with your VS Code extension through the MCP protocol. + +## 🐳 Docker Setup + +See [DOCKER.md](./DOCKER.md) for up-to-date build, Docker, and usage instructions. + +## Contributing + +## 💬 Questions and support + +- See the [Postman Agent Generator](https://postman.com/explore/agent-generator) page for updates and new capabilities. +- See [Add your MCP requests to your collections](https://learning.postman.com/docs/postman-ai-agent-builder/mcp-requests/overview/) to learn how to use Postman to perform MCP requests. +- Visit the [Postman Community](https://community.postman.com/) to share what you've built, ask questions, and get help. diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..121a357 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,37 @@ +// eslint.config.js +import eslint from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import unusedImports from "eslint-plugin-unused-imports"; +import eslintConfigPrettier from 'eslint-config-prettier'; // Ensures ESLint doesn't conflict with Prettier + +export default tseslint.config( + { + files: ['src/**/*.ts'], + ignores: ['**/*.js'] + }, + eslint.configs.recommended, + tseslint.configs.recommended, + { + plugins: { + "unused-imports": unusedImports, + }, + rules: { + 'no-undef': 'off', + '@typescript-eslint/no-explicit-any': 'off', + 'no-useless-escape': 'off', + '@typescript-eslint/no-unused-vars': 'off', + "no-unused-vars": "off", + "unused-imports/no-unused-imports": "error", + "unused-imports/no-unused-vars": [ + "warn", + { + "vars": "all", + "varsIgnorePattern": "^_", + "args": "after-used", + "argsIgnorePattern": "^_", + }, + ], + } + }, + eslintConfigPrettier +); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..84fe474 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6793 @@ +{ + "name": "postman-api-mcp-server", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "postman-api-mcp-server", + "version": "0.0.1", + "license": "Apache-2.0", + "dependencies": { + "@apidevtools/swagger-parser": "^11.0.0", + "@modelcontextprotocol/sdk": "^1.10.2", + "dotenv": "^16.5.0", + "es-toolkit": "^1.37.2", + "express": "^5.1.0" + }, + "devDependencies": { + "@eslint/js": "^9.26.0", + "@types/express": "^5.0.1", + "@types/node": "^22", + "eslint": "^9.26.0", + "eslint-config-prettier": "^10.1.5", + "eslint-plugin-prettier": "^5.4.0", + "eslint-plugin-unused-imports": "^4.1.4", + "fs-extra": "^11.3.0", + "jest": "^29.7.0", + "json-schema-to-zod": "^2.6.1", + "openapi-types": "^12.1.3", + "prettier": "^3.5.3", + "tsx": "^4.19.4", + "typescript": "^5.8.3", + "typescript-eslint": "^8.32.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@apidevtools/json-schema-ref-parser": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-13.0.2.tgz", + "integrity": "sha512-ThpknSFmb1zJXU16ba8cFbDRL3WRs6WETW323gOhj7Gwdj9GUqNpA5JFhdAINxINyAz03gqgF5Y4UydAjE3Pdg==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.15", + "js-yaml": "^4.1.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/philsturgeon" + } + }, + "node_modules/@apidevtools/openapi-schemas": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", + "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/@apidevtools/swagger-methods": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", + "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==", + "license": "MIT" + }, + "node_modules/@apidevtools/swagger-parser": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-11.0.1.tgz", + "integrity": "sha512-0OzWjKPUr7dvXOgQi6hsNLpwgQRtPgyQoYMuaIB+Zj50Qjbwxph/nu4BndwOA446FtQUTwkR3BxLnORpVYLHYw==", + "license": "MIT", + "dependencies": { + "@apidevtools/json-schema-ref-parser": "13.0.2", + "@apidevtools/openapi-schemas": "^2.1.0", + "@apidevtools/swagger-methods": "^3.0.2", + "ajv": "^8.17.1", + "ajv-draft-04": "^1.0.0", + "call-me-maybe": "^1.0.2" + }, + "peerDependencies": { + "openapi-types": ">=7" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.27.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.5.tgz", + "integrity": "sha512-KiRAp/VoJaWkkte84TvUd9qjdbZAdiqyvMxrGl1N6vzFogKmaLgoM3L1kgtLicp2HP5fBJS8JrZKLVIZGVJAVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.27.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.4.tgz", + "integrity": "sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.27.3", + "@babel/helpers": "^7.27.4", + "@babel/parser": "^7.27.4", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.27.4", + "@babel/types": "^7.27.3", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.27.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.5.tgz", + "integrity": "sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.27.5", + "@babel/types": "^7.27.3", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", + "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz", + "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.27.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.5.tgz", + "integrity": "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.27.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.4.tgz", + "integrity": "sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.3", + "@babel/parser": "^7.27.4", + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.3", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.6.tgz", + "integrity": "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", + "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz", + "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz", + "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz", + "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz", + "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz", + "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz", + "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz", + "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz", + "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz", + "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz", + "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz", + "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz", + "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz", + "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz", + "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz", + "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz", + "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz", + "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz", + "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz", + "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz", + "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz", + "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz", + "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz", + "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz", + "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", + "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.2.tgz", + "integrity": "sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz", + "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/js": { + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.28.0.tgz", + "integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz", + "integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.14.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.12.1.tgz", + "integrity": "sha512-KG1CZhZfWg+u8pxeM/mByJDScJSrjjxLc8fwQqbsS8xCjBmQfMNEBTotYdNanKekepnfRI85GtgQlctLFpcYPw==", + "license": "MIT", + "dependencies": { + "ajv": "^6.12.6", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "express": "^5.0.1", + "express-rate-limit": "^7.5.0", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.23.8", + "zod-to-json-schema": "^3.24.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgr/core": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.7.tgz", + "integrity": "sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz", + "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/express": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.3.tgz", + "integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz", + "integrity": "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.15.31", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.31.tgz", + "integrity": "sha512-jnVe5ULKl6tijxUhvQeNbQG/84fHfg+yMak02cT8QVhBx/F05rAVxCGBYYTh2EKz22D6JF5ktXuNwdx7b9iEGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.5", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", + "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz", + "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.0.tgz", + "integrity": "sha512-QXwAlHlbcAwNlEEMKQS2RCgJsgXrTJdjXT08xEgbPFa2yYQgVjBymxP5DrfrE7X7iodSzd9qBUHUycdyVJTW1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.34.0", + "@typescript-eslint/type-utils": "8.34.0", + "@typescript-eslint/utils": "8.34.0", + "@typescript-eslint/visitor-keys": "8.34.0", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.34.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.0.tgz", + "integrity": "sha512-vxXJV1hVFx3IXz/oy2sICsJukaBrtDEQSBiV48/YIV5KWjX1dO+bcIr/kCPrW6weKXvsaGKFNlwH0v2eYdRRbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.34.0", + "@typescript-eslint/types": "8.34.0", + "@typescript-eslint/typescript-estree": "8.34.0", + "@typescript-eslint/visitor-keys": "8.34.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.0.tgz", + "integrity": "sha512-iEgDALRf970/B2YExmtPMPF54NenZUf4xpL3wsCRx/lgjz6ul/l13R81ozP/ZNuXfnLCS+oPmG7JIxfdNYKELw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.34.0", + "@typescript-eslint/types": "^8.34.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.0.tgz", + "integrity": "sha512-9Ac0X8WiLykl0aj1oYQNcLZjHgBojT6cW68yAgZ19letYu+Hxd0rE0veI1XznSSst1X5lwnxhPbVdwjDRIomRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.34.0", + "@typescript-eslint/visitor-keys": "8.34.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.0.tgz", + "integrity": "sha512-+W9VYHKFIzA5cBeooqQxqNriAP0QeQ7xTiDuIOr71hzgffm3EL2hxwWBIIj4GuofIbKxGNarpKqIq6Q6YrShOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.0.tgz", + "integrity": "sha512-n7zSmOcUVhcRYC75W2pnPpbO1iwhJY3NLoHEtbJwJSNlVAZuwqu05zY3f3s2SDWWDSo9FdN5szqc73DCtDObAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.34.0", + "@typescript-eslint/utils": "8.34.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.0.tgz", + "integrity": "sha512-9V24k/paICYPniajHfJ4cuAWETnt7Ssy+R0Rbcqo5sSFr3QEZ/8TSoUi9XeXVBGXCaLtwTOKSLGcInCAvyZeMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.0.tgz", + "integrity": "sha512-rOi4KZxI7E0+BMqG7emPSK1bB4RICCpF7QD3KCLXn9ZvWoESsOMlHyZPAHyG04ujVplPaHbmEvs34m+wjgtVtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.34.0", + "@typescript-eslint/tsconfig-utils": "8.34.0", + "@typescript-eslint/types": "8.34.0", + "@typescript-eslint/visitor-keys": "8.34.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.0.tgz", + "integrity": "sha512-8L4tWatGchV9A1cKbjaavS6mwYwp39jql8xUmIIKJdm+qiaeHy5KMKlBrf30akXAWBzn2SqKsNOtSENWUwg7XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.34.0", + "@typescript-eslint/types": "8.34.0", + "@typescript-eslint/typescript-estree": "8.34.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.0.tgz", + "integrity": "sha512-qHV7pW7E85A0x6qyrFn+O+q1k1p3tQCsqIZ1KZ5ESLXY57aTvUd3/a4rdPTeXisvhXn2VQG0VSKUqs8KHF2zcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.34.0", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "license": "MIT", + "peerDependencies": { + "ajv": "^8.5.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", + "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "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/body-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.0.tgz", + "integrity": "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001718", + "electron-to-chromium": "^1.5.160", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-me-maybe": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", + "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", + "license": "MIT" + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001722", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001722.tgz", + "integrity": "sha512-DCQHBBZtiK6JVkAGw7drvAMK0Q0POD/xZvEmDp6baiMMP6QXXk9HpD6mNYBZWhOPG6LvIDb82ITqtWjhDckHCA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "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-disposition": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.6.0.tgz", + "integrity": "sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dotenv": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", + "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.166", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.166.tgz", + "integrity": "sha512-QPWqHL0BglzPYyJJ1zSSmwFFL6MFXhbACOCcsCdUMCkzPdS9/OIBVxg516X/Ado2qwAq8k0nJJ7phQPCqiaFAw==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-toolkit": { + "version": "1.39.3", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.39.3.tgz", + "integrity": "sha512-Qb/TCFCldgOy8lZ5uC7nLGdqJwSabkQiYQShmw4jyiPk1pZzaYWTwaYKYP7EgLccWYgZocMrtItrwh683voaww==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, + "node_modules/esbuild": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", + "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.5", + "@esbuild/android-arm": "0.25.5", + "@esbuild/android-arm64": "0.25.5", + "@esbuild/android-x64": "0.25.5", + "@esbuild/darwin-arm64": "0.25.5", + "@esbuild/darwin-x64": "0.25.5", + "@esbuild/freebsd-arm64": "0.25.5", + "@esbuild/freebsd-x64": "0.25.5", + "@esbuild/linux-arm": "0.25.5", + "@esbuild/linux-arm64": "0.25.5", + "@esbuild/linux-ia32": "0.25.5", + "@esbuild/linux-loong64": "0.25.5", + "@esbuild/linux-mips64el": "0.25.5", + "@esbuild/linux-ppc64": "0.25.5", + "@esbuild/linux-riscv64": "0.25.5", + "@esbuild/linux-s390x": "0.25.5", + "@esbuild/linux-x64": "0.25.5", + "@esbuild/netbsd-arm64": "0.25.5", + "@esbuild/netbsd-x64": "0.25.5", + "@esbuild/openbsd-arm64": "0.25.5", + "@esbuild/openbsd-x64": "0.25.5", + "@esbuild/sunos-x64": "0.25.5", + "@esbuild/win32-arm64": "0.25.5", + "@esbuild/win32-ia32": "0.25.5", + "@esbuild/win32-x64": "0.25.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.28.0.tgz", + "integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.20.0", + "@eslint/config-helpers": "^0.2.1", + "@eslint/core": "^0.14.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.28.0", + "@eslint/plugin-kit": "^0.3.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "10.1.5", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.5.tgz", + "integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.4.1.tgz", + "integrity": "sha512-9dF+KuU/Ilkq27A8idRP7N2DH8iUR6qXcjF3FR2wETY21PZdBrIjwCau8oboyGj9b7etWmTGEeM8e7oOed6ZWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.11.7" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-unused-imports": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.4.tgz", + "integrity": "sha512-YptD6IzQjDardkl0POxnnRBhU1OEePMV0nd6siHaRBbd+lyh6NAhFEobiznKU7kTsSsDeSD62Pe7kAM1b7dAZQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0", + "eslint": "^9.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.2.tgz", + "integrity": "sha512-6RxOBZ/cYgd8usLwsEl+EC09Au/9BcmCKYF2/xbml6DNczf7nv0MQb+7BA2F+li6//I+28VNlQR37XfQtcAJuA==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/express": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.0.tgz", + "integrity": "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": "^4.11 || 5 || ^5.0.0-beta.1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs-extra": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", + "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "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/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "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==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-tsconfig": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", + "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "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/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "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/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "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/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-to-zod": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/json-schema-to-zod/-/json-schema-to-zod-2.6.1.tgz", + "integrity": "sha512-uiHmWH21h9FjKJkRBntfVGTLpYlCZ1n98D0izIlByqQLqpmkQpNTBtfbdP04Na6+43lgsvrShFh2uWLkQDKJuQ==", + "dev": true, + "license": "ISC", + "bin": { + "json-schema-to-zod": "dist/cjs/cli.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=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/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openapi-types": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", + "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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/path-to-regexp": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", + "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkce-challenge": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz", + "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", + "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.6.3", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=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/synckit": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.8.tgz", + "integrity": "sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.4" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tsx": { + "version": "4.20.1", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.1.tgz", + "integrity": "sha512-JsFUnMHIE+g8KllOvWTrSOwCKM10xLcsesvUQR61znsbrcwZ4U/QaqdymmvTqG5GMD7k2VFv9UG35C4dRy34Ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.34.0.tgz", + "integrity": "sha512-MRpfN7uYjTrTGigFCt8sRyNqJFhjN0WwZecldaqhWm+wy0gaRt8Edb/3cuUy0zdq2opJWT6iXINKAtewnDOltQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.34.0", + "@typescript-eslint/parser": "8.34.0", + "@typescript-eslint/utils": "8.34.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "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==", + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.25.61", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.61.tgz", + "integrity": "sha512-fzfJgUw78LTNnHujj9re1Ov/JJQkRZZGDMcYqSx7Hp4rPOkKywaFHq0S6GoHeXs0wGNE/sIOutkXgnwzrVOGCQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.24.5", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz", + "integrity": "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.24.1" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..48c8db8 --- /dev/null +++ b/package.json @@ -0,0 +1,45 @@ +{ + "name": "postman-api-mcp-server", + "version": "0.0.1", + "description": "A simple MCP server to operate on the Postman API", + "main": "index.js", + "type": "module", + "scripts": { + "start": "node dist/src/index.js --sse", + "start:dev": "tsx src/index.ts --sse", + "start:stdio": "node dist/src/index.js", + "build": "eslint --fix ./src && prettier --write \"src/**/*.ts\" && tsc", + "test": "jest", + "lint": "eslint", + "lint:fix": "eslint --fix" + }, + "dependencies": { + "@apidevtools/swagger-parser": "^11.0.0", + "@modelcontextprotocol/sdk": "^1.10.2", + "dotenv": "^16.5.0", + "es-toolkit": "^1.37.2", + "express": "^5.1.0" + }, + "devDependencies": { + "@eslint/js": "^9.26.0", + "@types/express": "^5.0.1", + "@types/node": "^22", + "eslint": "^9.26.0", + "eslint-config-prettier": "^10.1.5", + "eslint-plugin-prettier": "^5.4.0", + "eslint-plugin-unused-imports": "^4.1.4", + "fs-extra": "^11.3.0", + "jest": "^29.7.0", + "json-schema-to-zod": "^2.6.1", + "openapi-types": "^12.1.3", + "prettier": "^3.5.3", + "tsx": "^4.19.4", + "typescript": "^5.8.3", + "typescript-eslint": "^8.32.1" + }, + "engines": { + "node": ">=16.0.0" + }, + "author": "Postman, Inc.", + "license": "Apache-2.0" +} \ No newline at end of file diff --git a/src/clients/postman.ts b/src/clients/postman.ts new file mode 100644 index 0000000..6a2e53f --- /dev/null +++ b/src/clients/postman.ts @@ -0,0 +1,49 @@ +import packageJson from '../../package.json' with { type: 'json' }; +const BASE_URL = 'https://api.getpostman.com'; + +export enum ContentType { + Json = 'application/json', + JsonPatch = 'application/json-patch+json', +} + +export interface FetchPostmanAPIOptions extends RequestInit { + contentType?: ContentType; + apiKey: string; +} + +export async function fetchPostmanAPI( + endpoint: string, + options: FetchPostmanAPIOptions +): Promise { + const apiKey = options.apiKey || process.env.POSTMAN_API_KEY; + if (!apiKey) { + throw new Error('API key is required.'); + } + const contentType = options.contentType || ContentType.Json; + + const headers = { + 'Content-Type': contentType, + 'X-API-Key': apiKey, + 'User-Agent': `${packageJson.name}/${packageJson.version}`, + ...options.headers, + }; + + const response = await fetch(`${BASE_URL}${endpoint}`, { + ...options, + headers, + }); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`API request failed: ${response.status} ${errorText}`); + } + + if (response.status === 204) return null; + + const responseContentType = response.headers.get('content-type') || ''; + if (responseContentType.includes('application/json')) { + return response.json(); + } + + return response.text(); +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..2233dc5 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,335 @@ +#!/usr/bin/env node + +import dotenv from 'dotenv'; +import { Server } from '@modelcontextprotocol/sdk/server/index.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; + +import { + CallToolRequestSchema, + ErrorCode, + ListToolsRequestSchema, + McpError, +} from '@modelcontextprotocol/sdk/types.js'; + +import zodToJsonSchema from 'zod-to-json-schema'; + +import { createApp } from './servers/express.js'; + +import * as update_api_collection_comment from './tools/update_api_collection_comment.js'; +import * as delete_api_collection_comment from './tools/delete_api_collection_comment.js'; +import * as get_status_of_an_async_task from './tools/get_status_of_an_async_task.js'; +import * as get_collections from './tools/get_collections.js'; +import * as create_collection from './tools/create_collection.js'; +import * as get_collections_forked_by_user from './tools/get_collections_forked_by_user.js'; +import * as create_collection_fork from './tools/create_collection_fork.js'; +import * as get_collection from './tools/get_collection.js'; +import * as put_collection from './tools/put_collection.js'; +import * as patch_collection from './tools/patch_collection.js'; +import * as delete_collection from './tools/delete_collection.js'; +import * as get_collection_comments from './tools/get_collection_comments.js'; +import * as create_collection_comment from './tools/create_collection_comment.js'; +import * as update_collection_comment from './tools/update_collection_comment.js'; +import * as delete_collection_comment from './tools/delete_collection_comment.js'; +import * as create_collection_folder from './tools/create_collection_folder.js'; +import * as get_folder_comments from './tools/get_folder_comments.js'; +import * as create_folder_comment from './tools/create_folder_comment.js'; +import * as update_folder_comment from './tools/update_folder_comment.js'; +import * as delete_folder_comment from './tools/delete_folder_comment.js'; +import * as get_collection_forks from './tools/get_collection_forks.js'; +import * as get_generated_collection_specs from './tools/get_generated_collection_specs.js'; +import * as generate_spec_from_collection from './tools/generate_spec_from_collection.js'; +import * as publish_documentation from './tools/publish_documentation.js'; +import * as unpublish_documentation from './tools/unpublish_documentation.js'; +import * as pull_collection_changes from './tools/pull_collection_changes.js'; +import * as create_collection_request from './tools/create_collection_request.js'; +import * as get_request_comments from './tools/get_request_comments.js'; +import * as create_request_comment from './tools/create_request_comment.js'; +import * as update_request_comment from './tools/update_request_comment.js'; +import * as delete_request_comment from './tools/delete_request_comment.js'; +import * as create_collection_response from './tools/create_collection_response.js'; +import * as get_response_comments from './tools/get_response_comments.js'; +import * as create_response_comment from './tools/create_response_comment.js'; +import * as update_response_comment from './tools/update_response_comment.js'; +import * as delete_response_comment from './tools/delete_response_comment.js'; +import * as get_source_collection_status from './tools/get_source_collection_status.js'; +import * as sync_collection_with_spec from './tools/sync_collection_with_spec.js'; +import * as get_collection_folder from './tools/get_collection_folder.js'; +import * as update_collection_folder from './tools/update_collection_folder.js'; +import * as delete_collection_folder from './tools/delete_collection_folder.js'; +import * as get_collection_request from './tools/get_collection_request.js'; +import * as update_collection_request from './tools/update_collection_request.js'; +import * as delete_collection_request from './tools/delete_collection_request.js'; +import * as get_collection_response from './tools/get_collection_response.js'; +import * as update_collection_response from './tools/update_collection_response.js'; +import * as delete_collection_response from './tools/delete_collection_response.js'; +import * as get_collection_tags from './tools/get_collection_tags.js'; +import * as update_collection_tags from './tools/update_collection_tags.js'; +import * as transfer_collection_folders from './tools/transfer_collection_folders.js'; +import * as transfer_collection_requests from './tools/transfer_collection_requests.js'; +import * as transfer_collection_responses from './tools/transfer_collection_responses.js'; +import * as get_collection_updates_tasks from './tools/get_collection_updates_tasks.js'; +import * as resolve_comment_thread from './tools/resolve_comment_thread.js'; +import * as get_async_spec_task_status from './tools/get_async_spec_task_status.js'; +import * as get_environments from './tools/get_environments.js'; +import * as create_environment from './tools/create_environment.js'; +import * as get_environment from './tools/get_environment.js'; +import * as patch_environment from './tools/patch_environment.js'; +import * as put_environment from './tools/put_environment.js'; +import * as delete_environment from './tools/delete_environment.js'; +import * as get_authenticated_user from './tools/get_authenticated_user.js'; +import * as get_mocks from './tools/get_mocks.js'; +import * as create_mock from './tools/create_mock.js'; +import * as get_mock from './tools/get_mock.js'; +import * as update_mock from './tools/update_mock.js'; +import * as delete_mock from './tools/delete_mock.js'; +import * as publish_mock from './tools/publish_mock.js'; +import * as unpublish_mock from './tools/unpublish_mock.js'; +import * as get_monitors from './tools/get_monitors.js'; +import * as create_monitor from './tools/create_monitor.js'; +import * as get_monitor from './tools/get_monitor.js'; +import * as update_monitor from './tools/update_monitor.js'; +import * as delete_monitor from './tools/delete_monitor.js'; +import * as run_monitor from './tools/run_monitor.js'; +import * as get_all_elements_and_folders from './tools/get_all_elements_and_folders.js'; +import * as post_pan_element_or_folder from './tools/post_pan_element_or_folder.js'; +import * as update_pan_element_or_folder from './tools/update_pan_element_or_folder.js'; +import * as delete_pan_element_or_folder from './tools/delete_pan_element_or_folder.js'; +import * as get_all_pan_add_element_requests from './tools/get_all_pan_add_element_requests.js'; +import * as get_tagged_entities from './tools/get_tagged_entities.js'; +import * as get_all_specs from './tools/get_all_specs.js'; +import * as create_spec from './tools/create_spec.js'; +import * as get_spec from './tools/get_spec.js'; +import * as delete_spec from './tools/delete_spec.js'; +import * as update_spec_properties from './tools/update_spec_properties.js'; +import * as get_spec_definition from './tools/get_spec_definition.js'; +import * as create_update_spec_file from './tools/create_update_spec_file.js'; +import * as get_spec_collections from './tools/get_spec_collections.js'; +import * as generate_collection from './tools/generate_collection.js'; +import * as sync_spec_with_collection from './tools/sync_spec_with_collection.js'; +import * as get_workspaces from './tools/get_workspaces.js'; +import * as create_workspace from './tools/create_workspace.js'; +import * as get_workspace from './tools/get_workspace.js'; +import * as update_workspace from './tools/update_workspace.js'; +import * as delete_workspace from './tools/delete_workspace.js'; +import * as get_workspace_global_variables from './tools/get_workspace_global_variables.js'; +import * as update_workspace_global_variables from './tools/update_workspace_global_variables.js'; +import * as get_workspace_tags from './tools/get_workspace_tags.js'; +import * as update_workspace_tags from './tools/update_workspace_tags.js'; + +dotenv.config(); + +const SERVER_NAME = 'generated-postman-api-mcp-server'; +const APP_VERSION = '0.1.0'; +export const USER_AGENT = `${SERVER_NAME}/${APP_VERSION}`; + +const logger = { + timestamp() { + return new Date().toISOString(); + }, + info(message: string, sessionId: string | null = null) { + const sessionPart = sessionId ? `[SessionId: ${sessionId}] ` : ''; + console.log(`[${this.timestamp()}] [INFO] ${sessionPart}${message}`); + }, + debug(message: string, sessionId: string | null = null) { + const sessionPart = sessionId ? `[SessionId: ${sessionId}] ` : ''; + console.log(`[${this.timestamp()}] [DEBUG] ${sessionPart}${message}`); + }, + warn(message: string, sessionId: string | null = null) { + const sessionPart = sessionId ? `[SessionId: ${sessionId}] ` : ''; + console.warn(`[${this.timestamp()}] [WARN] ${sessionPart}${message}`); + }, + error(message: string, error: any = null, sessionId: string | null = null) { + const sessionPart = sessionId ? `[SessionId: ${sessionId}] ` : ''; + console.error(`[${this.timestamp()}] [ERROR] ${sessionPart}${message}`, error || ''); + }, +}; + +let currentApiKey: string | undefined = undefined; + +const allGeneratedTools = [ + update_api_collection_comment, + delete_api_collection_comment, + get_status_of_an_async_task, + get_collections, + create_collection, + get_collections_forked_by_user, + create_collection_fork, + get_collection, + put_collection, + patch_collection, + delete_collection, + get_collection_comments, + create_collection_comment, + update_collection_comment, + delete_collection_comment, + create_collection_folder, + get_folder_comments, + create_folder_comment, + update_folder_comment, + delete_folder_comment, + get_collection_forks, + get_generated_collection_specs, + generate_spec_from_collection, + publish_documentation, + unpublish_documentation, + pull_collection_changes, + create_collection_request, + get_request_comments, + create_request_comment, + update_request_comment, + delete_request_comment, + create_collection_response, + get_response_comments, + create_response_comment, + update_response_comment, + delete_response_comment, + get_source_collection_status, + sync_collection_with_spec, + get_collection_folder, + update_collection_folder, + delete_collection_folder, + get_collection_request, + update_collection_request, + delete_collection_request, + get_collection_response, + update_collection_response, + delete_collection_response, + get_collection_tags, + update_collection_tags, + transfer_collection_folders, + transfer_collection_requests, + transfer_collection_responses, + get_collection_updates_tasks, + resolve_comment_thread, + get_async_spec_task_status, + get_environments, + create_environment, + get_environment, + patch_environment, + put_environment, + delete_environment, + get_authenticated_user, + get_mocks, + create_mock, + get_mock, + update_mock, + delete_mock, + publish_mock, + unpublish_mock, + get_monitors, + create_monitor, + get_monitor, + update_monitor, + delete_monitor, + run_monitor, + get_all_elements_and_folders, + post_pan_element_or_folder, + update_pan_element_or_folder, + delete_pan_element_or_folder, + get_all_pan_add_element_requests, + get_tagged_entities, + get_all_specs, + create_spec, + get_spec, + delete_spec, + update_spec_properties, + get_spec_definition, + create_update_spec_file, + get_spec_collections, + generate_collection, + sync_spec_with_collection, + get_workspaces, + create_workspace, + get_workspace, + update_workspace, + delete_workspace, + get_workspace_global_variables, + update_workspace_global_variables, + get_workspace_tags, + update_workspace_tags, +]; + +async function run() { + const args = process.argv.slice(2); + const isSSE = args.includes('--sse') || process.env.MCP_TRANSPORT === 'sse'; + logger.info(`Transport mode determined: ${isSSE ? 'HTTP/SSE' : 'Stdio'}`); + + const server = new Server( + { name: SERVER_NAME, version: APP_VERSION }, + { capabilities: { tools: {} } } + ); + + server.onerror = (error: any) => logger.error('[MCP Server Error]', error); + + process.on('SIGINT', async () => { + logger.info('SIGINT received, shutting down server...'); + await server.close(); + process.exit(0); + }); + + logger.info(`Registering ${allGeneratedTools.length} tools...`); + + server.setRequestHandler(CallToolRequestSchema, async (request) => { + const toolName = request.params.name; + const tool = allGeneratedTools.find((t) => t.method === toolName); + + if (!tool) { + throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${toolName}`); + } + + const args = request.params.arguments || {}; + + try { + if (!currentApiKey) { + throw new McpError(ErrorCode.InvalidParams, 'API key is required.'); + } + + const result = await tool.handler(args as any, { apiKey: currentApiKey }); + return result; + } catch (error: any) { + throw new McpError(ErrorCode.InternalError, `API error: ${error.message}`, { + originalError: error, + }); + } + }); + + server.setRequestHandler(ListToolsRequestSchema, async () => { + const transformedTools = allGeneratedTools.map((tool) => ({ + name: tool.method, + description: tool.description, + inputSchema: zodToJsonSchema(tool.parameters), + annotations: tool.annotations, + })); + return { tools: transformedTools }; + }); + + if (isSSE) { + const apiKeyCb = (key: string | undefined) => { + currentApiKey = key; + logger.info('API key set successfully.'); + }; + const app = createApp(server, logger, apiKeyCb); + const port = process.env.PORT || 1337; + const httpServer = app.listen(port, () => { + logger.info(`[${SERVER_NAME} - HTTP/SSE Server] running on port ${port}.`); + }); + process.on('SIGINT', () => { + httpServer.close(() => logger.info('HTTP server closed.')); + }); + } else { + currentApiKey = process.env.POSTMAN_API_KEY; + if (!currentApiKey) { + logger.error('API key is required. Set the POSTMAN_API_KEY environment variable.'); + process.exit(1); + } + logger.info(`[${SERVER_NAME} - Stdio Transport] running.`); + const transport = new StdioServerTransport(); + await server.connect(transport); + logger.info('Stdio transport connected. Waiting for messages...'); + } +} + +run().catch((error) => { + logger.error('Unhandled error during server execution:', error); + process.exit(1); +}); diff --git a/src/servers/express.ts b/src/servers/express.ts new file mode 100644 index 0000000..6a6f0a5 --- /dev/null +++ b/src/servers/express.ts @@ -0,0 +1,137 @@ +import express from 'express'; +import { Server } from '@modelcontextprotocol/sdk/server/index.js'; +import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; +import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'; +import { get } from 'es-toolkit/compat'; + +type Logger = { + info: (message: string, sessionId?: string | null) => void; + debug: (message: string, sessionId?: string | null) => void; + warn: (message: string, sessionId?: string | null) => void; + error: (message: string, error?: any, sessionId?: string | null) => void; + timestamp: () => string; +}; + +export function createApp( + server: Server, + logger: Logger, + setApiKeyCallback: (apiKey: string | undefined) => void +): express.Application { + const app = express(); + const transports: Record = {}; + + function extractApiKey(req: express.Request, res: express.Response, next: express.NextFunction) { + const authHeader = get(req, 'headers.authorization', ''); + const apiKey = authHeader.startsWith('Bearer ') ? authHeader.slice(7) : undefined; + setApiKeyCallback(apiKey); + logger.debug(`extractApiKey middleware: API key ${apiKey ? 'present' : 'absent'} in headers.`); + next(); + } + app.use(extractApiKey); + + app.post('/mcp', async (req: express.Request, res: express.Response) => { + logger.info('Received POST MCP request'); + try { + const transport = new StreamableHTTPServerTransport({ + sessionIdGenerator: undefined, + }); + + await server.connect(transport); + await transport.handleRequest(req, res, req.body); + + res.on('close', () => { + logger.info('Request closed'); + transport.close(); + }); + } catch (error) { + logger.error('Error handling MCP request:', error); + if (!res.headersSent) { + res.status(500).json({ + jsonrpc: '2.0', + error: { + code: -32603, + message: 'Internal server error', + }, + id: null, + }); + } + } + }); + + app.get('/mcp', (_req, res: express.Response) => { + logger.info('Received GET MCP request'); + res.writeHead(405).end( + JSON.stringify({ + jsonrpc: '2.0', + error: { + code: -32000, + message: 'Method not allowed.', + }, + id: null, + }) + ); + }); + app.delete('/mcp', (_req, res) => { + logger.warn('Received DELETE /mcp request - Method Not Allowed.'); + res.status(405).json({ + jsonrpc: '2.0', + error: { code: -32600, message: 'Method Not Allowed. Use POST.' }, + id: null, + }); + }); + + app.get('/sse', async (_req, res) => { + const clientIp = _req.headers['x-forwarded-for'] || _req.socket.remoteAddress; + const userAgent = _req.headers['user-agent']; + logger.info(`New SSE connection from ${clientIp} - User-Agent: ${userAgent}`); + + const transport = new SSEServerTransport('/messages', res); + const createdAt = new Date(); + logger.info(`SSE transport established`, transport.sessionId); + + transports[transport.sessionId] = transport; + res.on('close', () => { + const durationSec = ((new Date().getTime() - createdAt.getTime()) / 1000).toFixed(2); + logger.info(`SSE connection closed after ${durationSec}s`, transport.sessionId); + delete transports[transport.sessionId]; + }); + + try { + await server.connect(transport); + logger.info(`Server connected to SSE transport successfully`, transport.sessionId); + } catch (error) { + logger.error( + `Failed to connect server to SSE transport: ${error.message}`, + error, + transport.sessionId + ); + } + }); + app.post('/messages', async (req, res) => { + const sessionId = (req.query.sessionId as string) || ''; + logger.info(`Received message for processing`, sessionId); + + const transport = get(transports, sessionId, null); + if (transport) { + try { + logger.debug(`Processing message with transport handler`, sessionId); + await transport.handlePostMessage(req, res); + logger.info(`Message processed successfully`, sessionId); + } catch (error) { + logger.error(`Error processing message: ${error.message}`, error, sessionId); + if (!res.headersSent) { + res.status(500).send('Error processing message'); + } + } + } else { + logger.warn(`No transport found for sessionId`, sessionId); + res.status(400).send('No transport found for sessionId'); + } + }); + + app.get('/knockknock', (_req, res) => { + res.status(200).json({ server: 'papi', version: '0', status: 'ok', transport: 'http/sse' }); + }); + + return app; +} diff --git a/src/tools/create_collection.ts b/src/tools/create_collection.ts new file mode 100644 index 0000000..accf0f2 --- /dev/null +++ b/src/tools/create_collection.ts @@ -0,0 +1,5092 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'create-collection'; +export const description = + 'Creates a collection using the [Postman Collection v2.1.0 schema format](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\n- If you do not include the \\`workspace\\` query parameter, the system creates the collection in your "My Workspace" workspace.\n- For a complete list of available property values for this endpoint, use the following references available in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html):\n - \\`info\\` object — Refer to the **Information** entry.\n - \\`item\\` object — Refer to the **Items** entry.\n- For all other possible values, refer to the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n'; +export const parameters = z.object({ + workspace: z.string().describe("The workspace's ID.").optional(), + collection: z + .object({ + info: z + .object({ + name: z.string().describe("The collection's name."), + description: z.string().describe("The collection's description.").optional(), + schema: z + .literal('https://schema.getpostman.com/json/collection/v2.1.0/collection.json') + .describe( + 'The "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" Postman Collection Format v2.1.0 schema.' + ), + }) + .describe('Information about the collection.'), + item: z.array( + z.any().superRefine((x, ctx) => { + const schemas = [ + z + .object({ + name: z.string().describe("The item's name.").optional(), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z.string().describe("The description's contents.").optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z.string().nullable().describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => (result.error ? [...errors, result.error] : errors))( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z.string().describe("The variable's key (name).").optional(), + value: z.string().describe("The key's value.").optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z.string().describe("The variable's name.").optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe( + "A list of the collection's [variables](https://learning.postman.com/docs/sending-requests/variables/variables/). Make certain not to include sensitive information in variables." + ) + .optional(), + event: z + .array( + z + .object({ + listen: z + .enum(['test', 'prerequest']) + .describe( + 'Can be set to `test` or `prerequest` for test scripts or pre-request scripts respectively.' + ), + script: z + .object({ + type: z + .string() + .describe('The type of script. For example, `text/javascript`.') + .optional(), + exec: z + .array(z.string().nullable()) + .describe( + 'A list of script strings, where each line represents a line of code. Separate lines makes it easy to track script changes.' + ) + .optional(), + src: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z + .object({ + raw: z.string().describe("The request's raw URL.").optional(), + protocol: z + .string() + .describe('The request protocol.') + .optional(), + host: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string().describe("The host's URL."), + z + .array(z.string().nullable()) + .describe( + "A list of the host's subdomain components." + ), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe("The host's URL.") + .optional(), + path: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string(), + z + .array( + z.any().superRefine((x, ctx) => { + const schemas = [ + z.string().nullable(), + z.object({ + type: z.string().nullable().optional(), + value: z.string().nullable().optional(), + }), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + ) + .describe("A list of the URL's path components."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .optional(), + port: z + .string() + .describe( + "The URL's port number. An empty value indicates port `80` (http) or `443` (https)." + ) + .optional(), + query: z + .array( + z.object({ + key: z + .string() + .nullable() + .describe("The query parameter's key.") + .optional(), + value: z + .string() + .nullable() + .describe("The key's value.") + .optional(), + disabled: z + .boolean() + .describe( + "If true, the query parameter isn't sent with the request." + ) + .default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + ) + .describe( + 'A list of query parameters. These are the query string parts of the URL, parsed as separate variables.' + ) + .optional(), + hash: z + .string() + .describe( + 'Contains the URL fragment (if any). Usually this is not transmitted over the network, but it could be useful to store this in some cases.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z + .string() + .describe("The variable's key (name).") + .optional(), + value: z + .string() + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z + .string() + .describe("The variable's name.") + .optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe('A list of variables.') + .optional(), + }) + .describe('Information about the URL.'), + z.string().describe('The literal request URL.'), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe('Information about the URL.') + .optional(), + name: z.string().describe("The script's name.").optional(), + }) + .describe( + 'Information about the Javascript code that can be used to to perform setup or teardown operations in a response.' + ) + .optional(), + disabled: z + .boolean() + .describe( + 'If true, the event is disabled. If this value is absent, then the event is considered enabled.' + ) + .default(false), + }) + .describe("Information about the collection's events.") + ) + .describe( + 'A list of scripts configured to run when specific events occur. These scripts can be referenced in the collection by their ID.' + ) + .optional(), + request: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + url: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z + .object({ + raw: z.string().describe("The request's raw URL.").optional(), + protocol: z.string().describe('The request protocol.').optional(), + host: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string().describe("The host's URL."), + z + .array(z.string().nullable()) + .describe("A list of the host's subdomain components."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe("The host's URL.") + .optional(), + path: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string(), + z + .array( + z.any().superRefine((x, ctx) => { + const schemas = [ + z.string().nullable(), + z.object({ + type: z.string().nullable().optional(), + value: z.string().nullable().optional(), + }), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + ) + .describe("A list of the URL's path components."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .optional(), + port: z + .string() + .describe( + "The URL's port number. An empty value indicates port `80` (http) or `443` (https)." + ) + .optional(), + query: z + .array( + z.object({ + key: z + .string() + .nullable() + .describe("The query parameter's key.") + .optional(), + value: z + .string() + .nullable() + .describe("The key's value.") + .optional(), + disabled: z + .boolean() + .describe( + "If true, the query parameter isn't sent with the request." + ) + .default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + ) + .describe( + 'A list of query parameters. These are the query string parts of the URL, parsed as separate variables.' + ) + .optional(), + hash: z + .string() + .describe( + 'Contains the URL fragment (if any). Usually this is not transmitted over the network, but it could be useful to store this in some cases.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z + .string() + .describe("The variable's key (name).") + .optional(), + value: z.string().describe("The key's value.").optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z + .string() + .describe("The variable's name.") + .optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe('A list of variables.') + .optional(), + }) + .describe('Information about the URL.'), + z.string().describe('The literal request URL.'), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => (result.error ? [...errors, result.error] : errors))( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe('Information about the URL.') + .optional(), + auth: z + .object({ + type: z + .enum([ + 'noauth', + 'basic', + 'bearer', + 'apikey', + 'digest', + 'oauth1', + 'oauth2', + 'hawk', + 'awsv4', + 'ntlm', + 'edgegrid', + ]) + .describe('The authorization type.'), + noauth: z.any().optional(), + apikey: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe("The API key's authentication information.") + .optional(), + awsv4: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [AWS Signature](https://learning.postman.com/docs/sending-requests/authorization/aws-signature/) authentication.' + ) + .optional(), + basic: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Basic Auth](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#basic-auth).' + ) + .optional(), + bearer: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Bearer Token](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#bearer-token) authentication.' + ) + .optional(), + digest: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Digest](https://learning.postman.com/docs/sending-requests/authorization/digest-auth/) access authentication.' + ) + .optional(), + edgegrid: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Akamai Edgegrid](https://learning.postman.com/docs/sending-requests/authorization/akamai-edgegrid/) authentication.' + ) + .optional(), + hawk: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Hawk](https://learning.postman.com/docs/sending-requests/authorization/hawk-authentication/) authentication.' + ) + .optional(), + ntlm: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [NTLM](https://learning.postman.com/docs/sending-requests/authorization/ntlm-authentication/) authentication.' + ) + .optional(), + oauth1: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [OAuth1](https://learning.postman.com/docs/sending-requests/authorization/oauth-10/) authentication.' + ) + .optional(), + oauth2: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [OAuth2](https://learning.postman.com/docs/sending-requests/authorization/oauth-20/) authentication.' + ) + .optional(), + }) + .describe( + 'The [authorization type supported by Postman](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + .optional(), + proxy: z + .object({ + match: z + .string() + .describe('The URL match for the defined proxy configuration.') + .default('http+https://*/*'), + host: z.string().describe("The proxy server's host.").optional(), + port: z + .number() + .int() + .gte(0) + .describe("The proxy server's port.") + .default(8080), + tunnel: z + .boolean() + .describe('The tunneling details for the proxy configuration.') + .default(false), + disabled: z + .boolean() + .describe('If true, ignores the proxy configuration.') + .default(false), + }) + .describe('Information about custom proxy confiurations.') + .optional(), + certificate: z + .object({ + name: z.string().describe("The SSL certificate's name.").optional(), + matches: z + .array(z.string()) + .describe( + 'A list of URL match pattern strings to identify the URLs the certificate can be used for.' + ) + .optional(), + key: z + .object({ + src: z + .string() + .describe( + 'The path to the file that contains the certificate in the file system.' + ) + .optional(), + }) + .describe('Information about the private key.') + .optional(), + cert: z + .object({ + src: z + .string() + .describe( + 'The path to the file that contains the key for the certificate in the file system.' + ) + .optional(), + }) + .describe('Information about the file certificate.') + .optional(), + passphrase: z + .string() + .describe("The certificate's passphrase.") + .optional(), + }) + .optional(), + method: z + .union([ + z + .enum([ + 'GET', + 'PUT', + 'POST', + 'PATCH', + 'DELETE', + 'COPY', + 'HEAD', + 'OPTIONS', + 'LINK', + 'UNLINK', + 'PURGE', + 'LOCK', + 'UNLOCK', + 'PROPFIND', + 'VIEW', + ]) + .describe("The request's standard HTTP method."), + z.string().describe("The request's custom HTTP method."), + ]) + .optional(), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z.string().nullable().describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => (result.error ? [...errors, result.error] : errors))( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + header: z + .array( + z + .object({ + key: z + .string() + .describe( + "The header's key, such as `Content-Type` or `X-Custom-Header`." + ), + value: z.string().describe("The header key's value."), + disabled: z + .boolean() + .describe("If true, the current header isn't sent with requests.") + .default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + .describe('Information about the header.') + ) + .describe('A list of headers.') + .optional(), + body: z + .object({ + mode: z + .enum(['raw', 'urlencoded', 'formdata', 'file', 'graphql']) + .describe('The data associated with the request.') + .optional(), + raw: z + .string() + .describe( + 'If the `mode` value is `raw`, the raw content of the request body.' + ) + .optional(), + urlencoded: z + .array( + z.object({ + key: z.string().describe('The key value.'), + value: z.string().describe("The key's value.").optional(), + disabled: z.boolean().default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + ) + .describe('A list of x-www-form-encoded key/value pairs.') + .optional(), + formdata: z + .array( + z.record(z.any()).and( + z.union([ + z.object({ + key: z.string().describe('The key value.').optional(), + value: z.string().describe("The key's value.").optional(), + disabled: z + .boolean() + .describe('If true, prevents sending the form-data entry.') + .default(false), + type: z + .literal('text') + .describe('The `text` value.') + .optional(), + contentType: z + .string() + .describe('The form-data Content-Type header.') + .optional(), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }), + z.object({ + key: z.string().describe('The key value.').optional(), + src: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string().nullable(), + z.array(z.string()), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .optional(), + disabled: z + .boolean() + .describe('If true, prevents sending the form-data entry.') + .default(false), + type: z + .literal('file') + .describe('The `file` value.') + .optional(), + contentType: z + .string() + .describe('The form-data Content-Type header.') + .optional(), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }), + ]) + ) + ) + .describe( + 'If the `mode` value is `formdata`, then a list of form-data key/pair values.' + ) + .optional(), + file: z + .object({ + src: z + .string() + .nullable() + .describe( + 'The name of the file to upload (not its path). A null value indicates that no file is selected as a part of the request body.' + ) + .optional(), + content: z.string().optional(), + }) + .describe( + 'If the `mode` value is `file`, an object containing the file request information.' + ) + .optional(), + graphql: z + .object({ + query: z.string().describe('The GraphQL query.').optional(), + variables: z + .string() + .nullable() + .describe('The GraphQL query variables, in JSON format.') + .optional(), + }) + .describe( + 'If the `mode` value is `graphql`, an object containing the GraphQL request information.' + ) + .optional(), + options: z + .record(z.any()) + .describe( + 'Additional configurations and options set for various modes.' + ) + .optional(), + disabled: z + .boolean() + .describe('When set to true, prevents request body from being sent.') + .default(false), + }) + .describe("Information about the collection's request body.") + .optional(), + }), + z.string().nullable(), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => (result.error ? [...errors, result.error] : errors))( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe('Information about the collection request.'), + response: z + .array(z.any().describe("Information about the request's response.")) + .describe("A list of the collection's responses.") + .optional(), + protocolProfileBehavior: z + .object({ + strictSSL: z + .boolean() + .describe('If true, enables certificate verification.') + .optional(), + followRedirects: z + .boolean() + .describe('If true, follow HTTP 3xx responses as redirects.') + .optional(), + maxRedirects: z + .number() + .describe('The maximum number of redirects to follow.') + .optional(), + disableBodyPruning: z + .boolean() + .describe( + 'If true, disables request body pruning for the GET, COPY, HEAD, PURGE, and UNLOCK methods.' + ) + .optional(), + disableUrlEncoding: z + .boolean() + .describe( + 'If true, disables the percent encoding of auth, path, query, and fragment URL segments.' + ) + .optional(), + disabledSystemHeaders: z + .object({ + 'cache-control': z.boolean().optional(), + 'postman-token': z.boolean().optional(), + 'content-type': z.boolean().optional(), + 'content-length': z.boolean().optional(), + 'accept-encoding': z.boolean().optional(), + connection: z.boolean().optional(), + host: z.boolean().optional(), + }) + .describe('Disable the system headers which are added implicitly.') + .optional(), + insecureHTTPParser: z + .boolean() + .describe( + 'If true, uses an insecure HTTP parser that accepts invalid HTTP headers.' + ) + .optional(), + followOriginalHttpMethod: z + .boolean() + .describe( + 'If true, redirects with the original HTTP method. Redirects with the GET HTTP method by default.' + ) + .optional(), + followAuthorizationHeader: z + .boolean() + .describe( + 'If true, retains the `authorization` header when a redirect happens to a different hostname.' + ) + .optional(), + protocolVersion: z + .enum(['http1', 'http2', 'auto']) + .describe( + 'The HTTP protocol version to use. Supports the `http1`, `http2`, and `auto` values.' + ) + .optional(), + removeRefererHeaderOnRedirect: z + .boolean() + .describe('If true, removes the `referer` header when a redirect happens.') + .optional(), + tlsPreferServerCiphers: z + .boolean() + .describe( + "If true, uses the server's cipher suite order instead of the client's during negotiation." + ) + .optional(), + tlsDisabledProtocols: z + .array(z.string()) + .describe('The SSL and TLS protocol versions to disable during negotiation.') + .optional(), + tlsCipherSelection: z + .array(z.string()) + .describe( + 'The order of cipher suites that the SSL server profile uses to establish a secure connection.' + ) + .optional(), + }) + .describe( + 'The [settings](https://learning.postman.com/docs/sending-requests/create-requests/request-settings/) used to alter the [Protocol Profile Behavior](https://github.com/postmanlabs/postman-runtime/blob/develop/docs/protocol-profile-behavior.md) of sending a request.' + ) + .optional(), + }) + .describe('Information about the collection request or folder.'), + z + .object({ + name: z.string().describe("The folder's name.").optional(), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z.string().describe("The description's contents.").optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z.string().nullable().describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => (result.error ? [...errors, result.error] : errors))( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z.string().describe("The variable's key (name).").optional(), + value: z.string().describe("The key's value.").optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z.string().describe("The variable's name.").optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe( + "A list of the collection's [variables](https://learning.postman.com/docs/sending-requests/variables/variables/). Make certain not to include sensitive information in variables." + ) + .optional(), + item: z + .array( + z.union([ + z + .object({ + name: z.string().describe("The item's name.").optional(), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z.string().nullable().describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => (result.error ? [...errors, result.error] : errors))( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z.string().describe("The variable's key (name).").optional(), + value: z.string().describe("The key's value.").optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z.string().describe("The variable's name.").optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe( + "A list of the collection's [variables](https://learning.postman.com/docs/sending-requests/variables/variables/). Make certain not to include sensitive information in variables." + ) + .optional(), + event: z + .array( + z + .object({ + listen: z + .enum(['test', 'prerequest']) + .describe( + 'Can be set to `test` or `prerequest` for test scripts or pre-request scripts respectively.' + ), + script: z + .object({ + type: z + .string() + .describe( + 'The type of script. For example, `text/javascript`.' + ) + .optional(), + exec: z + .array(z.string().nullable()) + .describe( + 'A list of script strings, where each line represents a line of code. Separate lines makes it easy to track script changes.' + ) + .optional(), + src: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z + .object({ + raw: z + .string() + .describe("The request's raw URL.") + .optional(), + protocol: z + .string() + .describe('The request protocol.') + .optional(), + host: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string().describe("The host's URL."), + z + .array(z.string().nullable()) + .describe( + "A list of the host's subdomain components." + ), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe("The host's URL.") + .optional(), + path: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string(), + z + .array( + z.any().superRefine((x, ctx) => { + const schemas = [ + z.string().nullable(), + z.object({ + type: z + .string() + .nullable() + .optional(), + value: z + .string() + .nullable() + .optional(), + }), + ]; + const errors = schemas.reduce< + z.ZodError[] + >( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if ( + schemas.length - errors.length !== + 1 + ) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + ) + .describe( + "A list of the URL's path components." + ), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .optional(), + port: z + .string() + .describe( + "The URL's port number. An empty value indicates port `80` (http) or `443` (https)." + ) + .optional(), + query: z + .array( + z.object({ + key: z + .string() + .nullable() + .describe("The query parameter's key.") + .optional(), + value: z + .string() + .nullable() + .describe("The key's value.") + .optional(), + disabled: z + .boolean() + .describe( + "If true, the query parameter isn't sent with the request." + ) + .default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe( + "The description's contents." + ) + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe( + "The collection's description." + ), + ]; + const errors = schemas.reduce< + z.ZodError[] + >( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if ( + schemas.length - errors.length !== + 1 + ) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + ) + .describe( + 'A list of query parameters. These are the query string parts of the URL, parsed as separate variables.' + ) + .optional(), + hash: z + .string() + .describe( + 'Contains the URL fragment (if any). Usually this is not transmitted over the network, but it could be useful to store this in some cases.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z + .string() + .describe("The variable's key (name).") + .optional(), + value: z + .string() + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z + .string() + .describe("The variable's name.") + .optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe('A list of variables.') + .optional(), + }) + .describe('Information about the URL.'), + z.string().describe('The literal request URL.'), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe('Information about the URL.') + .optional(), + name: z.string().describe("The script's name.").optional(), + }) + .describe( + 'Information about the Javascript code that can be used to to perform setup or teardown operations in a response.' + ) + .optional(), + disabled: z + .boolean() + .describe( + 'If true, the event is disabled. If this value is absent, then the event is considered enabled.' + ) + .default(false), + }) + .describe("Information about the collection's events.") + ) + .describe( + 'A list of scripts configured to run when specific events occur. These scripts can be referenced in the collection by their ID.' + ) + .optional(), + request: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + url: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z + .object({ + raw: z + .string() + .describe("The request's raw URL.") + .optional(), + protocol: z + .string() + .describe('The request protocol.') + .optional(), + host: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string().describe("The host's URL."), + z + .array(z.string().nullable()) + .describe( + "A list of the host's subdomain components." + ), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe("The host's URL.") + .optional(), + path: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string(), + z + .array( + z.any().superRefine((x, ctx) => { + const schemas = [ + z.string().nullable(), + z.object({ + type: z.string().nullable().optional(), + value: z.string().nullable().optional(), + }), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + ) + .describe( + "A list of the URL's path components." + ), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .optional(), + port: z + .string() + .describe( + "The URL's port number. An empty value indicates port `80` (http) or `443` (https)." + ) + .optional(), + query: z + .array( + z.object({ + key: z + .string() + .nullable() + .describe("The query parameter's key.") + .optional(), + value: z + .string() + .nullable() + .describe("The key's value.") + .optional(), + disabled: z + .boolean() + .describe( + "If true, the query parameter isn't sent with the request." + ) + .default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe( + "The collection's description." + ), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + ) + .describe( + 'A list of query parameters. These are the query string parts of the URL, parsed as separate variables.' + ) + .optional(), + hash: z + .string() + .describe( + 'Contains the URL fragment (if any). Usually this is not transmitted over the network, but it could be useful to store this in some cases.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z + .string() + .describe("The variable's key (name).") + .optional(), + value: z + .string() + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z + .string() + .describe("The variable's name.") + .optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe('A list of variables.') + .optional(), + }) + .describe('Information about the URL.'), + z.string().describe('The literal request URL.'), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe('Information about the URL.') + .optional(), + auth: z + .object({ + type: z + .enum([ + 'noauth', + 'basic', + 'bearer', + 'apikey', + 'digest', + 'oauth1', + 'oauth2', + 'hawk', + 'awsv4', + 'ntlm', + 'edgegrid', + ]) + .describe('The authorization type.'), + noauth: z.any().optional(), + apikey: z + .array( + z + .object({ + key: z + .string() + .describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe("The API key's authentication information.") + .optional(), + awsv4: z + .array( + z + .object({ + key: z + .string() + .describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [AWS Signature](https://learning.postman.com/docs/sending-requests/authorization/aws-signature/) authentication.' + ) + .optional(), + basic: z + .array( + z + .object({ + key: z + .string() + .describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Basic Auth](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#basic-auth).' + ) + .optional(), + bearer: z + .array( + z + .object({ + key: z + .string() + .describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Bearer Token](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#bearer-token) authentication.' + ) + .optional(), + digest: z + .array( + z + .object({ + key: z + .string() + .describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Digest](https://learning.postman.com/docs/sending-requests/authorization/digest-auth/) access authentication.' + ) + .optional(), + edgegrid: z + .array( + z + .object({ + key: z + .string() + .describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Akamai Edgegrid](https://learning.postman.com/docs/sending-requests/authorization/akamai-edgegrid/) authentication.' + ) + .optional(), + hawk: z + .array( + z + .object({ + key: z + .string() + .describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Hawk](https://learning.postman.com/docs/sending-requests/authorization/hawk-authentication/) authentication.' + ) + .optional(), + ntlm: z + .array( + z + .object({ + key: z + .string() + .describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [NTLM](https://learning.postman.com/docs/sending-requests/authorization/ntlm-authentication/) authentication.' + ) + .optional(), + oauth1: z + .array( + z + .object({ + key: z + .string() + .describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [OAuth1](https://learning.postman.com/docs/sending-requests/authorization/oauth-10/) authentication.' + ) + .optional(), + oauth2: z + .array( + z + .object({ + key: z + .string() + .describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [OAuth2](https://learning.postman.com/docs/sending-requests/authorization/oauth-20/) authentication.' + ) + .optional(), + }) + .describe( + 'The [authorization type supported by Postman](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + .optional(), + proxy: z + .object({ + match: z + .string() + .describe( + 'The URL match for the defined proxy configuration.' + ) + .default('http+https://*/*'), + host: z + .string() + .describe("The proxy server's host.") + .optional(), + port: z + .number() + .int() + .gte(0) + .describe("The proxy server's port.") + .default(8080), + tunnel: z + .boolean() + .describe( + 'The tunneling details for the proxy configuration.' + ) + .default(false), + disabled: z + .boolean() + .describe('If true, ignores the proxy configuration.') + .default(false), + }) + .describe('Information about custom proxy confiurations.') + .optional(), + certificate: z + .object({ + name: z + .string() + .describe("The SSL certificate's name.") + .optional(), + matches: z + .array(z.string()) + .describe( + 'A list of URL match pattern strings to identify the URLs the certificate can be used for.' + ) + .optional(), + key: z + .object({ + src: z + .string() + .describe( + 'The path to the file that contains the certificate in the file system.' + ) + .optional(), + }) + .describe('Information about the private key.') + .optional(), + cert: z + .object({ + src: z + .string() + .describe( + 'The path to the file that contains the key for the certificate in the file system.' + ) + .optional(), + }) + .describe('Information about the file certificate.') + .optional(), + passphrase: z + .string() + .describe("The certificate's passphrase.") + .optional(), + }) + .optional(), + method: z + .union([ + z + .enum([ + 'GET', + 'PUT', + 'POST', + 'PATCH', + 'DELETE', + 'COPY', + 'HEAD', + 'OPTIONS', + 'LINK', + 'UNLINK', + 'PURGE', + 'LOCK', + 'UNLOCK', + 'PROPFIND', + 'VIEW', + ]) + .describe("The request's standard HTTP method."), + z.string().describe("The request's custom HTTP method."), + ]) + .optional(), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + header: z + .array( + z + .object({ + key: z + .string() + .describe( + "The header's key, such as `Content-Type` or `X-Custom-Header`." + ), + value: z.string().describe("The header key's value."), + disabled: z + .boolean() + .describe( + "If true, the current header isn't sent with requests." + ) + .default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + .describe('Information about the header.') + ) + .describe('A list of headers.') + .optional(), + body: z + .object({ + mode: z + .enum(['raw', 'urlencoded', 'formdata', 'file', 'graphql']) + .describe('The data associated with the request.') + .optional(), + raw: z + .string() + .describe( + 'If the `mode` value is `raw`, the raw content of the request body.' + ) + .optional(), + urlencoded: z + .array( + z.object({ + key: z.string().describe('The key value.'), + value: z + .string() + .describe("The key's value.") + .optional(), + disabled: z.boolean().default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + ) + .describe('A list of x-www-form-encoded key/value pairs.') + .optional(), + formdata: z + .array( + z.record(z.any()).and( + z.union([ + z.object({ + key: z + .string() + .describe('The key value.') + .optional(), + value: z + .string() + .describe("The key's value.") + .optional(), + disabled: z + .boolean() + .describe( + 'If true, prevents sending the form-data entry.' + ) + .default(false), + type: z + .literal('text') + .describe('The `text` value.') + .optional(), + contentType: z + .string() + .describe('The form-data Content-Type header.') + .optional(), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }), + z.object({ + key: z + .string() + .describe('The key value.') + .optional(), + src: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string().nullable(), + z.array(z.string()), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .optional(), + disabled: z + .boolean() + .describe( + 'If true, prevents sending the form-data entry.' + ) + .default(false), + type: z + .literal('file') + .describe('The `file` value.') + .optional(), + contentType: z + .string() + .describe('The form-data Content-Type header.') + .optional(), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }), + ]) + ) + ) + .describe( + 'If the `mode` value is `formdata`, then a list of form-data key/pair values.' + ) + .optional(), + file: z + .object({ + src: z + .string() + .nullable() + .describe( + 'The name of the file to upload (not its path). A null value indicates that no file is selected as a part of the request body.' + ) + .optional(), + content: z.string().optional(), + }) + .describe( + 'If the `mode` value is `file`, an object containing the file request information.' + ) + .optional(), + graphql: z + .object({ + query: z + .string() + .describe('The GraphQL query.') + .optional(), + variables: z + .string() + .nullable() + .describe( + 'The GraphQL query variables, in JSON format.' + ) + .optional(), + }) + .describe( + 'If the `mode` value is `graphql`, an object containing the GraphQL request information.' + ) + .optional(), + options: z + .record(z.any()) + .describe( + 'Additional configurations and options set for various modes.' + ) + .optional(), + disabled: z + .boolean() + .describe( + 'When set to true, prevents request body from being sent.' + ) + .default(false), + }) + .describe("Information about the collection's request body.") + .optional(), + }), + z.string().nullable(), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => (result.error ? [...errors, result.error] : errors))( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe('Information about the collection request.'), + response: z + .array(z.any().describe("Information about the request's response.")) + .describe("A list of the collection's responses.") + .optional(), + protocolProfileBehavior: z + .object({ + strictSSL: z + .boolean() + .describe('If true, enables certificate verification.') + .optional(), + followRedirects: z + .boolean() + .describe('If true, follow HTTP 3xx responses as redirects.') + .optional(), + maxRedirects: z + .number() + .describe('The maximum number of redirects to follow.') + .optional(), + disableBodyPruning: z + .boolean() + .describe( + 'If true, disables request body pruning for the GET, COPY, HEAD, PURGE, and UNLOCK methods.' + ) + .optional(), + disableUrlEncoding: z + .boolean() + .describe( + 'If true, disables the percent encoding of auth, path, query, and fragment URL segments.' + ) + .optional(), + disabledSystemHeaders: z + .object({ + 'cache-control': z.boolean().optional(), + 'postman-token': z.boolean().optional(), + 'content-type': z.boolean().optional(), + 'content-length': z.boolean().optional(), + 'accept-encoding': z.boolean().optional(), + connection: z.boolean().optional(), + host: z.boolean().optional(), + }) + .describe('Disable the system headers which are added implicitly.') + .optional(), + insecureHTTPParser: z + .boolean() + .describe( + 'If true, uses an insecure HTTP parser that accepts invalid HTTP headers.' + ) + .optional(), + followOriginalHttpMethod: z + .boolean() + .describe( + 'If true, redirects with the original HTTP method. Redirects with the GET HTTP method by default.' + ) + .optional(), + followAuthorizationHeader: z + .boolean() + .describe( + 'If true, retains the `authorization` header when a redirect happens to a different hostname.' + ) + .optional(), + protocolVersion: z + .enum(['http1', 'http2', 'auto']) + .describe( + 'The HTTP protocol version to use. Supports the `http1`, `http2`, and `auto` values.' + ) + .optional(), + removeRefererHeaderOnRedirect: z + .boolean() + .describe( + 'If true, removes the `referer` header when a redirect happens.' + ) + .optional(), + tlsPreferServerCiphers: z + .boolean() + .describe( + "If true, uses the server's cipher suite order instead of the client's during negotiation." + ) + .optional(), + tlsDisabledProtocols: z + .array(z.string()) + .describe( + 'The SSL and TLS protocol versions to disable during negotiation.' + ) + .optional(), + tlsCipherSelection: z + .array(z.string()) + .describe( + 'The order of cipher suites that the SSL server profile uses to establish a secure connection.' + ) + .optional(), + }) + .describe( + 'The [settings](https://learning.postman.com/docs/sending-requests/create-requests/request-settings/) used to alter the [Protocol Profile Behavior](https://github.com/postmanlabs/postman-runtime/blob/develop/docs/protocol-profile-behavior.md) of sending a request.' + ) + .optional(), + }) + .describe('Information about the collection request or folder.'), + z + .object({ + name: z.string().describe("The folder's name.").optional(), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z.string().nullable().describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => (result.error ? [...errors, result.error] : errors))( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z.string().describe("The variable's key (name).").optional(), + value: z.string().describe("The key's value.").optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z.string().describe("The variable's name.").optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe( + "A list of the collection's [variables](https://learning.postman.com/docs/sending-requests/variables/variables/). Make certain not to include sensitive information in variables." + ) + .optional(), + item: z.any(), + event: z + .array( + z + .object({ + listen: z + .enum(['test', 'prerequest']) + .describe( + 'Can be set to `test` or `prerequest` for test scripts or pre-request scripts respectively.' + ), + script: z + .object({ + type: z + .string() + .describe( + 'The type of script. For example, `text/javascript`.' + ) + .optional(), + exec: z + .array(z.string().nullable()) + .describe( + 'A list of script strings, where each line represents a line of code. Separate lines makes it easy to track script changes.' + ) + .optional(), + src: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z + .object({ + raw: z + .string() + .describe("The request's raw URL.") + .optional(), + protocol: z + .string() + .describe('The request protocol.') + .optional(), + host: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string().describe("The host's URL."), + z + .array(z.string().nullable()) + .describe( + "A list of the host's subdomain components." + ), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe("The host's URL.") + .optional(), + path: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string(), + z + .array( + z.any().superRefine((x, ctx) => { + const schemas = [ + z.string().nullable(), + z.object({ + type: z + .string() + .nullable() + .optional(), + value: z + .string() + .nullable() + .optional(), + }), + ]; + const errors = schemas.reduce< + z.ZodError[] + >( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if ( + schemas.length - errors.length !== + 1 + ) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + ) + .describe( + "A list of the URL's path components." + ), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .optional(), + port: z + .string() + .describe( + "The URL's port number. An empty value indicates port `80` (http) or `443` (https)." + ) + .optional(), + query: z + .array( + z.object({ + key: z + .string() + .nullable() + .describe("The query parameter's key.") + .optional(), + value: z + .string() + .nullable() + .describe("The key's value.") + .optional(), + disabled: z + .boolean() + .describe( + "If true, the query parameter isn't sent with the request." + ) + .default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe( + "The description's contents." + ) + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe( + "The collection's description." + ), + ]; + const errors = schemas.reduce< + z.ZodError[] + >( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if ( + schemas.length - errors.length !== + 1 + ) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + ) + .describe( + 'A list of query parameters. These are the query string parts of the URL, parsed as separate variables.' + ) + .optional(), + hash: z + .string() + .describe( + 'Contains the URL fragment (if any). Usually this is not transmitted over the network, but it could be useful to store this in some cases.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z + .string() + .describe("The variable's key (name).") + .optional(), + value: z + .string() + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z + .string() + .describe("The variable's name.") + .optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe('A list of variables.') + .optional(), + }) + .describe('Information about the URL.'), + z.string().describe('The literal request URL.'), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe('Information about the URL.') + .optional(), + name: z.string().describe("The script's name.").optional(), + }) + .describe( + 'Information about the Javascript code that can be used to to perform setup or teardown operations in a response.' + ) + .optional(), + disabled: z + .boolean() + .describe( + 'If true, the event is disabled. If this value is absent, then the event is considered enabled.' + ) + .default(false), + }) + .describe("Information about the collection's events.") + ) + .describe( + 'A list of scripts configured to run when specific events occur. These scripts can be referenced in the collection by their ID.' + ) + .optional(), + auth: z + .object({ + type: z + .enum([ + 'noauth', + 'basic', + 'bearer', + 'apikey', + 'digest', + 'oauth1', + 'oauth2', + 'hawk', + 'awsv4', + 'ntlm', + 'edgegrid', + ]) + .describe('The authorization type.'), + noauth: z.any().optional(), + apikey: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe("The API key's authentication information.") + .optional(), + awsv4: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [AWS Signature](https://learning.postman.com/docs/sending-requests/authorization/aws-signature/) authentication.' + ) + .optional(), + basic: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Basic Auth](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#basic-auth).' + ) + .optional(), + bearer: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Bearer Token](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#bearer-token) authentication.' + ) + .optional(), + digest: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Digest](https://learning.postman.com/docs/sending-requests/authorization/digest-auth/) access authentication.' + ) + .optional(), + edgegrid: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Akamai Edgegrid](https://learning.postman.com/docs/sending-requests/authorization/akamai-edgegrid/) authentication.' + ) + .optional(), + hawk: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Hawk](https://learning.postman.com/docs/sending-requests/authorization/hawk-authentication/) authentication.' + ) + .optional(), + ntlm: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [NTLM](https://learning.postman.com/docs/sending-requests/authorization/ntlm-authentication/) authentication.' + ) + .optional(), + oauth1: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [OAuth1](https://learning.postman.com/docs/sending-requests/authorization/oauth-10/) authentication.' + ) + .optional(), + oauth2: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [OAuth2](https://learning.postman.com/docs/sending-requests/authorization/oauth-20/) authentication.' + ) + .optional(), + }) + .describe("Information about the folder's authentication.") + .optional(), + protocolProfileBehavior: z + .object({ + strictSSL: z + .boolean() + .describe('If true, enables certificate verification.') + .optional(), + followRedirects: z + .boolean() + .describe('If true, follow HTTP 3xx responses as redirects.') + .optional(), + maxRedirects: z + .number() + .describe('The maximum number of redirects to follow.') + .optional(), + disableBodyPruning: z + .boolean() + .describe( + 'If true, disables request body pruning for the GET, COPY, HEAD, PURGE, and UNLOCK methods.' + ) + .optional(), + disableUrlEncoding: z + .boolean() + .describe( + 'If true, disables the percent encoding of auth, path, query, and fragment URL segments.' + ) + .optional(), + disabledSystemHeaders: z + .object({ + 'cache-control': z.boolean().optional(), + 'postman-token': z.boolean().optional(), + 'content-type': z.boolean().optional(), + 'content-length': z.boolean().optional(), + 'accept-encoding': z.boolean().optional(), + connection: z.boolean().optional(), + host: z.boolean().optional(), + }) + .describe('Disable the system headers which are added implicitly.') + .optional(), + insecureHTTPParser: z + .boolean() + .describe( + 'If true, uses an insecure HTTP parser that accepts invalid HTTP headers.' + ) + .optional(), + followOriginalHttpMethod: z + .boolean() + .describe( + 'If true, redirects with the original HTTP method. Redirects with the GET HTTP method by default.' + ) + .optional(), + followAuthorizationHeader: z + .boolean() + .describe( + 'If true, retains the `authorization` header when a redirect happens to a different hostname.' + ) + .optional(), + protocolVersion: z + .enum(['http1', 'http2', 'auto']) + .describe( + 'The HTTP protocol version to use. Supports the `http1`, `http2`, and `auto` values.' + ) + .optional(), + removeRefererHeaderOnRedirect: z + .boolean() + .describe( + 'If true, removes the `referer` header when a redirect happens.' + ) + .optional(), + tlsPreferServerCiphers: z + .boolean() + .describe( + "If true, uses the server's cipher suite order instead of the client's during negotiation." + ) + .optional(), + tlsDisabledProtocols: z + .array(z.string()) + .describe( + 'The SSL and TLS protocol versions to disable during negotiation.' + ) + .optional(), + tlsCipherSelection: z + .array(z.string()) + .describe( + 'The order of cipher suites that the SSL server profile uses to establish a secure connection.' + ) + .optional(), + }) + .describe( + 'The [settings](https://learning.postman.com/docs/sending-requests/create-requests/request-settings/) used to alter the [Protocol Profile Behavior](https://github.com/postmanlabs/postman-runtime/blob/develop/docs/protocol-profile-behavior.md) of sending a request.' + ) + .optional(), + }) + .describe( + "Information about the collection's folders. A folder is an organized group of requests." + ), + ]) + ) + .describe( + "A list of the folder's contents, such as requests, responses, and additional folders." + ), + event: z + .array( + z + .object({ + listen: z + .enum(['test', 'prerequest']) + .describe( + 'Can be set to `test` or `prerequest` for test scripts or pre-request scripts respectively.' + ), + script: z + .object({ + type: z + .string() + .describe('The type of script. For example, `text/javascript`.') + .optional(), + exec: z + .array(z.string().nullable()) + .describe( + 'A list of script strings, where each line represents a line of code. Separate lines makes it easy to track script changes.' + ) + .optional(), + src: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z + .object({ + raw: z.string().describe("The request's raw URL.").optional(), + protocol: z + .string() + .describe('The request protocol.') + .optional(), + host: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string().describe("The host's URL."), + z + .array(z.string().nullable()) + .describe( + "A list of the host's subdomain components." + ), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe("The host's URL.") + .optional(), + path: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string(), + z + .array( + z.any().superRefine((x, ctx) => { + const schemas = [ + z.string().nullable(), + z.object({ + type: z.string().nullable().optional(), + value: z.string().nullable().optional(), + }), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + ) + .describe("A list of the URL's path components."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .optional(), + port: z + .string() + .describe( + "The URL's port number. An empty value indicates port `80` (http) or `443` (https)." + ) + .optional(), + query: z + .array( + z.object({ + key: z + .string() + .nullable() + .describe("The query parameter's key.") + .optional(), + value: z + .string() + .nullable() + .describe("The key's value.") + .optional(), + disabled: z + .boolean() + .describe( + "If true, the query parameter isn't sent with the request." + ) + .default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + ) + .describe( + 'A list of query parameters. These are the query string parts of the URL, parsed as separate variables.' + ) + .optional(), + hash: z + .string() + .describe( + 'Contains the URL fragment (if any). Usually this is not transmitted over the network, but it could be useful to store this in some cases.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z + .string() + .describe("The variable's key (name).") + .optional(), + value: z + .string() + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z + .string() + .describe("The variable's name.") + .optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe('A list of variables.') + .optional(), + }) + .describe('Information about the URL.'), + z.string().describe('The literal request URL.'), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe('Information about the URL.') + .optional(), + name: z.string().describe("The script's name.").optional(), + }) + .describe( + 'Information about the Javascript code that can be used to to perform setup or teardown operations in a response.' + ) + .optional(), + disabled: z + .boolean() + .describe( + 'If true, the event is disabled. If this value is absent, then the event is considered enabled.' + ) + .default(false), + }) + .describe("Information about the collection's events.") + ) + .describe( + 'A list of scripts configured to run when specific events occur. These scripts can be referenced in the collection by their ID.' + ) + .optional(), + auth: z + .object({ + type: z + .enum([ + 'noauth', + 'basic', + 'bearer', + 'apikey', + 'digest', + 'oauth1', + 'oauth2', + 'hawk', + 'awsv4', + 'ntlm', + 'edgegrid', + ]) + .describe('The authorization type.'), + noauth: z.any().optional(), + apikey: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe("The API key's authentication information.") + .optional(), + awsv4: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [AWS Signature](https://learning.postman.com/docs/sending-requests/authorization/aws-signature/) authentication.' + ) + .optional(), + basic: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Basic Auth](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#basic-auth).' + ) + .optional(), + bearer: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Bearer Token](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#bearer-token) authentication.' + ) + .optional(), + digest: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Digest](https://learning.postman.com/docs/sending-requests/authorization/digest-auth/) access authentication.' + ) + .optional(), + edgegrid: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Akamai Edgegrid](https://learning.postman.com/docs/sending-requests/authorization/akamai-edgegrid/) authentication.' + ) + .optional(), + hawk: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Hawk](https://learning.postman.com/docs/sending-requests/authorization/hawk-authentication/) authentication.' + ) + .optional(), + ntlm: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [NTLM](https://learning.postman.com/docs/sending-requests/authorization/ntlm-authentication/) authentication.' + ) + .optional(), + oauth1: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [OAuth1](https://learning.postman.com/docs/sending-requests/authorization/oauth-10/) authentication.' + ) + .optional(), + oauth2: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [OAuth2](https://learning.postman.com/docs/sending-requests/authorization/oauth-20/) authentication.' + ) + .optional(), + }) + .describe("Information about the folder's authentication.") + .optional(), + protocolProfileBehavior: z + .object({ + strictSSL: z + .boolean() + .describe('If true, enables certificate verification.') + .optional(), + followRedirects: z + .boolean() + .describe('If true, follow HTTP 3xx responses as redirects.') + .optional(), + maxRedirects: z + .number() + .describe('The maximum number of redirects to follow.') + .optional(), + disableBodyPruning: z + .boolean() + .describe( + 'If true, disables request body pruning for the GET, COPY, HEAD, PURGE, and UNLOCK methods.' + ) + .optional(), + disableUrlEncoding: z + .boolean() + .describe( + 'If true, disables the percent encoding of auth, path, query, and fragment URL segments.' + ) + .optional(), + disabledSystemHeaders: z + .object({ + 'cache-control': z.boolean().optional(), + 'postman-token': z.boolean().optional(), + 'content-type': z.boolean().optional(), + 'content-length': z.boolean().optional(), + 'accept-encoding': z.boolean().optional(), + connection: z.boolean().optional(), + host: z.boolean().optional(), + }) + .describe('Disable the system headers which are added implicitly.') + .optional(), + insecureHTTPParser: z + .boolean() + .describe( + 'If true, uses an insecure HTTP parser that accepts invalid HTTP headers.' + ) + .optional(), + followOriginalHttpMethod: z + .boolean() + .describe( + 'If true, redirects with the original HTTP method. Redirects with the GET HTTP method by default.' + ) + .optional(), + followAuthorizationHeader: z + .boolean() + .describe( + 'If true, retains the `authorization` header when a redirect happens to a different hostname.' + ) + .optional(), + protocolVersion: z + .enum(['http1', 'http2', 'auto']) + .describe( + 'The HTTP protocol version to use. Supports the `http1`, `http2`, and `auto` values.' + ) + .optional(), + removeRefererHeaderOnRedirect: z + .boolean() + .describe('If true, removes the `referer` header when a redirect happens.') + .optional(), + tlsPreferServerCiphers: z + .boolean() + .describe( + "If true, uses the server's cipher suite order instead of the client's during negotiation." + ) + .optional(), + tlsDisabledProtocols: z + .array(z.string()) + .describe('The SSL and TLS protocol versions to disable during negotiation.') + .optional(), + tlsCipherSelection: z + .array(z.string()) + .describe( + 'The order of cipher suites that the SSL server profile uses to establish a secure connection.' + ) + .optional(), + }) + .describe( + 'The [settings](https://learning.postman.com/docs/sending-requests/create-requests/request-settings/) used to alter the [Protocol Profile Behavior](https://github.com/postmanlabs/postman-runtime/blob/develop/docs/protocol-profile-behavior.md) of sending a request.' + ) + .optional(), + }) + .describe( + "Information about the collection's folders. A folder is an organized group of requests." + ), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => (result.error ? [...errors, result.error] : errors))( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + ), + event: z + .array( + z + .object({ + listen: z + .enum(['test', 'prerequest']) + .describe( + 'Can be set to `test` or `prerequest` for test scripts or pre-request scripts respectively.' + ), + script: z + .object({ + type: z + .string() + .describe('The type of script. For example, `text/javascript`.') + .optional(), + exec: z + .array(z.string().nullable()) + .describe( + 'A list of script strings, where each line represents a line of code. Separate lines makes it easy to track script changes.' + ) + .optional(), + src: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z + .object({ + raw: z.string().describe("The request's raw URL.").optional(), + protocol: z.string().describe('The request protocol.').optional(), + host: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string().describe("The host's URL."), + z + .array(z.string().nullable()) + .describe("A list of the host's subdomain components."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe("The host's URL.") + .optional(), + path: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string(), + z + .array( + z.any().superRefine((x, ctx) => { + const schemas = [ + z.string().nullable(), + z.object({ + type: z.string().nullable().optional(), + value: z.string().nullable().optional(), + }), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + ) + .describe("A list of the URL's path components."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .optional(), + port: z + .string() + .describe( + "The URL's port number. An empty value indicates port `80` (http) or `443` (https)." + ) + .optional(), + query: z + .array( + z.object({ + key: z + .string() + .nullable() + .describe("The query parameter's key.") + .optional(), + value: z + .string() + .nullable() + .describe("The key's value.") + .optional(), + disabled: z + .boolean() + .describe( + "If true, the query parameter isn't sent with the request." + ) + .default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + ) + .describe( + 'A list of query parameters. These are the query string parts of the URL, parsed as separate variables.' + ) + .optional(), + hash: z + .string() + .describe( + 'Contains the URL fragment (if any). Usually this is not transmitted over the network, but it could be useful to store this in some cases.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z + .string() + .describe("The variable's key (name).") + .optional(), + value: z.string().describe("The key's value.").optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z.string().describe("The variable's name.").optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe('A list of variables.') + .optional(), + }) + .describe('Information about the URL.'), + z.string().describe('The literal request URL.'), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => (result.error ? [...errors, result.error] : errors))( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe('Information about the URL.') + .optional(), + name: z.string().describe("The script's name.").optional(), + }) + .describe( + 'Information about the Javascript code that can be used to to perform setup or teardown operations in a response.' + ) + .optional(), + disabled: z + .boolean() + .describe( + 'If true, the event is disabled. If this value is absent, then the event is considered enabled.' + ) + .default(false), + }) + .describe("Information about the collection's events.") + ) + .describe( + 'A list of scripts configured to run when specific events occur. These scripts can be referenced in the collection by their ID.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z.string().describe("The variable's key (name).").optional(), + value: z.string().describe("The key's value.").optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z.string().describe("The variable's name.").optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe( + "A list of the collection's [variables](https://learning.postman.com/docs/sending-requests/variables/variables/). Make certain not to include sensitive information in variables." + ) + .optional(), + auth: z + .object({ + type: z + .enum([ + 'noauth', + 'basic', + 'bearer', + 'apikey', + 'digest', + 'oauth1', + 'oauth2', + 'hawk', + 'awsv4', + 'ntlm', + 'edgegrid', + ]) + .describe('The authorization type.'), + noauth: z.any().optional(), + apikey: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe("The API key's authentication information.") + .optional(), + awsv4: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [AWS Signature](https://learning.postman.com/docs/sending-requests/authorization/aws-signature/) authentication.' + ) + .optional(), + basic: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Basic Auth](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#basic-auth).' + ) + .optional(), + bearer: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Bearer Token](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#bearer-token) authentication.' + ) + .optional(), + digest: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Digest](https://learning.postman.com/docs/sending-requests/authorization/digest-auth/) access authentication.' + ) + .optional(), + edgegrid: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Akamai Edgegrid](https://learning.postman.com/docs/sending-requests/authorization/akamai-edgegrid/) authentication.' + ) + .optional(), + hawk: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Hawk](https://learning.postman.com/docs/sending-requests/authorization/hawk-authentication/) authentication.' + ) + .optional(), + ntlm: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [NTLM](https://learning.postman.com/docs/sending-requests/authorization/ntlm-authentication/) authentication.' + ) + .optional(), + oauth1: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [OAuth1](https://learning.postman.com/docs/sending-requests/authorization/oauth-10/) authentication.' + ) + .optional(), + oauth2: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [OAuth2](https://learning.postman.com/docs/sending-requests/authorization/oauth-20/) authentication.' + ) + .optional(), + }) + .describe( + 'The [authorization type supported by Postman](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + .optional(), + protocolProfileBehavior: z + .object({ + strictSSL: z.boolean().describe('If true, enables certificate verification.').optional(), + followRedirects: z + .boolean() + .describe('If true, follow HTTP 3xx responses as redirects.') + .optional(), + maxRedirects: z + .number() + .describe('The maximum number of redirects to follow.') + .optional(), + disableBodyPruning: z + .boolean() + .describe( + 'If true, disables request body pruning for the GET, COPY, HEAD, PURGE, and UNLOCK methods.' + ) + .optional(), + disableUrlEncoding: z + .boolean() + .describe( + 'If true, disables the percent encoding of auth, path, query, and fragment URL segments.' + ) + .optional(), + disabledSystemHeaders: z + .object({ + 'cache-control': z.boolean().optional(), + 'postman-token': z.boolean().optional(), + 'content-type': z.boolean().optional(), + 'content-length': z.boolean().optional(), + 'accept-encoding': z.boolean().optional(), + connection: z.boolean().optional(), + host: z.boolean().optional(), + }) + .describe('Disable the system headers which are added implicitly.') + .optional(), + insecureHTTPParser: z + .boolean() + .describe('If true, uses an insecure HTTP parser that accepts invalid HTTP headers.') + .optional(), + followOriginalHttpMethod: z + .boolean() + .describe( + 'If true, redirects with the original HTTP method. Redirects with the GET HTTP method by default.' + ) + .optional(), + followAuthorizationHeader: z + .boolean() + .describe( + 'If true, retains the `authorization` header when a redirect happens to a different hostname.' + ) + .optional(), + protocolVersion: z + .enum(['http1', 'http2', 'auto']) + .describe( + 'The HTTP protocol version to use. Supports the `http1`, `http2`, and `auto` values.' + ) + .optional(), + removeRefererHeaderOnRedirect: z + .boolean() + .describe('If true, removes the `referer` header when a redirect happens.') + .optional(), + tlsPreferServerCiphers: z + .boolean() + .describe( + "If true, uses the server's cipher suite order instead of the client's during negotiation." + ) + .optional(), + tlsDisabledProtocols: z + .array(z.string()) + .describe('The SSL and TLS protocol versions to disable during negotiation.') + .optional(), + tlsCipherSelection: z + .array(z.string()) + .describe( + 'The order of cipher suites that the SSL server profile uses to establish a secure connection.' + ) + .optional(), + }) + .describe( + 'The [settings](https://learning.postman.com/docs/sending-requests/create-requests/request-settings/) used to alter the [Protocol Profile Behavior](https://github.com/postmanlabs/postman-runtime/blob/develop/docs/protocol-profile-behavior.md) of sending a request.' + ) + .optional(), + }) + .optional(), +}); +export const annotations = { + title: + 'Creates a collection using the [Postman Collection v2.1.0 schema format](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\n- If you do not include the \\`workspace\\` query parameter, the system creates the collection in your "My Workspace" workspace.\n- For a complete list of available property values for this endpoint, use the following references available in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html):\n - \\`info\\` object — Refer to the **Information** entry.\n - \\`item\\` object — Refer to the **Items** entry.\n- For all other possible values, refer to the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections`; + const query = new URLSearchParams(); + if (params.workspace !== undefined) query.set('workspace', String(params.workspace)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.collection !== undefined) bodyPayload.collection = params.collection; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/create_collection_comment.ts b/src/tools/create_collection_comment.ts new file mode 100644 index 0000000..0fae155 --- /dev/null +++ b/src/tools/create_collection_comment.ts @@ -0,0 +1,71 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'create-collection-comment'; +export const description = + 'Creates a comment on a collection. To create a reply on an existing comment, include the \\`threadId\\` property in the request body.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + body: z.string().describe('The contents of the comment.'), + threadId: z + .number() + .int() + .describe( + "The comment's thread ID. To create a reply on an existing comment, include this property." + ) + .optional(), + tags: z + .object({ + userName: z + .object({ + type: z.literal('user').describe('The `user` value.'), + id: z.number().int().describe("The user's ID."), + }) + .describe( + "An object that contains information about the tagged user. The object's name is the user's Postman username. For example, `@user-postman`." + ) + .optional(), + }) + .describe('Information about users tagged in the `body` comment.') + .optional(), +}); +export const annotations = { + title: + 'Creates a comment on a collection. To create a reply on an existing comment, include the \\`threadId\\` property in the request body.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/comments`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.body !== undefined) bodyPayload.body = params.body; + if (params.threadId !== undefined) bodyPayload.threadId = params.threadId; + if (params.tags !== undefined) bodyPayload.tags = params.tags; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/create_collection_folder.ts b/src/tools/create_collection_folder.ts new file mode 100644 index 0000000..06a96f9 --- /dev/null +++ b/src/tools/create_collection_folder.ts @@ -0,0 +1,55 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'create-collection-folder'; +export const description = + 'Creates a folder in a collection. For a complete list of properties, refer to the **Folder** entry in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\nYou can use this endpoint to to import requests and responses into a newly-created folder. To do this, include the \\`requests\\` field and the list of request objects in the request body. For more information, see the provided example.\n\n**Note:**\n\nIt is recommended that you pass the \\`name\\` property in the request body. If you do not, the system uses a null value. As a result, this creates a folder with a blank name.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's ID."), + name: z + .string() + .describe( + "The folder's name. It is recommended that you pass the `name` property in the request body. If you do not, the system uses a null value. As a result, this creates a folder with a blank name." + ) + .optional(), + folder: z.string().describe('The ID of a folder in which to create the folder.').optional(), +}); +export const annotations = { + title: + 'Creates a folder in a collection. For a complete list of properties, refer to the **Folder** entry in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\nYou can use this endpoint to to import requests and responses into a newly-created folder. To do this, include the \\`requests\\` field and the list of request objects in the request body. For more information, see the provided example.\n\n**Note:**\n\nIt is recommended that you pass the \\`name\\` property in the request body. If you do not, the system uses a null value. As a result, this creates a folder with a blank name.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/folders`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.name !== undefined) bodyPayload.name = params.name; + if (params.folder !== undefined) bodyPayload.folder = params.folder; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/create_collection_fork.ts b/src/tools/create_collection_fork.ts new file mode 100644 index 0000000..22b1420 --- /dev/null +++ b/src/tools/create_collection_fork.ts @@ -0,0 +1,50 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'create-collection-fork'; +export const description = + 'Creates a [fork](https://learning.postman.com/docs/collaborating-in-postman/version-control/#creating-a-fork) from an existing collection into a workspace.'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's ID."), + workspace: z.string().describe('The workspace ID in which to create the fork.'), + label: z.string().describe("The fork's label."), +}); +export const annotations = { + title: + 'Creates a [fork](https://learning.postman.com/docs/collaborating-in-postman/version-control/#creating-a-fork) from an existing collection into a workspace.', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/fork/${params.collectionId}`; + const query = new URLSearchParams(); + if (params.workspace !== undefined) query.set('workspace', String(params.workspace)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.label !== undefined) bodyPayload.label = params.label; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/create_collection_request.ts b/src/tools/create_collection_request.ts new file mode 100644 index 0000000..2adb004 --- /dev/null +++ b/src/tools/create_collection_request.ts @@ -0,0 +1,67 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'create-collection-request'; +export const description = + 'Creates a request in a collection. For a complete list of properties, refer to the **Request** entry in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\nIt is recommended that you pass the \\`name\\` property in the request body. If you do not, the system uses a null value. As a result, this creates a request with a blank name.\n'; +export const parameters = z.object({ + collectionId: z.string(), + folderId: z + .string() + .describe( + 'The folder ID in which to create the request. By default, the system will create the request at the collection level.' + ) + .optional(), + name: z + .string() + .describe( + "The request's name. It is recommended that you pass the `name` property in the request body. If you do not, the system uses a null value. As a result, this creates a request with a blank name." + ) + .optional(), + url: z.string().describe('The URL for the request.').optional(), + method: z.string().describe('The HTTP method for the request (e.g., POST, GET).').optional(), + body: z.record(z.any()).describe("The request's body.").optional(), +}); +export const annotations = { + title: + 'Creates a request in a collection. For a complete list of properties, refer to the **Request** entry in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\nIt is recommended that you pass the \\`name\\` property in the request body. If you do not, the system uses a null value. As a result, this creates a request with a blank name.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/requests`; + const query = new URLSearchParams(); + if (params.folderId !== undefined) query.set('folderId', String(params.folderId)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.name !== undefined) bodyPayload.name = params.name; + if (params.url !== undefined) bodyPayload.url = params.url; + if (params.method !== undefined) bodyPayload.method = params.method; + if (params.body !== undefined) bodyPayload.body = params.body; + if (params.collectionId !== undefined) bodyPayload.collectionId = params.collectionId; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/create_collection_response.ts b/src/tools/create_collection_response.ts new file mode 100644 index 0000000..0cd3d57 --- /dev/null +++ b/src/tools/create_collection_response.ts @@ -0,0 +1,55 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'create-collection-response'; +export const description = + 'Creates a request response in a collection. For a complete list of request body properties, refer to the **Response** entry in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\nIt is recommended that you pass the \\`name\\` property in the request body. If you do not, the system uses a null value. As a result, this creates a response with a blank name.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's ID."), + requestId: z.string().describe("The parent request's ID."), + name: z + .string() + .describe( + "The response's name. It is recommended that you pass the `name` property in the request body. If you do not, the system uses a null value. As a result, this creates a response with a blank name." + ) + .optional(), +}); +export const annotations = { + title: + 'Creates a request response in a collection. For a complete list of request body properties, refer to the **Response** entry in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\nIt is recommended that you pass the \\`name\\` property in the request body. If you do not, the system uses a null value. As a result, this creates a response with a blank name.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/responses`; + const query = new URLSearchParams(); + if (params.requestId !== undefined) query.set('requestId', String(params.requestId)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.name !== undefined) bodyPayload.name = params.name; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/create_environment.ts b/src/tools/create_environment.ts new file mode 100644 index 0000000..f02caf4 --- /dev/null +++ b/src/tools/create_environment.ts @@ -0,0 +1,64 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'create-environment'; +export const description = + 'Creates an environment.\n\n**Note:**\n\n- The request body size cannot exceed the maximum allowed size of 30MB.\n- If you receive an HTTP \\`411 Length Required\\` error response, manually pass the \\`Content-Length\\` header and its value in the request header.\n- If you do not include the \\`workspace\\` query parameter, the system creates the collection in your "My Workspace" workspace.\n'; +export const parameters = z.object({ + workspace: z.string().describe("The workspace's ID.").optional(), + environment: z + .object({ + name: z.string().describe("The environment's name."), + values: z + .array( + z.object({ + enabled: z.boolean().describe('If true, the variable is enabled.').optional(), + key: z.string().describe("The variable's name.").optional(), + value: z.string().describe("The variable's value.").optional(), + type: z.enum(['secret', 'default', 'any']).describe('The variable type.').optional(), + }) + ) + .describe("Information about the environment's variables.") + .optional(), + }) + .optional(), +}); +export const annotations = { + title: + 'Creates an environment.\n\n**Note:**\n\n- The request body size cannot exceed the maximum allowed size of 30MB.\n- If you receive an HTTP \\`411 Length Required\\` error response, manually pass the \\`Content-Length\\` header and its value in the request header.\n- If you do not include the \\`workspace\\` query parameter, the system creates the collection in your "My Workspace" workspace.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/environments`; + const query = new URLSearchParams(); + if (params.workspace !== undefined) query.set('workspace', String(params.workspace)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.environment !== undefined) bodyPayload.environment = params.environment; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/create_folder_comment.ts b/src/tools/create_folder_comment.ts new file mode 100644 index 0000000..7e46c74 --- /dev/null +++ b/src/tools/create_folder_comment.ts @@ -0,0 +1,72 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'create-folder-comment'; +export const description = + 'Creates a comment on a folder. To create a reply on an existing comment, include the \\`threadId\\` property in the request body.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + folderId: z.string().describe("The folder's unique ID."), + body: z.string().describe('The contents of the comment.'), + threadId: z + .number() + .int() + .describe( + "The comment's thread ID. To create a reply on an existing comment, include this property." + ) + .optional(), + tags: z + .object({ + userName: z + .object({ + type: z.literal('user').describe('The `user` value.'), + id: z.number().int().describe("The user's ID."), + }) + .describe( + "An object that contains information about the tagged user. The object's name is the user's Postman username. For example, `@user-postman`." + ) + .optional(), + }) + .describe('Information about users tagged in the `body` comment.') + .optional(), +}); +export const annotations = { + title: + 'Creates a comment on a folder. To create a reply on an existing comment, include the \\`threadId\\` property in the request body.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/folders/${params.folderId}/comments`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.body !== undefined) bodyPayload.body = params.body; + if (params.threadId !== undefined) bodyPayload.threadId = params.threadId; + if (params.tags !== undefined) bodyPayload.tags = params.tags; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/create_mock.ts b/src/tools/create_mock.ts new file mode 100644 index 0000000..a9d2fcb --- /dev/null +++ b/src/tools/create_mock.ts @@ -0,0 +1,64 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'create-mock'; +export const description = + 'Creates a mock server in a collection.\n\n**Note:**\n\n- If you do not include the \\`workspaceId\\` query parameter, the system creates the mock server in your [Personal\nworkspace](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/creating-workspaces/).\n- You cannot create mocks for collections added to an API definition.\n'; +export const parameters = z.object({ + workspaceId: z.string().describe("The workspace's ID.").optional(), + mock: z + .object({ + collection: z.string().describe("The unique ID of the mock's associated collection."), + environment: z + .string() + .describe("The unique ID of the mock's associated environment.") + .optional(), + name: z.string().describe("The mock server's name.").optional(), + private: z + .boolean() + .describe( + 'If true, the mock server is set private. By default, mock servers are public and can receive requests from anyone and anywhere.' + ) + .default(false), + }) + .optional(), +}); +export const annotations = { + title: + 'Creates a mock server in a collection.\n\n**Note:**\n\n- If you do not include the \\`workspaceId\\` query parameter, the system creates the mock server in your [Personal\nworkspace](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/creating-workspaces/).\n- You cannot create mocks for collections added to an API definition.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/mocks`; + const query = new URLSearchParams(); + if (params.workspaceId !== undefined) query.set('workspaceId', String(params.workspaceId)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.mock !== undefined) bodyPayload.mock = params.mock; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/create_monitor.ts b/src/tools/create_monitor.ts new file mode 100644 index 0000000..8a4a87a --- /dev/null +++ b/src/tools/create_monitor.ts @@ -0,0 +1,165 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'create-monitor'; +export const description = + 'Creates a monitor.\n\n**Note:**\n\n- You cannot create monitors for collections added to an API definition.\n- If you do not pass the \\`workspace\\` parameter, the monitor is created in your personal workspace.\n'; +export const parameters = z.object({ + workspace: z.string().describe("The workspace's ID.").optional(), + monitor: z + .object({ + name: z.string().describe("The monitor's name."), + active: z + .boolean() + .describe('If true, the monitor is active and makes calls to the specified URL.') + .default(true), + notificationLimit: z + .number() + .gte(1) + .lte(99) + .describe('Stop email notifications after the given number consecutive failures.') + .optional(), + collection: z.string().describe("The unique ID of the monitor's associated collection."), + environment: z + .string() + .describe("The unique ID of the monitor's associated environment.") + .optional(), + retry: z + .object({ + attempts: z + .number() + .gte(1) + .lte(2) + .describe( + 'The number of times to reattempt a monitor run if it fails or errors. This may impact your [monitor usage](https://learning.postman.com/docs/monitoring-your-api/monitor-usage/#view-monitor-usage).' + ) + .optional(), + }) + .optional(), + options: z + .object({ + followRedirects: z.boolean().describe('If true, follow redirects enabled.').optional(), + requestDelay: z + .number() + .gte(1) + .lte(900000) + .describe("The monitor's request delay value, in milliseconds.") + .optional(), + requestTimeout: z + .number() + .gte(1) + .lte(900000) + .describe("The monitor's request timeout value, in milliseconds.") + .optional(), + strictSSL: z.boolean().describe('If true, strict SSL enabled.').optional(), + }) + .describe("Information about the monitor's option settings.") + .optional(), + schedule: z + .object({ + cron: z + .string() + .describe( + 'The cron expression that defines when the monitor runs. Use standard five-field POSIX cron syntax.\n' + ) + .optional(), + timezone: z + .string() + .describe( + "The monitor's [timezone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)." + ) + .optional(), + }) + .describe("Information about the monitor's schedule."), + distribution: z + .array( + z.object({ + region: z + .enum([ + 'us-east', + 'us-west', + 'ap-southeast', + 'ca-central', + 'eu-central', + 'sa-east', + 'uk', + 'us-east-staticip', + 'us-west-staticip', + ]) + .describe('The assigned distribution region.') + .optional(), + }) + ) + .describe( + "A list of the monitor's [geographic regions](https://learning.postman.com/docs/monitoring-your-api/setting-up-monitor/#add-regions)." + ) + .optional(), + notifications: z + .object({ + onError: z + .array( + z.object({ + email: z + .string() + .email() + .describe('The email address of the user to notify on monitor error.') + .optional(), + }) + ) + .optional(), + onFailure: z + .array( + z.object({ + email: z + .string() + .email() + .describe('The email address of the user to notify on monitor failure.') + .optional(), + }) + ) + .optional(), + }) + .describe("Information about the monitor's notification settings.") + .optional(), + }) + .optional(), +}); +export const annotations = { + title: + 'Creates a monitor.\n\n**Note:**\n\n- You cannot create monitors for collections added to an API definition.\n- If you do not pass the \\`workspace\\` parameter, the monitor is created in your personal workspace.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/monitors`; + const query = new URLSearchParams(); + if (params.workspace !== undefined) query.set('workspace', String(params.workspace)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.monitor !== undefined) bodyPayload.monitor = params.monitor; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/create_request_comment.ts b/src/tools/create_request_comment.ts new file mode 100644 index 0000000..074c4e0 --- /dev/null +++ b/src/tools/create_request_comment.ts @@ -0,0 +1,76 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'create-request-comment'; +export const description = + "The request ID must contain the team ID as a prefix, in \\`teamId-requestId\\` format.\n\nFor example, if you're creating a comment on collection ID \\`24585957-7b2c98f7-30db-4b67-8685-0079f48a0947\\` (note on the prefix), and\nthe collection request's ID is \\`2c450b59-9bbf-729b-6ac0-f92535a7c336\\`, then the \\`{requestId}\\` must be \\`24585957-2c450b59-9bbf-729b-6ac0-f92535a7c336\\`.\n"; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + requestId: z + .string() + .describe( + "The request ID must contain the team ID as a prefix, in `teamId-requestId` format.\n\nFor example, if you're creating a comment on collection ID `24585957-7b2c98f7-30db-4b67-8685-0079f48a0947` (note on the prefix), and\nthe collection request's ID is `2c450b59-9bbf-729b-6ac0-f92535a7c336`, then the `{requestId}` must be `24585957-2c450b59-9bbf-729b-6ac0-f92535a7c336`.\n" + ), + body: z.string().describe('The contents of the comment.'), + threadId: z + .number() + .int() + .describe( + "The comment's thread ID. To create a reply on an existing comment, include this property." + ) + .optional(), + tags: z + .object({ + userName: z + .object({ + type: z.literal('user').describe('The `user` value.'), + id: z.number().int().describe("The user's ID."), + }) + .describe( + "An object that contains information about the tagged user. The object's name is the user's Postman username. For example, `@user-postman`." + ) + .optional(), + }) + .describe('Information about users tagged in the `body` comment.') + .optional(), +}); +export const annotations = { + title: + "The request ID must contain the team ID as a prefix, in \\`teamId-requestId\\` format.\n\nFor example, if you're creating a comment on collection ID \\`24585957-7b2c98f7-30db-4b67-8685-0079f48a0947\\` (note on the prefix), and\nthe collection request's ID is \\`2c450b59-9bbf-729b-6ac0-f92535a7c336\\`, then the \\`{requestId}\\` must be \\`24585957-2c450b59-9bbf-729b-6ac0-f92535a7c336\\`.\n", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/requests/${params.requestId}/comments`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.body !== undefined) bodyPayload.body = params.body; + if (params.threadId !== undefined) bodyPayload.threadId = params.threadId; + if (params.tags !== undefined) bodyPayload.tags = params.tags; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/create_response_comment.ts b/src/tools/create_response_comment.ts new file mode 100644 index 0000000..95c5b3f --- /dev/null +++ b/src/tools/create_response_comment.ts @@ -0,0 +1,72 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'create-response-comment'; +export const description = + 'Creates a comment on a response. To create a reply on an existing comment, include the \\`threadId\\` property in the request body.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + responseId: z.string().describe("The response's unique ID."), + body: z.string().describe('The contents of the comment.'), + threadId: z + .number() + .int() + .describe( + "The comment's thread ID. To create a reply on an existing comment, include this property." + ) + .optional(), + tags: z + .object({ + userName: z + .object({ + type: z.literal('user').describe('The `user` value.'), + id: z.number().int().describe("The user's ID."), + }) + .describe( + "An object that contains information about the tagged user. The object's name is the user's Postman username. For example, `@user-postman`." + ) + .optional(), + }) + .describe('Information about users tagged in the `body` comment.') + .optional(), +}); +export const annotations = { + title: + 'Creates a comment on a response. To create a reply on an existing comment, include the \\`threadId\\` property in the request body.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/responses/${params.responseId}/comments`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.body !== undefined) bodyPayload.body = params.body; + if (params.threadId !== undefined) bodyPayload.threadId = params.threadId; + if (params.tags !== undefined) bodyPayload.tags = params.tags; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/create_spec.ts b/src/tools/create_spec.ts new file mode 100644 index 0000000..4931eac --- /dev/null +++ b/src/tools/create_spec.ts @@ -0,0 +1,62 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'create-spec'; +export const description = + "Creates an API specification in Postman's [Spec Hub](https://learning.postman.com/docs/design-apis/specifications/overview/).\n\n**Note:**\n- Postman supports OpenAPI 3.0 and AsyncAPI 2.0 specifications.\n- This endpoint does not yet support multiple files.\n"; +export const parameters = z.object({ + workspaceId: z.string().describe("The workspace's ID."), + name: z.string().describe("The specification's name."), + type: z.enum(['OPENAPI:3.0', 'ASYNCAPI:2.0']).describe("The specification's type."), + files: z + .array( + z.object({ + path: z + .string() + .describe("The file's path. Accepts the `index.json` or `index.yaml` value."), + content: z.string().describe("The file's stringified contents."), + }) + ) + .describe("A list of the specification's files and their contents."), +}); +export const annotations = { + title: + "Creates an API specification in Postman's [Spec Hub](https://learning.postman.com/docs/design-apis/specifications/overview/).\n\n**Note:**\n- Postman supports OpenAPI 3.0 and AsyncAPI 2.0 specifications.\n- This endpoint does not yet support multiple files.\n", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/specs`; + const query = new URLSearchParams(); + if (params.workspaceId !== undefined) query.set('workspaceId', String(params.workspaceId)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.name !== undefined) bodyPayload.name = params.name; + if (params.type !== undefined) bodyPayload.type = params.type; + if (params.files !== undefined) bodyPayload.files = params.files; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/create_update_spec_file.ts b/src/tools/create_update_spec_file.ts new file mode 100644 index 0000000..c6e495b --- /dev/null +++ b/src/tools/create_update_spec_file.ts @@ -0,0 +1,47 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'create-update-spec-file'; +export const description = "Creates or updates an API specification's file.\n"; +export const parameters = z.object({ + specId: z.string().describe("The spec's ID."), + filePath: z.string().describe('The path to the file.'), + content: z.string().describe("The specification's stringified contents."), +}); +export const annotations = { + title: "Creates or updates an API specification's file.\n", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/specs/${params.specId}/files/${params.filePath}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.content !== undefined) bodyPayload.content = params.content; + const result = await fetchPostmanAPI(url, { + method: 'PATCH', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/create_workspace.ts b/src/tools/create_workspace.ts new file mode 100644 index 0000000..b72a4e2 --- /dev/null +++ b/src/tools/create_workspace.ts @@ -0,0 +1,58 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'create-workspace'; +export const description = + 'Creates a new [workspace](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/creating-workspaces/).\n\n**Note:**\n\n- This endpoint returns a 403 \\`Forbidden\\` response if the user does not have permission to create workspaces. [Admins and Super Admins](https://learning.postman.com/docs/collaborating-in-postman/roles-and-permissions/#team-roles) can configure workspace permissions to restrict users and/or user groups from creating workspaces or require approvals for the creation of team workspaces.\n- There are rate limits when publishing public workspaces.\n- Public team workspace names must be unique.\n\n### Important\n\nWe deprecated linking collections or environments between workspaces. We do not recommend that you do this.\n\nIf you have a linked collection or environment, note the following:\n- The endpoint does not create a clone of a collection or environment.\n- Any changes you make to a linked collection or environment changes them in all workspaces.\n- If you delete a collection or environment linked between workspaces, the system deletes it in all the workspaces.\n'; +export const parameters = z.object({ + workspace: z + .object({ + name: z.string().describe("The workspace's name."), + type: z + .enum(['personal', 'private', 'public', 'team', 'partner']) + .describe( + 'The type of workspace:\n- `personal`\n- `private` — Private workspaces are available on Postman [**Professional** and **Enterprise** plans](https://www.postman.com/pricing).\n- `public`\n- `team`\n- `partner` — [Partner Workspaces](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/partner-workspaces/) are available on Postman [**Professional** and **Enterprise** plans](https://www.postman.com/pricing)).\n' + ), + description: z.string().describe("The workspace's description.").optional(), + }) + .describe('Information about the workspace.') + .optional(), +}); +export const annotations = { + title: + 'Creates a new [workspace](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/creating-workspaces/).\n\n**Note:**\n\n- This endpoint returns a 403 \\`Forbidden\\` response if the user does not have permission to create workspaces. [Admins and Super Admins](https://learning.postman.com/docs/collaborating-in-postman/roles-and-permissions/#team-roles) can configure workspace permissions to restrict users and/or user groups from creating workspaces or require approvals for the creation of team workspaces.\n- There are rate limits when publishing public workspaces.\n- Public team workspace names must be unique.\n\n### Important\n\nWe deprecated linking collections or environments between workspaces. We do not recommend that you do this.\n\nIf you have a linked collection or environment, note the following:\n- The endpoint does not create a clone of a collection or environment.\n- Any changes you make to a linked collection or environment changes them in all workspaces.\n- If you delete a collection or environment linked between workspaces, the system deletes it in all the workspaces.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/workspaces`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.workspace !== undefined) bodyPayload.workspace = params.workspace; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/delete_api_collection_comment.ts b/src/tools/delete_api_collection_comment.ts new file mode 100644 index 0000000..dcdd977 --- /dev/null +++ b/src/tools/delete_api_collection_comment.ts @@ -0,0 +1,45 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'delete-api-collection-comment'; +export const description = + "Deletes a comment from an API's collection. On success, this returns an HTTP \\`204 No Content\\` response.\n\n**Note:**\n\nDeleting the first comment of a thread deletes all the comments in the thread.\n"; +export const parameters = z.object({ + apiId: z.string().describe("The API's ID."), + collectionId: z.string().describe("The collection's unique ID."), + commentId: z.number().int().describe("The comment's ID."), +}); +export const annotations = { + title: + "Deletes a comment from an API's collection. On success, this returns an HTTP \\`204 No Content\\` response.\n\n**Note:**\n\nDeleting the first comment of a thread deletes all the comments in the thread.\n", + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/apis/${params.apiId}/collections/${params.collectionId}/comments/${params.commentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/delete_collection.ts b/src/tools/delete_collection.ts new file mode 100644 index 0000000..5e4c257 --- /dev/null +++ b/src/tools/delete_collection.ts @@ -0,0 +1,39 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'delete-collection'; +export const description = 'Deletes a collection.'; +export const parameters = z.object({ collectionId: z.string().describe("The collection's ID.") }); +export const annotations = { + title: 'Deletes a collection.', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/delete_collection_comment.ts b/src/tools/delete_collection_comment.ts new file mode 100644 index 0000000..d3c095a --- /dev/null +++ b/src/tools/delete_collection_comment.ts @@ -0,0 +1,44 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'delete-collection-comment'; +export const description = + 'Deletes a comment from a collection. On success, this returns an HTTP \\`204 No Content\\` response.\n\n**Note:**\n\nDeleting the first comment of a thread deletes all the comments in the thread.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + commentId: z.number().int().describe("The comment's ID."), +}); +export const annotations = { + title: + 'Deletes a comment from a collection. On success, this returns an HTTP \\`204 No Content\\` response.\n\n**Note:**\n\nDeleting the first comment of a thread deletes all the comments in the thread.\n', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/comments/${params.commentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/delete_collection_folder.ts b/src/tools/delete_collection_folder.ts new file mode 100644 index 0000000..2dfac82 --- /dev/null +++ b/src/tools/delete_collection_folder.ts @@ -0,0 +1,42 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'delete-collection-folder'; +export const description = 'Deletes a folder in a collection.'; +export const parameters = z.object({ + folderId: z.string().describe("The folder's ID."), + collectionId: z.string().describe("The collection's ID."), +}); +export const annotations = { + title: 'Deletes a folder in a collection.', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/folders/${params.folderId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/delete_collection_request.ts b/src/tools/delete_collection_request.ts new file mode 100644 index 0000000..7bb6894 --- /dev/null +++ b/src/tools/delete_collection_request.ts @@ -0,0 +1,42 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'delete-collection-request'; +export const description = 'Deletes a request in a collection.'; +export const parameters = z.object({ + requestId: z.string().describe("The request's ID."), + collectionId: z.string().describe("The collection's ID."), +}); +export const annotations = { + title: 'Deletes a request in a collection.', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/requests/${params.requestId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/delete_collection_response.ts b/src/tools/delete_collection_response.ts new file mode 100644 index 0000000..1fe1dbd --- /dev/null +++ b/src/tools/delete_collection_response.ts @@ -0,0 +1,42 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'delete-collection-response'; +export const description = 'Deletes a response in a collection.'; +export const parameters = z.object({ + responseId: z.string().describe("The response's ID."), + collectionId: z.string().describe("The collection's ID."), +}); +export const annotations = { + title: 'Deletes a response in a collection.', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/responses/${params.responseId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/delete_environment.ts b/src/tools/delete_environment.ts new file mode 100644 index 0000000..146696b --- /dev/null +++ b/src/tools/delete_environment.ts @@ -0,0 +1,39 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'delete-environment'; +export const description = 'Deletes an environment.'; +export const parameters = z.object({ environmentId: z.string().describe("The environment's ID.") }); +export const annotations = { + title: 'Deletes an environment.', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/environments/${params.environmentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/delete_folder_comment.ts b/src/tools/delete_folder_comment.ts new file mode 100644 index 0000000..eb06f24 --- /dev/null +++ b/src/tools/delete_folder_comment.ts @@ -0,0 +1,45 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'delete-folder-comment'; +export const description = + 'Deletes a comment from a folder. On success, this returns an HTTP \\`204 No Content\\` response.\n\n**Note:**\n\nDeleting the first comment of a thread deletes all the comments in the thread.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + folderId: z.string().describe("The folder's unique ID."), + commentId: z.number().int().describe("The comment's ID."), +}); +export const annotations = { + title: + 'Deletes a comment from a folder. On success, this returns an HTTP \\`204 No Content\\` response.\n\n**Note:**\n\nDeleting the first comment of a thread deletes all the comments in the thread.\n', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/folders/${params.folderId}/comments/${params.commentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/delete_mock.ts b/src/tools/delete_mock.ts new file mode 100644 index 0000000..06741ef --- /dev/null +++ b/src/tools/delete_mock.ts @@ -0,0 +1,39 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'delete-mock'; +export const description = 'Deletes a mock server.'; +export const parameters = z.object({ mockId: z.string().describe("The mock's ID.") }); +export const annotations = { + title: 'Deletes a mock server.', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/mocks/${params.mockId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/delete_monitor.ts b/src/tools/delete_monitor.ts new file mode 100644 index 0000000..dfbcd5e --- /dev/null +++ b/src/tools/delete_monitor.ts @@ -0,0 +1,39 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'delete-monitor'; +export const description = 'Deletes a monitor.'; +export const parameters = z.object({ monitorId: z.string().describe("The monitor's ID.") }); +export const annotations = { + title: 'Deletes a monitor.', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/monitors/${params.monitorId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/delete_pan_element_or_folder.ts b/src/tools/delete_pan_element_or_folder.ts new file mode 100644 index 0000000..35e7b63 --- /dev/null +++ b/src/tools/delete_pan_element_or_folder.ts @@ -0,0 +1,48 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'delete-pan-element-or-folder'; +export const description = + "Removes an element or delete a folder from your team's [Private API Network](https://learning.postman.com/docs/collaborating-in-postman/adding-private-network/).\n\n**Note:**\n\nRemoving an API, collection, or workspace element does not delete it. It only removes it from the Private API Network folder.\n"; +export const parameters = z.object({ + elementId: z + .string() + .describe( + "The element's ID or UUID. For Postman Collections you must pass the collection's UID (`userId`-`collectionId`) value." + ), + elementType: z.enum(['api', 'folder', 'collection', 'workspace']).describe('The element type.'), +}); +export const annotations = { + title: + "Removes an element or delete a folder from your team's [Private API Network](https://learning.postman.com/docs/collaborating-in-postman/adding-private-network/).\n\n**Note:**\n\nRemoving an API, collection, or workspace element does not delete it. It only removes it from the Private API Network folder.\n", + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/network/private/${params.elementType}/${params.elementId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/delete_request_comment.ts b/src/tools/delete_request_comment.ts new file mode 100644 index 0000000..f816580 --- /dev/null +++ b/src/tools/delete_request_comment.ts @@ -0,0 +1,45 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'delete-request-comment'; +export const description = + 'Deletes a comment from a request. On success, this returns an HTTP \\`204 No Content\\` response.\n\n**Note:**\n\nDeleting the first comment of a thread deletes all the comments in the thread.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + requestId: z.string().describe("The request's unique ID."), + commentId: z.number().int().describe("The comment's ID."), +}); +export const annotations = { + title: + 'Deletes a comment from a request. On success, this returns an HTTP \\`204 No Content\\` response.\n\n**Note:**\n\nDeleting the first comment of a thread deletes all the comments in the thread.\n', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/requests/${params.requestId}/comments/${params.commentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/delete_response_comment.ts b/src/tools/delete_response_comment.ts new file mode 100644 index 0000000..0206ed2 --- /dev/null +++ b/src/tools/delete_response_comment.ts @@ -0,0 +1,45 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'delete-response-comment'; +export const description = + 'Deletes a comment from a response. On success, this returns an HTTP \\`204 No Content\\` response.\n\n**Note:**\n\nDeleting the first comment of a thread deletes all the comments in the thread.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + responseId: z.string().describe("The response's unique ID."), + commentId: z.number().int().describe("The comment's ID."), +}); +export const annotations = { + title: + 'Deletes a comment from a response. On success, this returns an HTTP \\`204 No Content\\` response.\n\n**Note:**\n\nDeleting the first comment of a thread deletes all the comments in the thread.\n', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/responses/${params.responseId}/comments/${params.commentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/delete_spec.ts b/src/tools/delete_spec.ts new file mode 100644 index 0000000..cc18b7f --- /dev/null +++ b/src/tools/delete_spec.ts @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'delete-spec'; +export const description = + 'Deletes an API specification. On success, this returns an HTTP \\`204 No Content\\` response.'; +export const parameters = z.object({ specId: z.string().describe("The spec's ID.") }); +export const annotations = { + title: + 'Deletes an API specification. On success, this returns an HTTP \\`204 No Content\\` response.', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/specs/${params.specId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/delete_workspace.ts b/src/tools/delete_workspace.ts new file mode 100644 index 0000000..26ccf94 --- /dev/null +++ b/src/tools/delete_workspace.ts @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'delete-workspace'; +export const description = + 'Deletes an existing workspace.\n\n### Important\n\nIf you delete a workspace that has a linked collection or environment with another workspace, this will delete the collection and environment in all workspaces.\n'; +export const parameters = z.object({ workspaceId: z.string().describe("The workspace's ID.") }); +export const annotations = { + title: + 'Deletes an existing workspace.\n\n### Important\n\nIf you delete a workspace that has a linked collection or environment with another workspace, this will delete the collection and environment in all workspaces.\n', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/workspaces/${params.workspaceId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/generate_collection.ts b/src/tools/generate_collection.ts new file mode 100644 index 0000000..f150e4e --- /dev/null +++ b/src/tools/generate_collection.ts @@ -0,0 +1,105 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'generate-collection'; +export const description = + 'Creates a collection from the given API specification. The response contains a polling link to the task status.'; +export const parameters = z.object({ + specId: z.string().describe("The spec's ID."), + elementType: z.literal('collection').describe('The `collection` element type.'), + name: z.string().describe("The generated collection's name.").optional(), + options: z + .object({ + requestNameSource: z + .enum(['Fallback', 'URL']) + .describe( + "Determines how the generated collection's requests are named. If the `Fallback` value is passed, then the request is named after one of the following values in the schema:\n- `summary`\n- `operationId`\n- `description`\n- `url`\n" + ) + .default('Fallback'), + indentCharacter: z + .enum(['Tab', 'Space']) + .describe('The option for setting the indentation character type.') + .default('Space'), + parametersResolution: z + .enum(['Schema', 'Example']) + .describe( + "Whether to generate the request and response parameters based on the specification or the specification's examples." + ) + .default('Schema'), + folderStrategy: z + .enum(['Paths', 'Tags']) + .describe( + "Whether to create folders based on the specification's `paths` or `tags` properties." + ) + .default('Paths'), + includeAuthInfoInExample: z + .boolean() + .describe('If true, include the authentication parameters in the example request.') + .default(true), + enableOptionalParameters: z + .boolean() + .describe('If true, enables optional parameters in the collection and its requests.') + .default(true), + keepImplicitHeaders: z + .boolean() + .describe( + 'If true, keep the implicit headers from the OpenAPI specification, which are removed by default.' + ) + .default(false), + includeDeprecated: z + .boolean() + .describe( + 'If true, includes all deprecated operations, parameters, and properties in generated collection.' + ) + .default(true), + alwaysInheritAuthentication: z + .boolean() + .describe( + 'Whether authentication details should be included in all requests, or always inherited from the collection.' + ) + .default(false), + }) + .describe( + "The advanced creation options and their values. For more details, see Postman's [OpenAPI to Postman Collection Converter OPTIONS documentation](https://github.com/postmanlabs/openapi-to-postman/blob/develop/OPTIONS.md). These properties are case-sensitive." + ) + .optional(), +}); +export const annotations = { + title: + 'Creates a collection from the given API specification. The response contains a polling link to the task status.', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/specs/${params.specId}/generations/${params.elementType}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.name !== undefined) bodyPayload.name = params.name; + if (params.options !== undefined) bodyPayload.options = params.options; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/generate_spec_from_collection.ts b/src/tools/generate_spec_from_collection.ts new file mode 100644 index 0000000..fa01bd8 --- /dev/null +++ b/src/tools/generate_spec_from_collection.ts @@ -0,0 +1,53 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'generate-spec-from-collection'; +export const description = + 'Generates an API specification for the given collection. The response contains a polling link to the task status.'; +export const parameters = z.object({ + collectionUid: z.string().describe("The collection's unique ID."), + elementType: z.literal('spec').describe('The `spec` value.'), + name: z.string().describe("The API specification's name.").optional(), + type: z.literal('OPENAPI:3.0').describe("The specification's type.").optional(), + format: z.enum(['JSON', 'YAML']).describe('The format of the API specification.').optional(), +}); +export const annotations = { + title: + 'Generates an API specification for the given collection. The response contains a polling link to the task status.', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionUid}/generations/${params.elementType}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.name !== undefined) bodyPayload.name = params.name; + if (params.type !== undefined) bodyPayload.type = params.type; + if (params.format !== undefined) bodyPayload.format = params.format; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_all_elements_and_folders.ts b/src/tools/get_all_elements_and_folders.ts new file mode 100644 index 0000000..a07f6d2 --- /dev/null +++ b/src/tools/get_all_elements_and_folders.ts @@ -0,0 +1,133 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-all-elements-and-folders'; +export const description = + "Gets information about the folders and their elements added to your team's [Private API Network](https://learning.postman.com/docs/collaborating-in-postman/adding-private-network/).\n\n**Note:**\n\nThe \\`limit\\` and \\`offset\\` parameters are separately applied to elements and folders. For example, if you query a \\`limit\\` value of \\`10\\` and an \\`offset\\` value \\`0\\`, the endpoint returns 10 elements and 10 folders for a total of 20 items. The \\`totalCount\\` property in the \\`meta\\` response is the total count of both elements and folders.\n"; +export const parameters = z.object({ + since: z + .string() + .datetime({ offset: true }) + .describe( + 'Return only results created since the given time, in [ISO 8601](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) format. This value cannot be later than the `until` value.' + ) + .optional(), + until: z + .string() + .datetime({ offset: true }) + .describe( + 'Return only results created until this given time, in [ISO 8601](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) format. This value cannot be earlier than the `since` value.' + ) + .optional(), + addedBy: z + .number() + .int() + .describe('Return only elements published by the given user ID.') + .optional(), + name: z + .string() + .describe( + 'Return only elements whose name includes the given value. Matching is not case-sensitive.' + ) + .optional(), + summary: z + .string() + .describe( + 'Return only elements whose summary includes the given value. Matching is not case-sensitive.' + ) + .optional(), + description: z + .string() + .describe( + 'Return only elements whose description includes the given value. Matching is not case-sensitive.' + ) + .optional(), + sort: z + .enum(['createdAt', 'updatedAt']) + .describe( + 'Sort the results by the given value. If you use this query parameter, you must also use the `direction` parameter.' + ) + .optional(), + direction: z + .enum(['asc', 'desc']) + .describe( + 'Sort in ascending (`asc`) or descending (`desc`) order. Matching is not case-sensitive. If you use this query parameter, you must also use the `sort` parameter.' + ) + .optional(), + createdBy: z + .number() + .int() + .describe('Return only results created by the given user ID.') + .optional(), + offset: z + .number() + .int() + .describe('The zero-based offset of the first item to return.') + .default(0), + limit: z + .number() + .int() + .describe( + 'The maximum number of elements to return. If the value exceeds the maximum value of `1000`, then the system uses the `1000` value.' + ) + .default(1000), + parentFolderId: z + .number() + .int() + .describe( + "Return the folders and elements in a specific folder. If this value is `0`, then the endpoint only returns the root folder's elements." + ) + .default(0), + type: z + .enum(['api', 'folder', 'collection', 'workspace']) + .describe('Filter by the element type.') + .optional(), +}); +export const annotations = { + title: + "Gets information about the folders and their elements added to your team's [Private API Network](https://learning.postman.com/docs/collaborating-in-postman/adding-private-network/).\n\n**Note:**\n\nThe \\`limit\\` and \\`offset\\` parameters are separately applied to elements and folders. For example, if you query a \\`limit\\` value of \\`10\\` and an \\`offset\\` value \\`0\\`, the endpoint returns 10 elements and 10 folders for a total of 20 items. The \\`totalCount\\` property in the \\`meta\\` response is the total count of both elements and folders.\n", + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/network/private`; + const query = new URLSearchParams(); + if (params.since !== undefined) query.set('since', String(params.since)); + if (params.until !== undefined) query.set('until', String(params.until)); + if (params.addedBy !== undefined) query.set('addedBy', String(params.addedBy)); + if (params.name !== undefined) query.set('name', String(params.name)); + if (params.summary !== undefined) query.set('summary', String(params.summary)); + if (params.description !== undefined) query.set('description', String(params.description)); + if (params.sort !== undefined) query.set('sort', String(params.sort)); + if (params.direction !== undefined) query.set('direction', String(params.direction)); + if (params.createdBy !== undefined) query.set('createdBy', String(params.createdBy)); + if (params.offset !== undefined) query.set('offset', String(params.offset)); + if (params.limit !== undefined) query.set('limit', String(params.limit)); + if (params.parentFolderId !== undefined) + query.set('parentFolderId', String(params.parentFolderId)); + if (params.type !== undefined) query.set('type', String(params.type)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_all_pan_add_element_requests.ts b/src/tools/get_all_pan_add_element_requests.ts new file mode 100644 index 0000000..bf5e1c8 --- /dev/null +++ b/src/tools/get_all_pan_add_element_requests.ts @@ -0,0 +1,106 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-all-pan-add-element-requests'; +export const description = + "Gets a list requests to add elements to your team's [Private API Network](https://learning.postman.com/docs/collaborating-in-postman/adding-private-network/)."; +export const parameters = z.object({ + since: z + .string() + .datetime({ offset: true }) + .describe( + 'Return only results created since the given time, in [ISO 8601](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) format. This value cannot be later than the `until` value. To use time-numoffset format, you must use `%2B` URL-encoding for the `+` character.' + ) + .optional(), + until: z + .string() + .datetime({ offset: true }) + .describe( + 'Return only results created until this given time, in [ISO 8601](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) format. This value cannot be earlier than the `since` value. To use time-numoffset format, you must use `%2B` URL-encoding for the `+` character.' + ) + .optional(), + requestedBy: z + .number() + .int() + .describe("Return a user's element requests by their user ID.") + .optional(), + type: z + .enum(['api', 'folder', 'collection', 'workspace']) + .describe('Filter by the element type.') + .optional(), + status: z.enum(['pending', 'denied']).describe('Filter by the request status.').optional(), + name: z + .string() + .describe( + 'Return only elements whose name includes the given value. Matching is not case-sensitive.' + ) + .optional(), + sort: z + .enum(['createdAt', 'updatedAt']) + .describe( + 'Sort the results by the given value. If you use this query parameter, you must also use the `direction` parameter.' + ) + .optional(), + direction: z + .enum(['asc', 'desc']) + .describe( + 'Sort in ascending (`asc`) or descending (`desc`) order. Matching is not case-sensitive. If you use this query parameter, you must also use the `sort` parameter.' + ) + .optional(), + offset: z + .number() + .int() + .describe('The zero-based offset of the first item to return.') + .default(0), + limit: z + .number() + .int() + .describe( + 'The maximum number of elements to return. If the value exceeds the maximum value of `1000`, then the system uses the `1000` value.' + ) + .default(1000), +}); +export const annotations = { + title: + "Gets a list requests to add elements to your team's [Private API Network](https://learning.postman.com/docs/collaborating-in-postman/adding-private-network/).", + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/network/private/network-entity/request/all`; + const query = new URLSearchParams(); + if (params.since !== undefined) query.set('since', String(params.since)); + if (params.until !== undefined) query.set('until', String(params.until)); + if (params.requestedBy !== undefined) query.set('requestedBy', String(params.requestedBy)); + if (params.type !== undefined) query.set('type', String(params.type)); + if (params.status !== undefined) query.set('status', String(params.status)); + if (params.name !== undefined) query.set('name', String(params.name)); + if (params.sort !== undefined) query.set('sort', String(params.sort)); + if (params.direction !== undefined) query.set('direction', String(params.direction)); + if (params.offset !== undefined) query.set('offset', String(params.offset)); + if (params.limit !== undefined) query.set('limit', String(params.limit)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_all_specs.ts b/src/tools/get_all_specs.ts new file mode 100644 index 0000000..48c8ab2 --- /dev/null +++ b/src/tools/get_all_specs.ts @@ -0,0 +1,55 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-all-specs'; +export const description = 'Gets all API specifications in a workspace.'; +export const parameters = z.object({ + workspaceId: z.string().describe("The workspace's ID."), + cursor: z + .string() + .describe( + 'The pointer to the first record of the set of paginated results. To view the next response, use the `nextCursor` value for this parameter.' + ) + .optional(), + limit: z + .number() + .int() + .describe('The maximum number of rows to return in the response.') + .default(10), +}); +export const annotations = { + title: 'Gets all API specifications in a workspace.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/specs`; + const query = new URLSearchParams(); + if (params.workspaceId !== undefined) query.set('workspaceId', String(params.workspaceId)); + if (params.cursor !== undefined) query.set('cursor', String(params.cursor)); + if (params.limit !== undefined) query.set('limit', String(params.limit)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_async_spec_task_status.ts b/src/tools/get_async_spec_task_status.ts new file mode 100644 index 0000000..3ec2a1c --- /dev/null +++ b/src/tools/get_async_spec_task_status.ts @@ -0,0 +1,43 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-async-spec-task-status'; +export const description = 'Gets the status of an asynchronous API specification creation task.'; +export const parameters = z.object({ + elementType: z.enum(['collections', 'specs']).describe('The element to filter results by.'), + elementId: z.union([z.string(), z.string()]).describe("The element's ID."), + taskId: z.string().describe("The task's ID."), +}); +export const annotations = { + title: 'Gets the status of an asynchronous API specification creation task.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/${params.elementType}/${params.elementId}/tasks/${params.taskId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_authenticated_user.ts b/src/tools/get_authenticated_user.ts new file mode 100644 index 0000000..beff67d --- /dev/null +++ b/src/tools/get_authenticated_user.ts @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-authenticated-user'; +export const description = + 'Gets information about the authenticated user.\n\n**Note:**\n\n- This API returns a different response for users with the [Guest and Partner roles](https://learning.postman.com/docs/collaborating-in-postman/roles-and-permissions/#team-roles).\n- The \\`flow_count\\` response only returns for users on [Free plans](https://www.postman.com/pricing/).\n'; +export const parameters = z.object({}); +export const annotations = { + title: + 'Gets information about the authenticated user.\n\n**Note:**\n\n- This API returns a different response for users with the [Guest and Partner roles](https://learning.postman.com/docs/collaborating-in-postman/roles-and-permissions/#team-roles).\n- The \\`flow_count\\` response only returns for users on [Free plans](https://www.postman.com/pricing/).\n', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/me`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_collection.ts b/src/tools/get_collection.ts new file mode 100644 index 0000000..2049bd5 --- /dev/null +++ b/src/tools/get_collection.ts @@ -0,0 +1,57 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-collection'; +export const description = + "Gets information about a collection. For a complete list of this endpoint's possible values, refer to the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html)."; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's ID."), + access_key: z + .string() + .describe( + "A collection's read-only access key. Using this query parameter does not require an API key to call the endpoint." + ) + .optional(), + model: z + .literal('minimal') + .describe( + "Return a list of only the collection's root-level request (`rootLevelRequests`) and folder (`rootLevelFolders`) IDs instead of the full collection element data." + ) + .optional(), +}); +export const annotations = { + title: + "Gets information about a collection. For a complete list of this endpoint's possible values, refer to the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).", + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}`; + const query = new URLSearchParams(); + if (params.access_key !== undefined) query.set('access_key', String(params.access_key)); + if (params.model !== undefined) query.set('model', String(params.model)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_collection_comments.ts b/src/tools/get_collection_comments.ts new file mode 100644 index 0000000..4f90488 --- /dev/null +++ b/src/tools/get_collection_comments.ts @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-collection-comments'; +export const description = 'Gets all comments left by users in a collection.'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), +}); +export const annotations = { + title: 'Gets all comments left by users in a collection.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/comments`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_collection_folder.ts b/src/tools/get_collection_folder.ts new file mode 100644 index 0000000..172a480 --- /dev/null +++ b/src/tools/get_collection_folder.ts @@ -0,0 +1,54 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-collection-folder'; +export const description = 'Gets information about a folder in a collection.'; +export const parameters = z.object({ + folderId: z.string().describe("The folder's ID."), + collectionId: z.string().describe("The collection's ID."), + ids: z + .boolean() + .describe('If true, returns only properties that contain ID values in the response.') + .optional(), + uid: z.boolean().describe('If true, returns all IDs in UID format (`userId`-`id`).').optional(), + populate: z + .boolean() + .describe("If true, returns all of the collection item's contents.") + .optional(), +}); +export const annotations = { + title: 'Gets information about a folder in a collection.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/folders/${params.folderId}`; + const query = new URLSearchParams(); + if (params.ids !== undefined) query.set('ids', String(params.ids)); + if (params.uid !== undefined) query.set('uid', String(params.uid)); + if (params.populate !== undefined) query.set('populate', String(params.populate)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_collection_forks.ts b/src/tools/get_collection_forks.ts new file mode 100644 index 0000000..59f4a59 --- /dev/null +++ b/src/tools/get_collection_forks.ts @@ -0,0 +1,63 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-collection-forks'; +export const description = + "Gets a collection's forked collections. The response returns data for each fork, such as the fork's ID, the user who forked it, and the fork's creation date."; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's ID."), + cursor: z + .string() + .describe( + 'The pointer to the first record of the set of paginated results. To view the next response, use the `nextCursor` value for this parameter.' + ) + .optional(), + limit: z + .number() + .int() + .describe('The maximum number of rows to return in the response.') + .default(10), + direction: z + .enum(['asc', 'desc']) + .describe( + 'Sort the results by creation date in ascending (`asc`) or descending (`desc`) order.' + ) + .optional(), +}); +export const annotations = { + title: + "Gets a collection's forked collections. The response returns data for each fork, such as the fork's ID, the user who forked it, and the fork's creation date.", + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/forks`; + const query = new URLSearchParams(); + if (params.cursor !== undefined) query.set('cursor', String(params.cursor)); + if (params.limit !== undefined) query.set('limit', String(params.limit)); + if (params.direction !== undefined) query.set('direction', String(params.direction)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_collection_request.ts b/src/tools/get_collection_request.ts new file mode 100644 index 0000000..a40303b --- /dev/null +++ b/src/tools/get_collection_request.ts @@ -0,0 +1,54 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-collection-request'; +export const description = 'Gets information about a request in a collection.'; +export const parameters = z.object({ + requestId: z.string().describe("The request's ID."), + collectionId: z.string().describe("The collection's ID."), + ids: z + .boolean() + .describe('If true, returns only properties that contain ID values in the response.') + .optional(), + uid: z.boolean().describe('If true, returns all IDs in UID format (`userId`-`id`).').optional(), + populate: z + .boolean() + .describe("If true, returns all of the collection item's contents.") + .optional(), +}); +export const annotations = { + title: 'Gets information about a request in a collection.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/requests/${params.requestId}`; + const query = new URLSearchParams(); + if (params.ids !== undefined) query.set('ids', String(params.ids)); + if (params.uid !== undefined) query.set('uid', String(params.uid)); + if (params.populate !== undefined) query.set('populate', String(params.populate)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_collection_response.ts b/src/tools/get_collection_response.ts new file mode 100644 index 0000000..799b385 --- /dev/null +++ b/src/tools/get_collection_response.ts @@ -0,0 +1,54 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-collection-response'; +export const description = 'Gets information about a response in a collection.'; +export const parameters = z.object({ + responseId: z.string().describe("The response's ID."), + collectionId: z.string().describe("The collection's ID."), + ids: z + .boolean() + .describe('If true, returns only properties that contain ID values in the response.') + .optional(), + uid: z.boolean().describe('If true, returns all IDs in UID format (`userId`-`id`).').optional(), + populate: z + .boolean() + .describe("If true, returns all of the collection item's contents.") + .optional(), +}); +export const annotations = { + title: 'Gets information about a response in a collection.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/responses/${params.responseId}`; + const query = new URLSearchParams(); + if (params.ids !== undefined) query.set('ids', String(params.ids)); + if (params.uid !== undefined) query.set('uid', String(params.uid)); + if (params.populate !== undefined) query.set('populate', String(params.populate)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_collection_tags.ts b/src/tools/get_collection_tags.ts new file mode 100644 index 0000000..324b868 --- /dev/null +++ b/src/tools/get_collection_tags.ts @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-collection-tags'; +export const description = 'Gets all the tags associated with a collection.'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), +}); +export const annotations = { + title: 'Gets all the tags associated with a collection.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/tags`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_collection_updates_tasks.ts b/src/tools/get_collection_updates_tasks.ts new file mode 100644 index 0000000..63f05dd --- /dev/null +++ b/src/tools/get_collection_updates_tasks.ts @@ -0,0 +1,39 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-collection-updates-tasks'; +export const description = 'Gets the status of an asynchronous collection update task.'; +export const parameters = z.object({ taskId: z.string().describe("The task's ID.") }); +export const annotations = { + title: 'Gets the status of an asynchronous collection update task.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collection-updates-tasks/${params.taskId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_collections.ts b/src/tools/get_collections.ts new file mode 100644 index 0000000..547763e --- /dev/null +++ b/src/tools/get_collections.ts @@ -0,0 +1,58 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-collections'; +export const description = + 'The workspace ID query is required for this endpoint. If not provided, the LLM should ask the user to provide it.'; +export const parameters = z.object({ + workspace: z.string().describe("The workspace's ID."), + name: z.string().describe('Filter results by collections that match the given name.').optional(), + limit: z + .number() + .int() + .describe('The maximum number of rows to return in the response.') + .optional(), + offset: z + .number() + .int() + .describe('The zero-based offset of the first item to return.') + .optional(), +}); +export const annotations = { + title: + 'The workspace ID query is required for this endpoint. If not provided, the LLM should ask the user to provide it.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections`; + const query = new URLSearchParams(); + if (params.workspace !== undefined) query.set('workspace', String(params.workspace)); + if (params.name !== undefined) query.set('name', String(params.name)); + if (params.limit !== undefined) query.set('limit', String(params.limit)); + if (params.offset !== undefined) query.set('offset', String(params.offset)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_collections_forked_by_user.ts b/src/tools/get_collections_forked_by_user.ts new file mode 100644 index 0000000..205b157 --- /dev/null +++ b/src/tools/get_collections_forked_by_user.ts @@ -0,0 +1,60 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-collections-forked-by-user'; +export const description = "Gets a list of all the authenticated user's forked collections."; +export const parameters = z.object({ + cursor: z + .string() + .describe( + 'The pointer to the first record of the set of paginated results. To view the next response, use the `nextCursor` value for this parameter.' + ) + .optional(), + limit: z + .number() + .int() + .describe('The maximum number of rows to return in the response.') + .default(10), + direction: z + .enum(['asc', 'desc']) + .describe( + 'Sort the results by creation date in ascending (`asc`) or descending (`desc`) order.' + ) + .optional(), +}); +export const annotations = { + title: "Gets a list of all the authenticated user's forked collections.", + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/collection-forks`; + const query = new URLSearchParams(); + if (params.cursor !== undefined) query.set('cursor', String(params.cursor)); + if (params.limit !== undefined) query.set('limit', String(params.limit)); + if (params.direction !== undefined) query.set('direction', String(params.direction)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_environment.ts b/src/tools/get_environment.ts new file mode 100644 index 0000000..a6edead --- /dev/null +++ b/src/tools/get_environment.ts @@ -0,0 +1,39 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-environment'; +export const description = 'Gets information about an environment.'; +export const parameters = z.object({ environmentId: z.string().describe("The environment's ID.") }); +export const annotations = { + title: 'Gets information about an environment.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/environments/${params.environmentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_environments.ts b/src/tools/get_environments.ts new file mode 100644 index 0000000..1c61569 --- /dev/null +++ b/src/tools/get_environments.ts @@ -0,0 +1,44 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-environments'; +export const description = + 'Gets information about all of your [environments](https://learning.postman.com/docs/sending-requests/managing-environments/).'; +export const parameters = z.object({ + workspace: z.string().describe("The workspace's ID.").optional(), +}); +export const annotations = { + title: + 'Gets information about all of your [environments](https://learning.postman.com/docs/sending-requests/managing-environments/).', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/environments`; + const query = new URLSearchParams(); + if (params.workspace !== undefined) query.set('workspace', String(params.workspace)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_folder_comments.ts b/src/tools/get_folder_comments.ts new file mode 100644 index 0000000..ffe54f5 --- /dev/null +++ b/src/tools/get_folder_comments.ts @@ -0,0 +1,42 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-folder-comments'; +export const description = 'Gets all comments left by users in a folder.'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + folderId: z.string().describe("The folder's unique ID."), +}); +export const annotations = { + title: 'Gets all comments left by users in a folder.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/folders/${params.folderId}/comments`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_generated_collection_specs.ts b/src/tools/get_generated_collection_specs.ts new file mode 100644 index 0000000..9656227 --- /dev/null +++ b/src/tools/get_generated_collection_specs.ts @@ -0,0 +1,42 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-generated-collection-specs'; +export const description = 'Gets the API specification generated for the given collection.'; +export const parameters = z.object({ + collectionUid: z.string().describe("The collection's unique ID."), + elementType: z.literal('spec').describe('The `spec` value.'), +}); +export const annotations = { + title: 'Gets the API specification generated for the given collection.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionUid}/generations/${params.elementType}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_mock.ts b/src/tools/get_mock.ts new file mode 100644 index 0000000..53ba15f --- /dev/null +++ b/src/tools/get_mock.ts @@ -0,0 +1,39 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-mock'; +export const description = 'Gets information about a mock server.'; +export const parameters = z.object({ mockId: z.string().describe("The mock's ID.") }); +export const annotations = { + title: 'Gets information about a mock server.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/mocks/${params.mockId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_mocks.ts b/src/tools/get_mocks.ts new file mode 100644 index 0000000..074c94c --- /dev/null +++ b/src/tools/get_mocks.ts @@ -0,0 +1,46 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-mocks'; +export const description = + 'Gets all active mock servers. By default, this endpoint returns only mock servers you created across all workspaces.\n\n**Note:**\n\nIf you pass both the \\`teamId\\` and \\`workspace\\` query parameters, this endpoint only accepts the \\`workspace\\` query.\n'; +export const parameters = z.object({ + teamId: z.string().describe('Return only results that belong to the given team ID.').optional(), + workspace: z.string().describe('Return only results found in the given workspace ID.').optional(), +}); +export const annotations = { + title: + 'Gets all active mock servers. By default, this endpoint returns only mock servers you created across all workspaces.\n\n**Note:**\n\nIf you pass both the \\`teamId\\` and \\`workspace\\` query parameters, this endpoint only accepts the \\`workspace\\` query.\n', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/mocks`; + const query = new URLSearchParams(); + if (params.teamId !== undefined) query.set('teamId', String(params.teamId)); + if (params.workspace !== undefined) query.set('workspace', String(params.workspace)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_monitor.ts b/src/tools/get_monitor.ts new file mode 100644 index 0000000..2f64d98 --- /dev/null +++ b/src/tools/get_monitor.ts @@ -0,0 +1,39 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-monitor'; +export const description = 'Gets information about a monitor.'; +export const parameters = z.object({ monitorId: z.string().describe("The monitor's ID.") }); +export const annotations = { + title: 'Gets information about a monitor.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/monitors/${params.monitorId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_monitors.ts b/src/tools/get_monitors.ts new file mode 100644 index 0000000..58586be --- /dev/null +++ b/src/tools/get_monitors.ts @@ -0,0 +1,72 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-monitors'; +export const description = 'Gets all monitors.'; +export const parameters = z.object({ + workspace: z.string().describe('Return only results found in the given workspace ID.').optional(), + active: z.boolean().describe('If true, return only active monitors.').default(false), + owner: z + .number() + .int() + .describe('Return only results that belong to the given user ID.') + .optional(), + collectionUid: z.string().describe("Filter the results by a collection's unique ID.").optional(), + environmentUid: z + .string() + .describe("Filter the results by an environment's unique ID.") + .optional(), + cursor: z + .string() + .describe( + 'The pointer to the first record of the set of paginated results. To view the next response, use the `nextCursor` value for this parameter.' + ) + .optional(), + limit: z + .number() + .int() + .describe('The maximum number of rows to return in the response.') + .default(10), +}); +export const annotations = { + title: 'Gets all monitors.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/monitors`; + const query = new URLSearchParams(); + if (params.workspace !== undefined) query.set('workspace', String(params.workspace)); + if (params.active !== undefined) query.set('active', String(params.active)); + if (params.owner !== undefined) query.set('owner', String(params.owner)); + if (params.collectionUid !== undefined) + query.set('collectionUid', String(params.collectionUid)); + if (params.environmentUid !== undefined) + query.set('environmentUid', String(params.environmentUid)); + if (params.cursor !== undefined) query.set('cursor', String(params.cursor)); + if (params.limit !== undefined) query.set('limit', String(params.limit)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_request_comments.ts b/src/tools/get_request_comments.ts new file mode 100644 index 0000000..3cc33cd --- /dev/null +++ b/src/tools/get_request_comments.ts @@ -0,0 +1,46 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-request-comments'; +export const description = 'Gets all comments left by users in a request.'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + requestId: z + .string() + .describe( + "The request ID must contain the team ID as a prefix, in `teamId-requestId` format.\n\nFor example, if you're creating a comment on collection ID `24585957-7b2c98f7-30db-4b67-8685-0079f48a0947` (note on the prefix), and\nthe collection request's ID is `2c450b59-9bbf-729b-6ac0-f92535a7c336`, then the `{requestId}` must be `24585957-2c450b59-9bbf-729b-6ac0-f92535a7c336`.\n" + ), +}); +export const annotations = { + title: 'Gets all comments left by users in a request.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/requests/${params.requestId}/comments`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_response_comments.ts b/src/tools/get_response_comments.ts new file mode 100644 index 0000000..39ec24a --- /dev/null +++ b/src/tools/get_response_comments.ts @@ -0,0 +1,42 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-response-comments'; +export const description = 'Gets all comments left by users in a response.'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + responseId: z.string().describe("The response's unique ID."), +}); +export const annotations = { + title: 'Gets all comments left by users in a response.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/responses/${params.responseId}/comments`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_source_collection_status.ts b/src/tools/get_source_collection_status.ts new file mode 100644 index 0000000..a8296ef --- /dev/null +++ b/src/tools/get_source_collection_status.ts @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-source-collection-status'; +export const description = + 'Checks whether there is a change between the forked collection and its parent (source) collection.\n\nIf the value of the \\`isSourceAhead\\` property is \\`true\\` in the response, then there is a difference between the forked collection and its source collection.\n\n**Note:**\n\nThis endpoint may take a few minutes to return an updated \\`isSourceAhead\\` status.\n'; +export const parameters = z.object({ collectionId: z.string().describe("The collection's ID.") }); +export const annotations = { + title: + 'Checks whether there is a change between the forked collection and its parent (source) collection.\n\nIf the value of the \\`isSourceAhead\\` property is \\`true\\` in the response, then there is a difference between the forked collection and its source collection.\n\n**Note:**\n\nThis endpoint may take a few minutes to return an updated \\`isSourceAhead\\` status.\n', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/source-status`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_spec.ts b/src/tools/get_spec.ts new file mode 100644 index 0000000..72f5375 --- /dev/null +++ b/src/tools/get_spec.ts @@ -0,0 +1,39 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-spec'; +export const description = 'Gets information about an API specification.'; +export const parameters = z.object({ specId: z.string().describe("The spec's ID.") }); +export const annotations = { + title: 'Gets information about an API specification.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/specs/${params.specId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_spec_collections.ts b/src/tools/get_spec_collections.ts new file mode 100644 index 0000000..c3d6d31 --- /dev/null +++ b/src/tools/get_spec_collections.ts @@ -0,0 +1,55 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-spec-collections'; +export const description = "Gets all of an API specification's generated collections."; +export const parameters = z.object({ + specId: z.string().describe("The spec's ID."), + elementType: z.literal('collection').describe('The `collection` element type.'), + limit: z + .number() + .int() + .describe('The maximum number of rows to return in the response.') + .default(10), + cursor: z + .string() + .describe( + 'The pointer to the first record of the set of paginated results. To view the next response, use the `nextCursor` value for this parameter.' + ) + .optional(), +}); +export const annotations = { + title: "Gets all of an API specification's generated collections.", + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/specs/${params.specId}/generations/${params.elementType}`; + const query = new URLSearchParams(); + if (params.limit !== undefined) query.set('limit', String(params.limit)); + if (params.cursor !== undefined) query.set('cursor', String(params.cursor)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_spec_definition.ts b/src/tools/get_spec_definition.ts new file mode 100644 index 0000000..901f9b9 --- /dev/null +++ b/src/tools/get_spec_definition.ts @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-spec-definition'; +export const description = + "Gets an API specification's definition. You can use this endpoint to get the complete contents of an API specification in JSON or YAML format."; +export const parameters = z.object({ specId: z.string().describe("The spec's ID.") }); +export const annotations = { + title: + "Gets an API specification's definition. You can use this endpoint to get the complete contents of an API specification in JSON or YAML format.", + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/specs/${params.specId}/definitions`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_status_of_an_async_task.ts b/src/tools/get_status_of_an_async_task.ts new file mode 100644 index 0000000..2a4f825 --- /dev/null +++ b/src/tools/get_status_of_an_async_task.ts @@ -0,0 +1,45 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-status-of-an-async-task'; +export const description = 'Gets the status of an asynchronous task.'; +export const parameters = z.object({ + apiId: z.string().describe("The API's ID."), + taskId: z.string().describe("The task's ID."), + Accept: z + .literal('application/vnd.api.v10+json') + .describe('The `application/vnd.api.v10+json` request header required to use the endpoint.'), +}); +export const annotations = { + title: 'Gets the status of an asynchronous task.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/apis/${params.apiId}/tasks/${params.taskId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_tagged_entities.ts b/src/tools/get_tagged_entities.ts new file mode 100644 index 0000000..1525187 --- /dev/null +++ b/src/tools/get_tagged_entities.ts @@ -0,0 +1,74 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-tagged-entities'; +export const description = + 'Gets Postman elements (entities) by a given tag. Tags enable you to organize and search [workspaces](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/managing-workspaces/#tagging-a-workspace), [APIs](https://learning.postman.com/docs/designing-and-developing-your-api/managing-apis/#tagging-apis), and [collections](https://learning.postman.com/docs/collections/using-collections/#tagging-a-collection) that contain shared tags.\n\n**Note:**\n\nTagging is available on Postman [**Enterprise** plans](https://www.postman.com/pricing/).\n'; +export const parameters = z.object({ + slug: z + .string() + .regex(new RegExp('^[a-z][a-z0-9-]*[a-z0-9]+$')) + .min(2) + .max(64) + .describe("The tag's ID within a team or individual (non-team) user scope."), + limit: z + .number() + .int() + .lte(50) + .describe('The maximum number of tagged elements to return in a single call.') + .default(10), + direction: z + .enum(['asc', 'desc']) + .describe( + "The ascending (`asc`) or descending (`desc`) order to sort the results by, based on the time of the entity's tagging." + ) + .default('desc'), + cursor: z + .string() + .describe( + 'The cursor to get the next set of results in the paginated response. If you pass an invalid value, the API only returns the first set of results.' + ) + .optional(), + entityType: z + .enum(['api', 'collection', 'workspace']) + .describe('Filter results for the given entity type.') + .optional(), +}); +export const annotations = { + title: + 'Gets Postman elements (entities) by a given tag. Tags enable you to organize and search [workspaces](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/managing-workspaces/#tagging-a-workspace), [APIs](https://learning.postman.com/docs/designing-and-developing-your-api/managing-apis/#tagging-apis), and [collections](https://learning.postman.com/docs/collections/using-collections/#tagging-a-collection) that contain shared tags.\n\n**Note:**\n\nTagging is available on Postman [**Enterprise** plans](https://www.postman.com/pricing/).\n', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/tags/${params.slug}/entities`; + const query = new URLSearchParams(); + if (params.limit !== undefined) query.set('limit', String(params.limit)); + if (params.direction !== undefined) query.set('direction', String(params.direction)); + if (params.cursor !== undefined) query.set('cursor', String(params.cursor)); + if (params.entityType !== undefined) query.set('entityType', String(params.entityType)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_workspace.ts b/src/tools/get_workspace.ts new file mode 100644 index 0000000..a20aa8d --- /dev/null +++ b/src/tools/get_workspace.ts @@ -0,0 +1,50 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-workspace'; +export const description = + "Gets information about a workspace.\n\n**Note:**\n\nThis endpoint's response contains the \\`visibility\\` field. [Visibility](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/managing-workspaces/#changing-workspace-visibility) determines who can access the workspace:\n- \\`personal\\` — Only you can access the workspace.\n- \\`team\\` — All team members can access the workspace.\n- \\`private\\` — Only invited team members can access the workspace ([**Professional** and **Enterprise** plans only](https://www.postman.com/pricing)).\n- \\`public\\` — Everyone can access the workspace.\n- \\`partner\\` — Only invited team members and [partners](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/partner-workspaces/) can access the workspace ([**Professional** and **Enterprise** plans only](https://www.postman.com/pricing)).\n\n### Important\n\nWe have deprecated the \\`name\\` and \\`uid\\` responses in the following array of objects:\n- \\`collections\\`\n- \\`environments\\`\n- \\`mocks\\`\n- \\`monitors\\`\n- \\`apis\\`\n"; +export const parameters = z.object({ + workspaceId: z.string().describe("The workspace's ID."), + include: z + .enum(['mocks:deactivated', 'scim']) + .describe( + "Include the following information in the endpoint's response:\n- `mocks:deactivated` — Include all deactivated mock servers in the response.\n- `scim` — Return the SCIM user IDs of the workspace creator and who last modified it.\n" + ) + .optional(), +}); +export const annotations = { + title: + "Gets information about a workspace.\n\n**Note:**\n\nThis endpoint's response contains the \\`visibility\\` field. [Visibility](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/managing-workspaces/#changing-workspace-visibility) determines who can access the workspace:\n- \\`personal\\` — Only you can access the workspace.\n- \\`team\\` — All team members can access the workspace.\n- \\`private\\` — Only invited team members can access the workspace ([**Professional** and **Enterprise** plans only](https://www.postman.com/pricing)).\n- \\`public\\` — Everyone can access the workspace.\n- \\`partner\\` — Only invited team members and [partners](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/partner-workspaces/) can access the workspace ([**Professional** and **Enterprise** plans only](https://www.postman.com/pricing)).\n\n### Important\n\nWe have deprecated the \\`name\\` and \\`uid\\` responses in the following array of objects:\n- \\`collections\\`\n- \\`environments\\`\n- \\`mocks\\`\n- \\`monitors\\`\n- \\`apis\\`\n", + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/workspaces/${params.workspaceId}`; + const query = new URLSearchParams(); + if (params.include !== undefined) query.set('include', String(params.include)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_workspace_global_variables.ts b/src/tools/get_workspace_global_variables.ts new file mode 100644 index 0000000..9ac3f8e --- /dev/null +++ b/src/tools/get_workspace_global_variables.ts @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-workspace-global-variables'; +export const description = + "Gets a workspace's global [variables](https://learning.postman.com/docs/sending-requests/variables/#variable-scopes). Global variables enable you to access data between collections, requests, scripts, and environments and are available throughout a workspace."; +export const parameters = z.object({ workspaceId: z.string().describe("The workspace's ID.") }); +export const annotations = { + title: + "Gets a workspace's global [variables](https://learning.postman.com/docs/sending-requests/variables/#variable-scopes). Global variables enable you to access data between collections, requests, scripts, and environments and are available throughout a workspace.", + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/workspaces/${params.workspaceId}/global-variables`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_workspace_tags.ts b/src/tools/get_workspace_tags.ts new file mode 100644 index 0000000..bfc5dc9 --- /dev/null +++ b/src/tools/get_workspace_tags.ts @@ -0,0 +1,39 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-workspace-tags'; +export const description = 'Gets all the tags associated with a workspace.'; +export const parameters = z.object({ workspaceId: z.string().describe("The workspace's ID.") }); +export const annotations = { + title: 'Gets all the tags associated with a workspace.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/workspaces/${params.workspaceId}/tags`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/get_workspaces.ts b/src/tools/get_workspaces.ts new file mode 100644 index 0000000..c06b9f1 --- /dev/null +++ b/src/tools/get_workspaces.ts @@ -0,0 +1,62 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'get-workspaces'; +export const description = + "Gets all [workspaces](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/creating-workspaces/). The response includes your workspaces and any workspaces that you have access to.\n\n**Note:**\n\nThis endpoint's response contains the visibility field. Visibility determines who can access the workspace:\n- \\`personal\\` — Only you can access the workspace.\n- \\`team\\` — All team members can access the workspace.\n- \\`private\\` — Only invited team members can access the workspace ([**Professional** and **Enterprise** plans only](https://www.postman.com/pricing)).\n- \\`public\\` — Everyone can access the workspace.\n- \\`partner\\` — Only invited team members and [partners](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/partner-workspaces/) can access the workspace ([**Professional** and **Enterprise** plans only](https://www.postman.com/pricing)).\n"; +export const parameters = z.object({ + type: z + .enum(['personal', 'team', 'private', 'public', 'partner']) + .describe('The type of workspace to filter the response by.') + .optional(), + createdBy: z + .number() + .int() + .describe( + 'Return only workspaces created by a specific user ID. For multiple users, pass this value as a comma-separated list of user IDs. The response only returns workspaces that you have access to.' + ) + .optional(), + include: z + .enum(['mocks:deactivated', 'scim']) + .describe( + "Include the following information in the endpoint's response:\n- `mocks:deactivated` — Include all deactivated mock servers in the response.\n- `scim` — Return the SCIM user IDs of the workspace creator and who last modified it.\n" + ) + .optional(), +}); +export const annotations = { + title: + "Gets all [workspaces](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/creating-workspaces/). The response includes your workspaces and any workspaces that you have access to.\n\n**Note:**\n\nThis endpoint's response contains the visibility field. Visibility determines who can access the workspace:\n- \\`personal\\` — Only you can access the workspace.\n- \\`team\\` — All team members can access the workspace.\n- \\`private\\` — Only invited team members can access the workspace ([**Professional** and **Enterprise** plans only](https://www.postman.com/pricing)).\n- \\`public\\` — Everyone can access the workspace.\n- \\`partner\\` — Only invited team members and [partners](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/partner-workspaces/) can access the workspace ([**Professional** and **Enterprise** plans only](https://www.postman.com/pricing)).\n", + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/workspaces`; + const query = new URLSearchParams(); + if (params.type !== undefined) query.set('type', String(params.type)); + if (params.createdBy !== undefined) query.set('createdBy', String(params.createdBy)); + if (params.include !== undefined) query.set('include', String(params.include)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/patch_collection.ts b/src/tools/patch_collection.ts new file mode 100644 index 0000000..4d67f15 --- /dev/null +++ b/src/tools/patch_collection.ts @@ -0,0 +1,577 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'patch-collection'; +export const description = + 'Updates specific collection information, such as its name, events, or its variables. For more information about the \\`auth\\`, \\`variable\\`, and \\`events\\` properties, refer to the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html):\n- For \\`variable\\`, refer to the **Variable List** entry. Also accepts \\`variables\\`.\n- For \\`auth\\`, refer to the **Auth** entry.\n- For \\`events\\`, refer to the **Event List** entry.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's ID."), + collection: z + .object({ + info: z + .object({ + name: z.string().describe("The collection's updated name.").optional(), + description: z.string().describe("The collection's updated description.").optional(), + }) + .describe("An object that contains the collection's updated name and description.") + .optional(), + variable: z + .array( + z + .object({ + key: z.string().describe("The variable's key (name).").optional(), + value: z.string().describe("The key's value.").optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z.string().describe("The variable's name.").optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe( + "A list of the collection's [variables](https://learning.postman.com/docs/sending-requests/variables/variables/). Make certain not to include sensitive information in variables." + ) + .optional(), + auth: z + .object({ + type: z + .enum([ + 'basic', + 'bearer', + 'apikey', + 'digest', + 'oauth1', + 'oauth2', + 'hawk', + 'awsv4', + 'ntlm', + 'edgegrid', + ]) + .describe('The authorization type.'), + apikey: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe("The API key's authentication information.") + .optional(), + awsv4: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [AWS Signature](https://learning.postman.com/docs/sending-requests/authorization/aws-signature/) authentication.' + ) + .optional(), + basic: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Basic Auth](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#basic-auth).' + ) + .optional(), + bearer: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Bearer Token](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#bearer-token) authentication.' + ) + .optional(), + digest: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Digest](https://learning.postman.com/docs/sending-requests/authorization/digest-auth/) access authentication.' + ) + .optional(), + edgegrid: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Akamai Edgegrid](https://learning.postman.com/docs/sending-requests/authorization/akamai-edgegrid/) authentication.' + ) + .optional(), + hawk: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Hawk](https://learning.postman.com/docs/sending-requests/authorization/hawk-authentication/) authentication.' + ) + .optional(), + ntlm: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [NTLM](https://learning.postman.com/docs/sending-requests/authorization/ntlm-authentication/) authentication.' + ) + .optional(), + oauth1: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [OAuth1](https://learning.postman.com/docs/sending-requests/authorization/oauth-10/) authentication.' + ) + .optional(), + oauth2: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [OAuth2](https://learning.postman.com/docs/sending-requests/authorization/oauth-20/) authentication.' + ) + .optional(), + }) + .describe( + 'The [authorization type supported by Postman](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + .optional(), + events: z + .array( + z + .object({ + id: z.string().describe("The event's ID.").optional(), + listen: z + .enum(['test', 'prerequest']) + .describe( + 'Can be set to `test` or `prerequest` for test scripts or pre-request scripts respectively.' + ), + script: z + .object({ + id: z.string().describe("The script's ID.").optional(), + type: z + .string() + .describe('The type of script. For example, `text/javascript`.') + .optional(), + exec: z + .array(z.string().nullable()) + .describe( + 'A list of script strings, where each line represents a line of code. Separate lines makes it easy to track script changes.' + ) + .optional(), + src: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z + .object({ + raw: z.string().describe("The request's raw URL.").optional(), + protocol: z.string().describe('The request protocol.').optional(), + host: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string().describe("The host's URL."), + z + .array(z.string().nullable()) + .describe("A list of the host's subdomain components."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe("The host's URL.") + .optional(), + path: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string(), + z + .array( + z.any().superRefine((x, ctx) => { + const schemas = [ + z.string().nullable(), + z.object({ + type: z.string().nullable().optional(), + value: z.string().nullable().optional(), + }), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + ) + .describe("A list of the URL's path components."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .optional(), + port: z + .string() + .describe( + "The URL's port number. An empty value indicates port `80` (http) or `443` (https)." + ) + .optional(), + query: z + .array( + z.object({ + key: z + .string() + .nullable() + .describe("The query parameter's key.") + .optional(), + value: z + .string() + .nullable() + .describe("The key's value.") + .optional(), + disabled: z + .boolean() + .describe( + "If true, the query parameter isn't sent with the request." + ) + .default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + ) + .describe( + 'A list of query parameters. These are the query string parts of the URL, parsed as separate variables.' + ) + .optional(), + hash: z + .string() + .describe( + 'Contains the URL fragment (if any). Usually this is not transmitted over the network, but it could be useful to store this in some cases.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z + .string() + .describe("The variable's key (name).") + .optional(), + value: z.string().describe("The key's value.").optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z.string().describe("The variable's name.").optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe('A list of variables.') + .optional(), + }) + .describe('Information about the URL.'), + z.string().describe('The literal request URL.'), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => (result.error ? [...errors, result.error] : errors))( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe('Information about the URL.') + .optional(), + name: z.string().describe("The script's name.").optional(), + }) + .describe( + 'Information about the Javascript code that can be used to to perform setup or teardown operations in a response.' + ) + .optional(), + disabled: z + .boolean() + .describe( + 'If true, the event is disabled. If this value is absent, then the event is considered enabled.' + ) + .default(false), + }) + .describe("Information about the collection's events.") + ) + .optional(), + }) + .optional(), +}); +export const annotations = { + title: + 'Updates specific collection information, such as its name, events, or its variables. For more information about the \\`auth\\`, \\`variable\\`, and \\`events\\` properties, refer to the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html):\n- For \\`variable\\`, refer to the **Variable List** entry. Also accepts \\`variables\\`.\n- For \\`auth\\`, refer to the **Auth** entry.\n- For \\`events\\`, refer to the **Event List** entry.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.collection !== undefined) bodyPayload.collection = params.collection; + const result = await fetchPostmanAPI(url, { + method: 'PATCH', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/patch_environment.ts b/src/tools/patch_environment.ts new file mode 100644 index 0000000..7082de1 --- /dev/null +++ b/src/tools/patch_environment.ts @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'patch-environment'; +export const description = + 'Updates specific environment properties, such as its name and variables.\n\n**Note:**\n\n- The request body size cannot exceed the maximum allowed size of 30MB.\n- If you receive an HTTP \\`411 Length Required\\` error response, manually pass the \\`Content-Length\\` header and its value in the request header.\n'; +export const parameters = z.object({ environmentId: z.string().describe("The environment's ID.") }); +export const annotations = { + title: + 'Updates specific environment properties, such as its name and variables.\n\n**Note:**\n\n- The request body size cannot exceed the maximum allowed size of 30MB.\n- If you receive an HTTP \\`411 Length Required\\` error response, manually pass the \\`Content-Length\\` header and its value in the request header.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/environments/${params.environmentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'PATCH', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/post_pan_element_or_folder.ts b/src/tools/post_pan_element_or_folder.ts new file mode 100644 index 0000000..177647b --- /dev/null +++ b/src/tools/post_pan_element_or_folder.ts @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'post-pan-element-or-folder'; +export const description = + "Publishes a element or creates a folder in your team's [Private API Network](https://learning.postman.com/docs/collaborating-in-postman/adding-private-network/). An element is a Postman API, collection, or workspace.\n\n**Note:**\n\nYou can only pass one element object type per call. For example, you cannot pass both \\`api\\` and \\`collection\\` in a single request.\n"; +export const parameters = z.object({}); +export const annotations = { + title: + "Publishes a element or creates a folder in your team's [Private API Network](https://learning.postman.com/docs/collaborating-in-postman/adding-private-network/). An element is a Postman API, collection, or workspace.\n\n**Note:**\n\nYou can only pass one element object type per call. For example, you cannot pass both \\`api\\` and \\`collection\\` in a single request.\n", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/network/private`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'POST', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/publish_documentation.ts b/src/tools/publish_documentation.ts new file mode 100644 index 0000000..14e4fed --- /dev/null +++ b/src/tools/publish_documentation.ts @@ -0,0 +1,148 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'publish-documentation'; +export const description = + "Publishes a collection's documentation. This makes it publicly available to anyone with the link to the documentation.\n\n**Note:**\n\n- Your [Postman plan](https://www.postman.com/pricing/) impacts your use of these endpoints:\n - For **Free** and **Basic** users, you must have permissions to edit the collection.\n - If [API Governance and Security](https://learning.postman.com/docs/api-governance/configurable-rules/configurable-rules-overview/) is enabled for your [**Enterprise**](https://www.postman.com/pricing/) team, only users with the [Community Manager role](https://learning.postman.com/docs/collaborating-in-postman/roles-and-permissions/#team-roles) can publish documentation.\n- Publishing is only supported for collections with HTTP requests.\n- You cannot publish a collection added to an API.\n"; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + environmentUid: z + .string() + .describe( + "The unique ID of the environment to publish with the documentation. The initial values of all variables are published with the documentation. Make certain they don't contain sensitive information such as passwords or tokens." + ) + .optional(), + customColor: z + .object({ + highlight: z + .string() + .describe("The hexcode color code for the documentation's highlighting.") + .optional(), + rightSidebar: z + .string() + .describe("The hexcode color code for the documentation's right sidebar color.") + .optional(), + topBar: z + .string() + .describe("The hexcode color code for the documentation's top bar color.") + .optional(), + }) + .describe( + "The theme's colors, in six digit hexcode. The values in this object must match the hexcode values of either the `light` or `dark` theme defined in the `appearance` object." + ), + documentationLayout: z + .enum(['classic-single-column', 'classic-double-column']) + .describe( + "The documentation's default layout style:\n- `classic-single-column` — Displays sample code inline beneath each request.\n- `classic-double-column` — Displays sample code in a column next to the documentation.\n" + ) + .default('classic-single-column'), + customization: z + .object({ + metaTags: z + .array( + z + .object({ + name: z + .string() + .describe( + "The key's name:\n - `title` — The title of your documentation. This value appears in relevant search queries and browser tabs. By default, the system uses the collection's name for the documentation title.\n - `description` — The documentation's description. This provides brief information about your document and lets users know what it contains. By default, the system uses the collection's description content.\n" + ), + value: z.string().describe("The `name` key's value."), + }) + .describe( + "The key-pair values that contain the documentation's `title` and `description` metadata information." + ) + ) + .optional(), + appearance: z + .object({ + default: z + .enum(['light', 'dark']) + .describe( + 'The default color theme (`light` or `dark`). Documentation uses the given theme value by default.' + ) + .optional(), + themes: z + .array( + z.object({ + name: z.enum(['dark', 'light']).describe('The `light` or `dark` theme.').optional(), + colors: z + .object({ + highlight: z + .string() + .describe("The hexcode color code for the documentation's highlighting.") + .optional(), + rightSidebar: z + .string() + .describe( + "The hexcode color code for the documentation's right sidebar color." + ) + .optional(), + topBar: z + .string() + .describe("The hexcode color code for the documentation's top bar color.") + .optional(), + }) + .describe( + "The theme's colors, in six digit hexcode. The values in this object must match the hexcode values of either the `light` or `dark` theme defined in the `appearance` object." + ) + .optional(), + logo: z + .string() + .nullable() + .describe( + "The URL to the documentation's logo image. By default, public documentation uses your team logo." + ) + .optional(), + }) + ) + .describe('A list of theme settings for the `light` and `dark` themes.') + .optional(), + }) + .describe('Information about the documentation appearance, such as colors and theme.') + .optional(), + }) + .describe("Information about the documentation's customization."), +}); +export const annotations = { + title: + "Publishes a collection's documentation. This makes it publicly available to anyone with the link to the documentation.\n\n**Note:**\n\n- Your [Postman plan](https://www.postman.com/pricing/) impacts your use of these endpoints:\n - For **Free** and **Basic** users, you must have permissions to edit the collection.\n - If [API Governance and Security](https://learning.postman.com/docs/api-governance/configurable-rules/configurable-rules-overview/) is enabled for your [**Enterprise**](https://www.postman.com/pricing/) team, only users with the [Community Manager role](https://learning.postman.com/docs/collaborating-in-postman/roles-and-permissions/#team-roles) can publish documentation.\n- Publishing is only supported for collections with HTTP requests.\n- You cannot publish a collection added to an API.\n", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/public-documentations`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.environmentUid !== undefined) bodyPayload.environmentUid = params.environmentUid; + if (params.customColor !== undefined) bodyPayload.customColor = params.customColor; + if (params.documentationLayout !== undefined) + bodyPayload.documentationLayout = params.documentationLayout; + if (params.customization !== undefined) bodyPayload.customization = params.customization; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/publish_mock.ts b/src/tools/publish_mock.ts new file mode 100644 index 0000000..9f109ed --- /dev/null +++ b/src/tools/publish_mock.ts @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'publish-mock'; +export const description = + 'Publishes a mock server. Publishing a mock server sets its **Access Control** configuration setting to public.'; +export const parameters = z.object({ mockId: z.string().describe("The mock's ID.") }); +export const annotations = { + title: + 'Publishes a mock server. Publishing a mock server sets its **Access Control** configuration setting to public.', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/mocks/${params.mockId}/publish`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'POST', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/pull_collection_changes.ts b/src/tools/pull_collection_changes.ts new file mode 100644 index 0000000..2d6e730 --- /dev/null +++ b/src/tools/pull_collection_changes.ts @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'pull-collection-changes'; +export const description = + "Pulls the changes from a parent (source) collection into the forked collection. In the endpoint's response:\n\n- The \\`destinationId\\` is the ID of the forked collection.\n- The \\`sourceId\\` is the ID of the source collection.\n"; +export const parameters = z.object({ collectionId: z.string().describe("The collection's ID.") }); +export const annotations = { + title: + "Pulls the changes from a parent (source) collection into the forked collection. In the endpoint's response:\n\n- The \\`destinationId\\` is the ID of the forked collection.\n- The \\`sourceId\\` is the ID of the source collection.\n", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/pulls`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/put_collection.ts b/src/tools/put_collection.ts new file mode 100644 index 0000000..1ef4a8e --- /dev/null +++ b/src/tools/put_collection.ts @@ -0,0 +1,5103 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'put-collection'; +export const description = + "Replaces the contents of a collection using the [Postman Collection v2.1.0 schema format](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html). Include the collection's ID values in the request body. If you do not, the endpoint removes the existing items and creates new items.\n\nTo perform an update asynchronously, use the \\`Prefer\\` header with the \\`respond-async\\` value. When performing an async update, this endpoint returns a HTTP \\`202 Accepted\\` response.\n\n> The maximum collection size this endpoint accepts cannot exceed 100 MB.\n\nFor a complete list of available property values for this endpoint, use the following references available in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html):\n- \\`info\\` object — Refer to the **Information** entry.\n- \\`item\\` object — Refer to the **Items** entry.\n- For all other possible values, refer to the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n- For protocol profile behavior, refer to Postman's [Protocol Profile Behavior documentation](https://github.com/postmanlabs/postman-runtime/blob/develop/docs/protocol-profile-behavior.md).\n\n**Note:**\n\n- If you don't include the collection items' ID values from the request body, the endpoint **removes** the existing items and recreates the items with new ID values.\n- To copy another collection's contents to the given collection, remove all ID values before you pass it in this endpoint. If you do not, this endpoint returns an error. These values include the \\`id\\`, \\`uid\\`, and \\`postman_id\\` values.\n"; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's ID."), + Prefer: z + .literal('respond-async') + .describe('The `respond-async` header to perform the update asynchronously.') + .optional(), + collection: z + .object({ + info: z + .object({ + name: z.string().describe("The collection's name."), + _postman_id: z + .string() + .describe( + "The collection's Postman ID. This field exists for Postman Collection Format v1 compatibility." + ) + .optional(), + description: z.string().describe("The collection's description.").optional(), + schema: z + .literal('https://schema.getpostman.com/json/collection/v2.1.0/collection.json') + .describe( + 'The "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" Postman Collection Format v2.1.0 schema.' + ), + }) + .describe('Information about the collection.'), + item: z.array( + z.any().superRefine((x, ctx) => { + const schemas = [ + z + .object({ + id: z.string().describe("The collection item's ID.").optional(), + name: z.string().describe("The item's name.").optional(), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z.string().describe("The description's contents.").optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z.string().nullable().describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => (result.error ? [...errors, result.error] : errors))( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z.string().describe("The variable's key (name).").optional(), + value: z.string().describe("The key's value.").optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z.string().describe("The variable's name.").optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe( + "A list of the collection's [variables](https://learning.postman.com/docs/sending-requests/variables/variables/). Make certain not to include sensitive information in variables." + ) + .optional(), + event: z + .array( + z + .object({ + id: z.string().describe("The event's ID.").optional(), + listen: z + .enum(['test', 'prerequest']) + .describe( + 'Can be set to `test` or `prerequest` for test scripts or pre-request scripts respectively.' + ), + script: z + .object({ + id: z.string().describe("The script's ID.").optional(), + type: z + .string() + .describe('The type of script. For example, `text/javascript`.') + .optional(), + exec: z + .array(z.string().nullable()) + .describe( + 'A list of script strings, where each line represents a line of code. Separate lines makes it easy to track script changes.' + ) + .optional(), + src: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z + .object({ + raw: z.string().describe("The request's raw URL.").optional(), + protocol: z + .string() + .describe('The request protocol.') + .optional(), + host: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string().describe("The host's URL."), + z + .array(z.string().nullable()) + .describe( + "A list of the host's subdomain components." + ), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe("The host's URL.") + .optional(), + path: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string(), + z + .array( + z.any().superRefine((x, ctx) => { + const schemas = [ + z.string().nullable(), + z.object({ + type: z.string().nullable().optional(), + value: z.string().nullable().optional(), + }), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + ) + .describe("A list of the URL's path components."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .optional(), + port: z + .string() + .describe( + "The URL's port number. An empty value indicates port `80` (http) or `443` (https)." + ) + .optional(), + query: z + .array( + z.object({ + key: z + .string() + .nullable() + .describe("The query parameter's key.") + .optional(), + value: z + .string() + .nullable() + .describe("The key's value.") + .optional(), + disabled: z + .boolean() + .describe( + "If true, the query parameter isn't sent with the request." + ) + .default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + ) + .describe( + 'A list of query parameters. These are the query string parts of the URL, parsed as separate variables.' + ) + .optional(), + hash: z + .string() + .describe( + 'Contains the URL fragment (if any). Usually this is not transmitted over the network, but it could be useful to store this in some cases.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z + .string() + .describe("The variable's key (name).") + .optional(), + value: z + .string() + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z + .string() + .describe("The variable's name.") + .optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe('A list of variables.') + .optional(), + }) + .describe('Information about the URL.'), + z.string().describe('The literal request URL.'), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe('Information about the URL.') + .optional(), + name: z.string().describe("The script's name.").optional(), + }) + .describe( + 'Information about the Javascript code that can be used to to perform setup or teardown operations in a response.' + ) + .optional(), + disabled: z + .boolean() + .describe( + 'If true, the event is disabled. If this value is absent, then the event is considered enabled.' + ) + .default(false), + }) + .describe("Information about the collection's events.") + ) + .describe( + 'A list of scripts configured to run when specific events occur. These scripts can be referenced in the collection by their ID.' + ) + .optional(), + request: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + url: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z + .object({ + raw: z.string().describe("The request's raw URL.").optional(), + protocol: z.string().describe('The request protocol.').optional(), + host: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string().describe("The host's URL."), + z + .array(z.string().nullable()) + .describe("A list of the host's subdomain components."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe("The host's URL.") + .optional(), + path: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string(), + z + .array( + z.any().superRefine((x, ctx) => { + const schemas = [ + z.string().nullable(), + z.object({ + type: z.string().nullable().optional(), + value: z.string().nullable().optional(), + }), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + ) + .describe("A list of the URL's path components."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .optional(), + port: z + .string() + .describe( + "The URL's port number. An empty value indicates port `80` (http) or `443` (https)." + ) + .optional(), + query: z + .array( + z.object({ + key: z + .string() + .nullable() + .describe("The query parameter's key.") + .optional(), + value: z + .string() + .nullable() + .describe("The key's value.") + .optional(), + disabled: z + .boolean() + .describe( + "If true, the query parameter isn't sent with the request." + ) + .default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + ) + .describe( + 'A list of query parameters. These are the query string parts of the URL, parsed as separate variables.' + ) + .optional(), + hash: z + .string() + .describe( + 'Contains the URL fragment (if any). Usually this is not transmitted over the network, but it could be useful to store this in some cases.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z + .string() + .describe("The variable's key (name).") + .optional(), + value: z.string().describe("The key's value.").optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z + .string() + .describe("The variable's name.") + .optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe('A list of variables.') + .optional(), + }) + .describe('Information about the URL.'), + z.string().describe('The literal request URL.'), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => (result.error ? [...errors, result.error] : errors))( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe('Information about the URL.') + .optional(), + auth: z + .object({ + type: z + .enum([ + 'basic', + 'bearer', + 'apikey', + 'digest', + 'oauth1', + 'oauth2', + 'hawk', + 'awsv4', + 'ntlm', + 'edgegrid', + ]) + .describe('The authorization type.'), + apikey: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe("The API key's authentication information.") + .optional(), + awsv4: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [AWS Signature](https://learning.postman.com/docs/sending-requests/authorization/aws-signature/) authentication.' + ) + .optional(), + basic: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Basic Auth](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#basic-auth).' + ) + .optional(), + bearer: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Bearer Token](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#bearer-token) authentication.' + ) + .optional(), + digest: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Digest](https://learning.postman.com/docs/sending-requests/authorization/digest-auth/) access authentication.' + ) + .optional(), + edgegrid: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Akamai Edgegrid](https://learning.postman.com/docs/sending-requests/authorization/akamai-edgegrid/) authentication.' + ) + .optional(), + hawk: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Hawk](https://learning.postman.com/docs/sending-requests/authorization/hawk-authentication/) authentication.' + ) + .optional(), + ntlm: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [NTLM](https://learning.postman.com/docs/sending-requests/authorization/ntlm-authentication/) authentication.' + ) + .optional(), + oauth1: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [OAuth1](https://learning.postman.com/docs/sending-requests/authorization/oauth-10/) authentication.' + ) + .optional(), + oauth2: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [OAuth2](https://learning.postman.com/docs/sending-requests/authorization/oauth-20/) authentication.' + ) + .optional(), + }) + .describe( + 'The [authorization type supported by Postman](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + .optional(), + proxy: z + .object({ + match: z + .string() + .describe('The URL match for the defined proxy configuration.') + .default('http+https://*/*'), + host: z.string().describe("The proxy server's host.").optional(), + port: z + .number() + .int() + .gte(0) + .describe("The proxy server's port.") + .default(8080), + tunnel: z + .boolean() + .describe('The tunneling details for the proxy configuration.') + .default(false), + disabled: z + .boolean() + .describe('If true, ignores the proxy configuration.') + .default(false), + }) + .describe('Information about custom proxy confiurations.') + .optional(), + certificate: z + .object({ + name: z.string().describe("The SSL certificate's name.").optional(), + matches: z + .array(z.string()) + .describe( + 'A list of URL match pattern strings to identify the URLs the certificate can be used for.' + ) + .optional(), + key: z + .object({ + src: z + .string() + .describe( + 'The path to the file that contains the certificate in the file system.' + ) + .optional(), + }) + .describe('Information about the private key.') + .optional(), + cert: z + .object({ + src: z + .string() + .describe( + 'The path to the file that contains the key for the certificate in the file system.' + ) + .optional(), + }) + .describe('Information about the file certificate.') + .optional(), + passphrase: z + .string() + .describe("The certificate's passphrase.") + .optional(), + }) + .optional(), + method: z + .union([ + z + .enum([ + 'GET', + 'PUT', + 'POST', + 'PATCH', + 'DELETE', + 'COPY', + 'HEAD', + 'OPTIONS', + 'LINK', + 'UNLINK', + 'PURGE', + 'LOCK', + 'UNLOCK', + 'PROPFIND', + 'VIEW', + ]) + .describe("The request's standard HTTP method."), + z.string().describe("The request's custom HTTP method."), + ]) + .optional(), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z.string().nullable().describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => (result.error ? [...errors, result.error] : errors))( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + header: z + .array( + z + .object({ + key: z + .string() + .describe( + "The header's key, such as `Content-Type` or `X-Custom-Header`." + ), + value: z.string().describe("The header key's value."), + disabled: z + .boolean() + .describe("If true, the current header isn't sent with requests.") + .default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + .describe('Information about the header.') + ) + .describe('A list of headers.') + .optional(), + body: z + .object({ + mode: z + .enum(['raw', 'urlencoded', 'formdata', 'file', 'graphql']) + .describe('The data associated with the request.') + .optional(), + raw: z + .string() + .describe( + 'If the `mode` value is `raw`, the raw content of the request body.' + ) + .optional(), + urlencoded: z + .array( + z.object({ + key: z.string().describe('The key value.'), + value: z.string().describe("The key's value.").optional(), + disabled: z.boolean().default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + ) + .describe('A list of x-www-form-encoded key/value pairs.') + .optional(), + formdata: z + .array( + z.record(z.any()).and( + z.union([ + z.object({ + key: z.string().describe('The key value.').optional(), + value: z.string().describe("The key's value.").optional(), + disabled: z + .boolean() + .describe('If true, prevents sending the form-data entry.') + .default(false), + type: z + .literal('text') + .describe('The `text` value.') + .optional(), + contentType: z + .string() + .describe('The form-data Content-Type header.') + .optional(), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }), + z.object({ + key: z.string().describe('The key value.').optional(), + src: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string().nullable(), + z.array(z.string()), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .optional(), + disabled: z + .boolean() + .describe('If true, prevents sending the form-data entry.') + .default(false), + type: z + .literal('file') + .describe('The `file` value.') + .optional(), + contentType: z + .string() + .describe('The form-data Content-Type header.') + .optional(), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }), + ]) + ) + ) + .describe( + 'If the `mode` value is `formdata`, then a list of form-data key/pair values.' + ) + .optional(), + file: z + .object({ + src: z + .string() + .nullable() + .describe( + 'The name of the file to upload (not its path). A null value indicates that no file is selected as a part of the request body.' + ) + .optional(), + content: z.string().optional(), + }) + .describe( + 'If the `mode` value is `file`, an object containing the file request information.' + ) + .optional(), + graphql: z + .object({ + query: z.string().describe('The GraphQL query.').optional(), + variables: z + .string() + .nullable() + .describe('The GraphQL query variables, in JSON format.') + .optional(), + }) + .describe( + 'If the `mode` value is `graphql`, an object containing the GraphQL request information.' + ) + .optional(), + options: z + .record(z.any()) + .describe( + 'Additional configurations and options set for various modes.' + ) + .optional(), + disabled: z + .boolean() + .describe('When set to true, prevents request body from being sent.') + .default(false), + }) + .describe("Information about the collection's request body.") + .optional(), + }), + z.string().nullable(), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => (result.error ? [...errors, result.error] : errors))( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe('Information about the collection request.'), + response: z + .array(z.any().describe("Information about the request's response.")) + .describe("A list of the collection's responses.") + .optional(), + protocolProfileBehavior: z + .object({ + strictSSL: z + .boolean() + .describe('If true, enables certificate verification.') + .optional(), + followRedirects: z + .boolean() + .describe('If true, follow HTTP 3xx responses as redirects.') + .optional(), + maxRedirects: z + .number() + .describe('The maximum number of redirects to follow.') + .optional(), + disableBodyPruning: z + .boolean() + .describe( + 'If true, disables request body pruning for the GET, COPY, HEAD, PURGE, and UNLOCK methods.' + ) + .optional(), + disableUrlEncoding: z + .boolean() + .describe( + 'If true, disables the percent encoding of auth, path, query, and fragment URL segments.' + ) + .optional(), + disabledSystemHeaders: z + .object({ + 'cache-control': z.boolean().optional(), + 'postman-token': z.boolean().optional(), + 'content-type': z.boolean().optional(), + 'content-length': z.boolean().optional(), + 'accept-encoding': z.boolean().optional(), + connection: z.boolean().optional(), + host: z.boolean().optional(), + }) + .describe('Disable the system headers which are added implicitly.') + .optional(), + insecureHTTPParser: z + .boolean() + .describe( + 'If true, uses an insecure HTTP parser that accepts invalid HTTP headers.' + ) + .optional(), + followOriginalHttpMethod: z + .boolean() + .describe( + 'If true, redirects with the original HTTP method. Redirects with the GET HTTP method by default.' + ) + .optional(), + followAuthorizationHeader: z + .boolean() + .describe( + 'If true, retains the `authorization` header when a redirect happens to a different hostname.' + ) + .optional(), + protocolVersion: z + .enum(['http1', 'http2', 'auto']) + .describe( + 'The HTTP protocol version to use. Supports the `http1`, `http2`, and `auto` values.' + ) + .optional(), + removeRefererHeaderOnRedirect: z + .boolean() + .describe('If true, removes the `referer` header when a redirect happens.') + .optional(), + tlsPreferServerCiphers: z + .boolean() + .describe( + "If true, uses the server's cipher suite order instead of the client's during negotiation." + ) + .optional(), + tlsDisabledProtocols: z + .array(z.string()) + .describe('The SSL and TLS protocol versions to disable during negotiation.') + .optional(), + tlsCipherSelection: z + .array(z.string()) + .describe( + 'The order of cipher suites that the SSL server profile uses to establish a secure connection.' + ) + .optional(), + }) + .describe( + 'The [settings](https://learning.postman.com/docs/sending-requests/create-requests/request-settings/) used to alter the [Protocol Profile Behavior](https://github.com/postmanlabs/postman-runtime/blob/develop/docs/protocol-profile-behavior.md) of sending a request.' + ) + .optional(), + }) + .describe('Information about the collection request or folder.'), + z + .object({ + name: z.string().describe("The folder's name.").optional(), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z.string().describe("The description's contents.").optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z.string().nullable().describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => (result.error ? [...errors, result.error] : errors))( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z.string().describe("The variable's key (name).").optional(), + value: z.string().describe("The key's value.").optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z.string().describe("The variable's name.").optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe( + "A list of the collection's [variables](https://learning.postman.com/docs/sending-requests/variables/variables/). Make certain not to include sensitive information in variables." + ) + .optional(), + item: z + .array( + z.union([ + z + .object({ + id: z.string().describe("The collection item's ID.").optional(), + name: z.string().describe("The item's name.").optional(), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z.string().nullable().describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => (result.error ? [...errors, result.error] : errors))( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z.string().describe("The variable's key (name).").optional(), + value: z.string().describe("The key's value.").optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z.string().describe("The variable's name.").optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe( + "A list of the collection's [variables](https://learning.postman.com/docs/sending-requests/variables/variables/). Make certain not to include sensitive information in variables." + ) + .optional(), + event: z + .array( + z + .object({ + id: z.string().describe("The event's ID.").optional(), + listen: z + .enum(['test', 'prerequest']) + .describe( + 'Can be set to `test` or `prerequest` for test scripts or pre-request scripts respectively.' + ), + script: z + .object({ + id: z.string().describe("The script's ID.").optional(), + type: z + .string() + .describe( + 'The type of script. For example, `text/javascript`.' + ) + .optional(), + exec: z + .array(z.string().nullable()) + .describe( + 'A list of script strings, where each line represents a line of code. Separate lines makes it easy to track script changes.' + ) + .optional(), + src: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z + .object({ + raw: z + .string() + .describe("The request's raw URL.") + .optional(), + protocol: z + .string() + .describe('The request protocol.') + .optional(), + host: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string().describe("The host's URL."), + z + .array(z.string().nullable()) + .describe( + "A list of the host's subdomain components." + ), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe("The host's URL.") + .optional(), + path: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string(), + z + .array( + z.any().superRefine((x, ctx) => { + const schemas = [ + z.string().nullable(), + z.object({ + type: z + .string() + .nullable() + .optional(), + value: z + .string() + .nullable() + .optional(), + }), + ]; + const errors = schemas.reduce< + z.ZodError[] + >( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if ( + schemas.length - errors.length !== + 1 + ) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + ) + .describe( + "A list of the URL's path components." + ), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .optional(), + port: z + .string() + .describe( + "The URL's port number. An empty value indicates port `80` (http) or `443` (https)." + ) + .optional(), + query: z + .array( + z.object({ + key: z + .string() + .nullable() + .describe("The query parameter's key.") + .optional(), + value: z + .string() + .nullable() + .describe("The key's value.") + .optional(), + disabled: z + .boolean() + .describe( + "If true, the query parameter isn't sent with the request." + ) + .default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe( + "The description's contents." + ) + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe( + "The collection's description." + ), + ]; + const errors = schemas.reduce< + z.ZodError[] + >( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if ( + schemas.length - errors.length !== + 1 + ) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + ) + .describe( + 'A list of query parameters. These are the query string parts of the URL, parsed as separate variables.' + ) + .optional(), + hash: z + .string() + .describe( + 'Contains the URL fragment (if any). Usually this is not transmitted over the network, but it could be useful to store this in some cases.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z + .string() + .describe("The variable's key (name).") + .optional(), + value: z + .string() + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z + .string() + .describe("The variable's name.") + .optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe('A list of variables.') + .optional(), + }) + .describe('Information about the URL.'), + z.string().describe('The literal request URL.'), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe('Information about the URL.') + .optional(), + name: z.string().describe("The script's name.").optional(), + }) + .describe( + 'Information about the Javascript code that can be used to to perform setup or teardown operations in a response.' + ) + .optional(), + disabled: z + .boolean() + .describe( + 'If true, the event is disabled. If this value is absent, then the event is considered enabled.' + ) + .default(false), + }) + .describe("Information about the collection's events.") + ) + .describe( + 'A list of scripts configured to run when specific events occur. These scripts can be referenced in the collection by their ID.' + ) + .optional(), + request: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + url: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z + .object({ + raw: z + .string() + .describe("The request's raw URL.") + .optional(), + protocol: z + .string() + .describe('The request protocol.') + .optional(), + host: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string().describe("The host's URL."), + z + .array(z.string().nullable()) + .describe( + "A list of the host's subdomain components." + ), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe("The host's URL.") + .optional(), + path: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string(), + z + .array( + z.any().superRefine((x, ctx) => { + const schemas = [ + z.string().nullable(), + z.object({ + type: z.string().nullable().optional(), + value: z.string().nullable().optional(), + }), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + ) + .describe( + "A list of the URL's path components." + ), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .optional(), + port: z + .string() + .describe( + "The URL's port number. An empty value indicates port `80` (http) or `443` (https)." + ) + .optional(), + query: z + .array( + z.object({ + key: z + .string() + .nullable() + .describe("The query parameter's key.") + .optional(), + value: z + .string() + .nullable() + .describe("The key's value.") + .optional(), + disabled: z + .boolean() + .describe( + "If true, the query parameter isn't sent with the request." + ) + .default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe( + "The collection's description." + ), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + ) + .describe( + 'A list of query parameters. These are the query string parts of the URL, parsed as separate variables.' + ) + .optional(), + hash: z + .string() + .describe( + 'Contains the URL fragment (if any). Usually this is not transmitted over the network, but it could be useful to store this in some cases.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z + .string() + .describe("The variable's key (name).") + .optional(), + value: z + .string() + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z + .string() + .describe("The variable's name.") + .optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe('A list of variables.') + .optional(), + }) + .describe('Information about the URL.'), + z.string().describe('The literal request URL.'), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe('Information about the URL.') + .optional(), + auth: z + .object({ + type: z + .enum([ + 'basic', + 'bearer', + 'apikey', + 'digest', + 'oauth1', + 'oauth2', + 'hawk', + 'awsv4', + 'ntlm', + 'edgegrid', + ]) + .describe('The authorization type.'), + apikey: z + .array( + z + .object({ + key: z + .string() + .describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe("The API key's authentication information.") + .optional(), + awsv4: z + .array( + z + .object({ + key: z + .string() + .describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [AWS Signature](https://learning.postman.com/docs/sending-requests/authorization/aws-signature/) authentication.' + ) + .optional(), + basic: z + .array( + z + .object({ + key: z + .string() + .describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Basic Auth](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#basic-auth).' + ) + .optional(), + bearer: z + .array( + z + .object({ + key: z + .string() + .describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Bearer Token](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#bearer-token) authentication.' + ) + .optional(), + digest: z + .array( + z + .object({ + key: z + .string() + .describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Digest](https://learning.postman.com/docs/sending-requests/authorization/digest-auth/) access authentication.' + ) + .optional(), + edgegrid: z + .array( + z + .object({ + key: z + .string() + .describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Akamai Edgegrid](https://learning.postman.com/docs/sending-requests/authorization/akamai-edgegrid/) authentication.' + ) + .optional(), + hawk: z + .array( + z + .object({ + key: z + .string() + .describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Hawk](https://learning.postman.com/docs/sending-requests/authorization/hawk-authentication/) authentication.' + ) + .optional(), + ntlm: z + .array( + z + .object({ + key: z + .string() + .describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [NTLM](https://learning.postman.com/docs/sending-requests/authorization/ntlm-authentication/) authentication.' + ) + .optional(), + oauth1: z + .array( + z + .object({ + key: z + .string() + .describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [OAuth1](https://learning.postman.com/docs/sending-requests/authorization/oauth-10/) authentication.' + ) + .optional(), + oauth2: z + .array( + z + .object({ + key: z + .string() + .describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [OAuth2](https://learning.postman.com/docs/sending-requests/authorization/oauth-20/) authentication.' + ) + .optional(), + }) + .describe( + 'The [authorization type supported by Postman](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + .optional(), + proxy: z + .object({ + match: z + .string() + .describe( + 'The URL match for the defined proxy configuration.' + ) + .default('http+https://*/*'), + host: z + .string() + .describe("The proxy server's host.") + .optional(), + port: z + .number() + .int() + .gte(0) + .describe("The proxy server's port.") + .default(8080), + tunnel: z + .boolean() + .describe( + 'The tunneling details for the proxy configuration.' + ) + .default(false), + disabled: z + .boolean() + .describe('If true, ignores the proxy configuration.') + .default(false), + }) + .describe('Information about custom proxy confiurations.') + .optional(), + certificate: z + .object({ + name: z + .string() + .describe("The SSL certificate's name.") + .optional(), + matches: z + .array(z.string()) + .describe( + 'A list of URL match pattern strings to identify the URLs the certificate can be used for.' + ) + .optional(), + key: z + .object({ + src: z + .string() + .describe( + 'The path to the file that contains the certificate in the file system.' + ) + .optional(), + }) + .describe('Information about the private key.') + .optional(), + cert: z + .object({ + src: z + .string() + .describe( + 'The path to the file that contains the key for the certificate in the file system.' + ) + .optional(), + }) + .describe('Information about the file certificate.') + .optional(), + passphrase: z + .string() + .describe("The certificate's passphrase.") + .optional(), + }) + .optional(), + method: z + .union([ + z + .enum([ + 'GET', + 'PUT', + 'POST', + 'PATCH', + 'DELETE', + 'COPY', + 'HEAD', + 'OPTIONS', + 'LINK', + 'UNLINK', + 'PURGE', + 'LOCK', + 'UNLOCK', + 'PROPFIND', + 'VIEW', + ]) + .describe("The request's standard HTTP method."), + z.string().describe("The request's custom HTTP method."), + ]) + .optional(), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + header: z + .array( + z + .object({ + key: z + .string() + .describe( + "The header's key, such as `Content-Type` or `X-Custom-Header`." + ), + value: z.string().describe("The header key's value."), + disabled: z + .boolean() + .describe( + "If true, the current header isn't sent with requests." + ) + .default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + .describe('Information about the header.') + ) + .describe('A list of headers.') + .optional(), + body: z + .object({ + mode: z + .enum(['raw', 'urlencoded', 'formdata', 'file', 'graphql']) + .describe('The data associated with the request.') + .optional(), + raw: z + .string() + .describe( + 'If the `mode` value is `raw`, the raw content of the request body.' + ) + .optional(), + urlencoded: z + .array( + z.object({ + key: z.string().describe('The key value.'), + value: z + .string() + .describe("The key's value.") + .optional(), + disabled: z.boolean().default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + ) + .describe('A list of x-www-form-encoded key/value pairs.') + .optional(), + formdata: z + .array( + z.record(z.any()).and( + z.union([ + z.object({ + key: z + .string() + .describe('The key value.') + .optional(), + value: z + .string() + .describe("The key's value.") + .optional(), + disabled: z + .boolean() + .describe( + 'If true, prevents sending the form-data entry.' + ) + .default(false), + type: z + .literal('text') + .describe('The `text` value.') + .optional(), + contentType: z + .string() + .describe('The form-data Content-Type header.') + .optional(), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }), + z.object({ + key: z + .string() + .describe('The key value.') + .optional(), + src: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string().nullable(), + z.array(z.string()), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .optional(), + disabled: z + .boolean() + .describe( + 'If true, prevents sending the form-data entry.' + ) + .default(false), + type: z + .literal('file') + .describe('The `file` value.') + .optional(), + contentType: z + .string() + .describe('The form-data Content-Type header.') + .optional(), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }), + ]) + ) + ) + .describe( + 'If the `mode` value is `formdata`, then a list of form-data key/pair values.' + ) + .optional(), + file: z + .object({ + src: z + .string() + .nullable() + .describe( + 'The name of the file to upload (not its path). A null value indicates that no file is selected as a part of the request body.' + ) + .optional(), + content: z.string().optional(), + }) + .describe( + 'If the `mode` value is `file`, an object containing the file request information.' + ) + .optional(), + graphql: z + .object({ + query: z + .string() + .describe('The GraphQL query.') + .optional(), + variables: z + .string() + .nullable() + .describe( + 'The GraphQL query variables, in JSON format.' + ) + .optional(), + }) + .describe( + 'If the `mode` value is `graphql`, an object containing the GraphQL request information.' + ) + .optional(), + options: z + .record(z.any()) + .describe( + 'Additional configurations and options set for various modes.' + ) + .optional(), + disabled: z + .boolean() + .describe( + 'When set to true, prevents request body from being sent.' + ) + .default(false), + }) + .describe("Information about the collection's request body.") + .optional(), + }), + z.string().nullable(), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => (result.error ? [...errors, result.error] : errors))( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe('Information about the collection request.'), + response: z + .array(z.any().describe("Information about the request's response.")) + .describe("A list of the collection's responses.") + .optional(), + protocolProfileBehavior: z + .object({ + strictSSL: z + .boolean() + .describe('If true, enables certificate verification.') + .optional(), + followRedirects: z + .boolean() + .describe('If true, follow HTTP 3xx responses as redirects.') + .optional(), + maxRedirects: z + .number() + .describe('The maximum number of redirects to follow.') + .optional(), + disableBodyPruning: z + .boolean() + .describe( + 'If true, disables request body pruning for the GET, COPY, HEAD, PURGE, and UNLOCK methods.' + ) + .optional(), + disableUrlEncoding: z + .boolean() + .describe( + 'If true, disables the percent encoding of auth, path, query, and fragment URL segments.' + ) + .optional(), + disabledSystemHeaders: z + .object({ + 'cache-control': z.boolean().optional(), + 'postman-token': z.boolean().optional(), + 'content-type': z.boolean().optional(), + 'content-length': z.boolean().optional(), + 'accept-encoding': z.boolean().optional(), + connection: z.boolean().optional(), + host: z.boolean().optional(), + }) + .describe('Disable the system headers which are added implicitly.') + .optional(), + insecureHTTPParser: z + .boolean() + .describe( + 'If true, uses an insecure HTTP parser that accepts invalid HTTP headers.' + ) + .optional(), + followOriginalHttpMethod: z + .boolean() + .describe( + 'If true, redirects with the original HTTP method. Redirects with the GET HTTP method by default.' + ) + .optional(), + followAuthorizationHeader: z + .boolean() + .describe( + 'If true, retains the `authorization` header when a redirect happens to a different hostname.' + ) + .optional(), + protocolVersion: z + .enum(['http1', 'http2', 'auto']) + .describe( + 'The HTTP protocol version to use. Supports the `http1`, `http2`, and `auto` values.' + ) + .optional(), + removeRefererHeaderOnRedirect: z + .boolean() + .describe( + 'If true, removes the `referer` header when a redirect happens.' + ) + .optional(), + tlsPreferServerCiphers: z + .boolean() + .describe( + "If true, uses the server's cipher suite order instead of the client's during negotiation." + ) + .optional(), + tlsDisabledProtocols: z + .array(z.string()) + .describe( + 'The SSL and TLS protocol versions to disable during negotiation.' + ) + .optional(), + tlsCipherSelection: z + .array(z.string()) + .describe( + 'The order of cipher suites that the SSL server profile uses to establish a secure connection.' + ) + .optional(), + }) + .describe( + 'The [settings](https://learning.postman.com/docs/sending-requests/create-requests/request-settings/) used to alter the [Protocol Profile Behavior](https://github.com/postmanlabs/postman-runtime/blob/develop/docs/protocol-profile-behavior.md) of sending a request.' + ) + .optional(), + }) + .describe('Information about the collection request or folder.'), + z + .object({ + name: z.string().describe("The folder's name.").optional(), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z.string().nullable().describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => (result.error ? [...errors, result.error] : errors))( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z.string().describe("The variable's key (name).").optional(), + value: z.string().describe("The key's value.").optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z.string().describe("The variable's name.").optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe( + "A list of the collection's [variables](https://learning.postman.com/docs/sending-requests/variables/variables/). Make certain not to include sensitive information in variables." + ) + .optional(), + item: z.any(), + event: z + .array( + z + .object({ + id: z.string().describe("The event's ID.").optional(), + listen: z + .enum(['test', 'prerequest']) + .describe( + 'Can be set to `test` or `prerequest` for test scripts or pre-request scripts respectively.' + ), + script: z + .object({ + id: z.string().describe("The script's ID.").optional(), + type: z + .string() + .describe( + 'The type of script. For example, `text/javascript`.' + ) + .optional(), + exec: z + .array(z.string().nullable()) + .describe( + 'A list of script strings, where each line represents a line of code. Separate lines makes it easy to track script changes.' + ) + .optional(), + src: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z + .object({ + raw: z + .string() + .describe("The request's raw URL.") + .optional(), + protocol: z + .string() + .describe('The request protocol.') + .optional(), + host: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string().describe("The host's URL."), + z + .array(z.string().nullable()) + .describe( + "A list of the host's subdomain components." + ), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe("The host's URL.") + .optional(), + path: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string(), + z + .array( + z.any().superRefine((x, ctx) => { + const schemas = [ + z.string().nullable(), + z.object({ + type: z + .string() + .nullable() + .optional(), + value: z + .string() + .nullable() + .optional(), + }), + ]; + const errors = schemas.reduce< + z.ZodError[] + >( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if ( + schemas.length - errors.length !== + 1 + ) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + ) + .describe( + "A list of the URL's path components." + ), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .optional(), + port: z + .string() + .describe( + "The URL's port number. An empty value indicates port `80` (http) or `443` (https)." + ) + .optional(), + query: z + .array( + z.object({ + key: z + .string() + .nullable() + .describe("The query parameter's key.") + .optional(), + value: z + .string() + .nullable() + .describe("The key's value.") + .optional(), + disabled: z + .boolean() + .describe( + "If true, the query parameter isn't sent with the request." + ) + .default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe( + "The description's contents." + ) + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe( + "The collection's description." + ), + ]; + const errors = schemas.reduce< + z.ZodError[] + >( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if ( + schemas.length - errors.length !== + 1 + ) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + ) + .describe( + 'A list of query parameters. These are the query string parts of the URL, parsed as separate variables.' + ) + .optional(), + hash: z + .string() + .describe( + 'Contains the URL fragment (if any). Usually this is not transmitted over the network, but it could be useful to store this in some cases.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z + .string() + .describe("The variable's key (name).") + .optional(), + value: z + .string() + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z + .string() + .describe("The variable's name.") + .optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe('A list of variables.') + .optional(), + }) + .describe('Information about the URL.'), + z.string().describe('The literal request URL.'), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe('Information about the URL.') + .optional(), + name: z.string().describe("The script's name.").optional(), + }) + .describe( + 'Information about the Javascript code that can be used to to perform setup or teardown operations in a response.' + ) + .optional(), + disabled: z + .boolean() + .describe( + 'If true, the event is disabled. If this value is absent, then the event is considered enabled.' + ) + .default(false), + }) + .describe("Information about the collection's events.") + ) + .describe( + 'A list of scripts configured to run when specific events occur. These scripts can be referenced in the collection by their ID.' + ) + .optional(), + auth: z + .object({ + type: z + .enum([ + 'basic', + 'bearer', + 'apikey', + 'digest', + 'oauth1', + 'oauth2', + 'hawk', + 'awsv4', + 'ntlm', + 'edgegrid', + ]) + .describe('The authorization type.'), + apikey: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe("The API key's authentication information.") + .optional(), + awsv4: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [AWS Signature](https://learning.postman.com/docs/sending-requests/authorization/aws-signature/) authentication.' + ) + .optional(), + basic: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Basic Auth](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#basic-auth).' + ) + .optional(), + bearer: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Bearer Token](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#bearer-token) authentication.' + ) + .optional(), + digest: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Digest](https://learning.postman.com/docs/sending-requests/authorization/digest-auth/) access authentication.' + ) + .optional(), + edgegrid: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Akamai Edgegrid](https://learning.postman.com/docs/sending-requests/authorization/akamai-edgegrid/) authentication.' + ) + .optional(), + hawk: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Hawk](https://learning.postman.com/docs/sending-requests/authorization/hawk-authentication/) authentication.' + ) + .optional(), + ntlm: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [NTLM](https://learning.postman.com/docs/sending-requests/authorization/ntlm-authentication/) authentication.' + ) + .optional(), + oauth1: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [OAuth1](https://learning.postman.com/docs/sending-requests/authorization/oauth-10/) authentication.' + ) + .optional(), + oauth2: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum([ + 'string', + 'boolean', + 'number', + 'array', + 'object', + 'any', + ]) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [OAuth2](https://learning.postman.com/docs/sending-requests/authorization/oauth-20/) authentication.' + ) + .optional(), + }) + .describe("Information about the folder's authentication.") + .optional(), + protocolProfileBehavior: z + .object({ + strictSSL: z + .boolean() + .describe('If true, enables certificate verification.') + .optional(), + followRedirects: z + .boolean() + .describe('If true, follow HTTP 3xx responses as redirects.') + .optional(), + maxRedirects: z + .number() + .describe('The maximum number of redirects to follow.') + .optional(), + disableBodyPruning: z + .boolean() + .describe( + 'If true, disables request body pruning for the GET, COPY, HEAD, PURGE, and UNLOCK methods.' + ) + .optional(), + disableUrlEncoding: z + .boolean() + .describe( + 'If true, disables the percent encoding of auth, path, query, and fragment URL segments.' + ) + .optional(), + disabledSystemHeaders: z + .object({ + 'cache-control': z.boolean().optional(), + 'postman-token': z.boolean().optional(), + 'content-type': z.boolean().optional(), + 'content-length': z.boolean().optional(), + 'accept-encoding': z.boolean().optional(), + connection: z.boolean().optional(), + host: z.boolean().optional(), + }) + .describe('Disable the system headers which are added implicitly.') + .optional(), + insecureHTTPParser: z + .boolean() + .describe( + 'If true, uses an insecure HTTP parser that accepts invalid HTTP headers.' + ) + .optional(), + followOriginalHttpMethod: z + .boolean() + .describe( + 'If true, redirects with the original HTTP method. Redirects with the GET HTTP method by default.' + ) + .optional(), + followAuthorizationHeader: z + .boolean() + .describe( + 'If true, retains the `authorization` header when a redirect happens to a different hostname.' + ) + .optional(), + protocolVersion: z + .enum(['http1', 'http2', 'auto']) + .describe( + 'The HTTP protocol version to use. Supports the `http1`, `http2`, and `auto` values.' + ) + .optional(), + removeRefererHeaderOnRedirect: z + .boolean() + .describe( + 'If true, removes the `referer` header when a redirect happens.' + ) + .optional(), + tlsPreferServerCiphers: z + .boolean() + .describe( + "If true, uses the server's cipher suite order instead of the client's during negotiation." + ) + .optional(), + tlsDisabledProtocols: z + .array(z.string()) + .describe( + 'The SSL and TLS protocol versions to disable during negotiation.' + ) + .optional(), + tlsCipherSelection: z + .array(z.string()) + .describe( + 'The order of cipher suites that the SSL server profile uses to establish a secure connection.' + ) + .optional(), + }) + .describe( + 'The [settings](https://learning.postman.com/docs/sending-requests/create-requests/request-settings/) used to alter the [Protocol Profile Behavior](https://github.com/postmanlabs/postman-runtime/blob/develop/docs/protocol-profile-behavior.md) of sending a request.' + ) + .optional(), + }) + .describe( + "Information about the collection's folders. A folder is an organized group of requests." + ), + ]) + ) + .describe( + "A list of the folder's contents, such as requests, responses, and additional folders." + ), + event: z + .array( + z + .object({ + id: z.string().describe("The event's ID.").optional(), + listen: z + .enum(['test', 'prerequest']) + .describe( + 'Can be set to `test` or `prerequest` for test scripts or pre-request scripts respectively.' + ), + script: z + .object({ + id: z.string().describe("The script's ID.").optional(), + type: z + .string() + .describe('The type of script. For example, `text/javascript`.') + .optional(), + exec: z + .array(z.string().nullable()) + .describe( + 'A list of script strings, where each line represents a line of code. Separate lines makes it easy to track script changes.' + ) + .optional(), + src: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z + .object({ + raw: z.string().describe("The request's raw URL.").optional(), + protocol: z + .string() + .describe('The request protocol.') + .optional(), + host: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string().describe("The host's URL."), + z + .array(z.string().nullable()) + .describe( + "A list of the host's subdomain components." + ), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe("The host's URL.") + .optional(), + path: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string(), + z + .array( + z.any().superRefine((x, ctx) => { + const schemas = [ + z.string().nullable(), + z.object({ + type: z.string().nullable().optional(), + value: z.string().nullable().optional(), + }), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + ) + .describe("A list of the URL's path components."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .optional(), + port: z + .string() + .describe( + "The URL's port number. An empty value indicates port `80` (http) or `443` (https)." + ) + .optional(), + query: z + .array( + z.object({ + key: z + .string() + .nullable() + .describe("The query parameter's key.") + .optional(), + value: z + .string() + .nullable() + .describe("The key's value.") + .optional(), + disabled: z + .boolean() + .describe( + "If true, the query parameter isn't sent with the request." + ) + .default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error + ? [...errors, result.error] + : errors)(schema.safeParse(x)), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: + 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + ) + .describe( + 'A list of query parameters. These are the query string parts of the URL, parsed as separate variables.' + ) + .optional(), + hash: z + .string() + .describe( + 'Contains the URL fragment (if any). Usually this is not transmitted over the network, but it could be useful to store this in some cases.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z + .string() + .describe("The variable's key (name).") + .optional(), + value: z + .string() + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z + .string() + .describe("The variable's name.") + .optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe('A list of variables.') + .optional(), + }) + .describe('Information about the URL.'), + z.string().describe('The literal request URL.'), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe('Information about the URL.') + .optional(), + name: z.string().describe("The script's name.").optional(), + }) + .describe( + 'Information about the Javascript code that can be used to to perform setup or teardown operations in a response.' + ) + .optional(), + disabled: z + .boolean() + .describe( + 'If true, the event is disabled. If this value is absent, then the event is considered enabled.' + ) + .default(false), + }) + .describe("Information about the collection's events.") + ) + .describe( + 'A list of scripts configured to run when specific events occur. These scripts can be referenced in the collection by their ID.' + ) + .optional(), + auth: z + .object({ + type: z + .enum([ + 'basic', + 'bearer', + 'apikey', + 'digest', + 'oauth1', + 'oauth2', + 'hawk', + 'awsv4', + 'ntlm', + 'edgegrid', + ]) + .describe('The authorization type.'), + apikey: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe("The API key's authentication information.") + .optional(), + awsv4: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [AWS Signature](https://learning.postman.com/docs/sending-requests/authorization/aws-signature/) authentication.' + ) + .optional(), + basic: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Basic Auth](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#basic-auth).' + ) + .optional(), + bearer: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Bearer Token](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#bearer-token) authentication.' + ) + .optional(), + digest: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Digest](https://learning.postman.com/docs/sending-requests/authorization/digest-auth/) access authentication.' + ) + .optional(), + edgegrid: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Akamai Edgegrid](https://learning.postman.com/docs/sending-requests/authorization/akamai-edgegrid/) authentication.' + ) + .optional(), + hawk: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Hawk](https://learning.postman.com/docs/sending-requests/authorization/hawk-authentication/) authentication.' + ) + .optional(), + ntlm: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [NTLM](https://learning.postman.com/docs/sending-requests/authorization/ntlm-authentication/) authentication.' + ) + .optional(), + oauth1: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [OAuth1](https://learning.postman.com/docs/sending-requests/authorization/oauth-10/) authentication.' + ) + .optional(), + oauth2: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [OAuth2](https://learning.postman.com/docs/sending-requests/authorization/oauth-20/) authentication.' + ) + .optional(), + }) + .describe("Information about the folder's authentication.") + .optional(), + protocolProfileBehavior: z + .object({ + strictSSL: z + .boolean() + .describe('If true, enables certificate verification.') + .optional(), + followRedirects: z + .boolean() + .describe('If true, follow HTTP 3xx responses as redirects.') + .optional(), + maxRedirects: z + .number() + .describe('The maximum number of redirects to follow.') + .optional(), + disableBodyPruning: z + .boolean() + .describe( + 'If true, disables request body pruning for the GET, COPY, HEAD, PURGE, and UNLOCK methods.' + ) + .optional(), + disableUrlEncoding: z + .boolean() + .describe( + 'If true, disables the percent encoding of auth, path, query, and fragment URL segments.' + ) + .optional(), + disabledSystemHeaders: z + .object({ + 'cache-control': z.boolean().optional(), + 'postman-token': z.boolean().optional(), + 'content-type': z.boolean().optional(), + 'content-length': z.boolean().optional(), + 'accept-encoding': z.boolean().optional(), + connection: z.boolean().optional(), + host: z.boolean().optional(), + }) + .describe('Disable the system headers which are added implicitly.') + .optional(), + insecureHTTPParser: z + .boolean() + .describe( + 'If true, uses an insecure HTTP parser that accepts invalid HTTP headers.' + ) + .optional(), + followOriginalHttpMethod: z + .boolean() + .describe( + 'If true, redirects with the original HTTP method. Redirects with the GET HTTP method by default.' + ) + .optional(), + followAuthorizationHeader: z + .boolean() + .describe( + 'If true, retains the `authorization` header when a redirect happens to a different hostname.' + ) + .optional(), + protocolVersion: z + .enum(['http1', 'http2', 'auto']) + .describe( + 'The HTTP protocol version to use. Supports the `http1`, `http2`, and `auto` values.' + ) + .optional(), + removeRefererHeaderOnRedirect: z + .boolean() + .describe('If true, removes the `referer` header when a redirect happens.') + .optional(), + tlsPreferServerCiphers: z + .boolean() + .describe( + "If true, uses the server's cipher suite order instead of the client's during negotiation." + ) + .optional(), + tlsDisabledProtocols: z + .array(z.string()) + .describe('The SSL and TLS protocol versions to disable during negotiation.') + .optional(), + tlsCipherSelection: z + .array(z.string()) + .describe( + 'The order of cipher suites that the SSL server profile uses to establish a secure connection.' + ) + .optional(), + }) + .describe( + 'The [settings](https://learning.postman.com/docs/sending-requests/create-requests/request-settings/) used to alter the [Protocol Profile Behavior](https://github.com/postmanlabs/postman-runtime/blob/develop/docs/protocol-profile-behavior.md) of sending a request.' + ) + .optional(), + }) + .describe( + "Information about the collection's folders. A folder is an organized group of requests." + ), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => (result.error ? [...errors, result.error] : errors))( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + ), + event: z + .array( + z + .object({ + id: z.string().describe("The event's ID.").optional(), + listen: z + .enum(['test', 'prerequest']) + .describe( + 'Can be set to `test` or `prerequest` for test scripts or pre-request scripts respectively.' + ), + script: z + .object({ + id: z.string().describe("The script's ID.").optional(), + type: z + .string() + .describe('The type of script. For example, `text/javascript`.') + .optional(), + exec: z + .array(z.string().nullable()) + .describe( + 'A list of script strings, where each line represents a line of code. Separate lines makes it easy to track script changes.' + ) + .optional(), + src: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z + .object({ + raw: z.string().describe("The request's raw URL.").optional(), + protocol: z.string().describe('The request protocol.').optional(), + host: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string().describe("The host's URL."), + z + .array(z.string().nullable()) + .describe("A list of the host's subdomain components."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe("The host's URL.") + .optional(), + path: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.string(), + z + .array( + z.any().superRefine((x, ctx) => { + const schemas = [ + z.string().nullable(), + z.object({ + type: z.string().nullable().optional(), + value: z.string().nullable().optional(), + }), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + ) + .describe("A list of the URL's path components."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .optional(), + port: z + .string() + .describe( + "The URL's port number. An empty value indicates port `80` (http) or `443` (https)." + ) + .optional(), + query: z + .array( + z.object({ + key: z + .string() + .nullable() + .describe("The query parameter's key.") + .optional(), + value: z + .string() + .nullable() + .describe("The key's value.") + .optional(), + disabled: z + .boolean() + .describe( + "If true, the query parameter isn't sent with the request." + ) + .default(false), + description: z + .any() + .superRefine((x, ctx) => { + const schemas = [ + z.object({ + content: z + .string() + .describe("The description's contents.") + .optional(), + type: z + .string() + .describe( + "The raw description content's MIME type, such as `text/markdown` or `text/html`. The type is used to render the description in the Postman app or when generating documentation." + ) + .optional(), + }), + z + .string() + .nullable() + .describe("The collection's description."), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => + result.error ? [...errors, result.error] : errors)( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe( + 'A description can be a raw text or an object containing the description along with its format.' + ) + .optional(), + }) + ) + .describe( + 'A list of query parameters. These are the query string parts of the URL, parsed as separate variables.' + ) + .optional(), + hash: z + .string() + .describe( + 'Contains the URL fragment (if any). Usually this is not transmitted over the network, but it could be useful to store this in some cases.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z + .string() + .describe("The variable's key (name).") + .optional(), + value: z.string().describe("The key's value.").optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z.string().describe("The variable's name.").optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe('A list of variables.') + .optional(), + }) + .describe('Information about the URL.'), + z.string().describe('The literal request URL.'), + ]; + const errors = schemas.reduce( + (errors, schema) => + ((result) => (result.error ? [...errors, result.error] : errors))( + schema.safeParse(x) + ), + [] + ); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .describe('Information about the URL.') + .optional(), + name: z.string().describe("The script's name.").optional(), + }) + .describe( + 'Information about the Javascript code that can be used to to perform setup or teardown operations in a response.' + ) + .optional(), + disabled: z + .boolean() + .describe( + 'If true, the event is disabled. If this value is absent, then the event is considered enabled.' + ) + .default(false), + }) + .describe("Information about the collection's events.") + ) + .describe( + 'A list of scripts configured to run when specific events occur. These scripts can be referenced in the collection by their ID.' + ) + .optional(), + variable: z + .array( + z + .object({ + key: z.string().describe("The variable's key (name).").optional(), + value: z.string().describe("The key's value.").optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + name: z.string().describe("The variable's name.").optional(), + description: z + .string() + .describe( + "The variable's description. Doesn't apply to collection-level variables." + ) + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.') + ) + .describe( + "A list of the collection's [variables](https://learning.postman.com/docs/sending-requests/variables/variables/). Make certain not to include sensitive information in variables." + ) + .optional(), + auth: z + .object({ + type: z + .enum([ + 'basic', + 'bearer', + 'apikey', + 'digest', + 'oauth1', + 'oauth2', + 'hawk', + 'awsv4', + 'ntlm', + 'edgegrid', + ]) + .describe('The authorization type.'), + apikey: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe("The API key's authentication information.") + .optional(), + awsv4: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [AWS Signature](https://learning.postman.com/docs/sending-requests/authorization/aws-signature/) authentication.' + ) + .optional(), + basic: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Basic Auth](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#basic-auth).' + ) + .optional(), + bearer: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Bearer Token](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#bearer-token) authentication.' + ) + .optional(), + digest: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Digest](https://learning.postman.com/docs/sending-requests/authorization/digest-auth/) access authentication.' + ) + .optional(), + edgegrid: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Akamai Edgegrid](https://learning.postman.com/docs/sending-requests/authorization/akamai-edgegrid/) authentication.' + ) + .optional(), + hawk: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [Hawk](https://learning.postman.com/docs/sending-requests/authorization/hawk-authentication/) authentication.' + ) + .optional(), + ntlm: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [NTLM](https://learning.postman.com/docs/sending-requests/authorization/ntlm-authentication/) authentication.' + ) + .optional(), + oauth1: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [OAuth1](https://learning.postman.com/docs/sending-requests/authorization/oauth-10/) authentication.' + ) + .optional(), + oauth2: z + .array( + z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe( + 'Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + ) + .describe( + 'The attributes for [OAuth2](https://learning.postman.com/docs/sending-requests/authorization/oauth-20/) authentication.' + ) + .optional(), + }) + .describe( + 'The [authorization type supported by Postman](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).' + ) + .optional(), + protocolProfileBehavior: z + .object({ + strictSSL: z.boolean().describe('If true, enables certificate verification.').optional(), + followRedirects: z + .boolean() + .describe('If true, follow HTTP 3xx responses as redirects.') + .optional(), + maxRedirects: z + .number() + .describe('The maximum number of redirects to follow.') + .optional(), + disableBodyPruning: z + .boolean() + .describe( + 'If true, disables request body pruning for the GET, COPY, HEAD, PURGE, and UNLOCK methods.' + ) + .optional(), + disableUrlEncoding: z + .boolean() + .describe( + 'If true, disables the percent encoding of auth, path, query, and fragment URL segments.' + ) + .optional(), + disabledSystemHeaders: z + .object({ + 'cache-control': z.boolean().optional(), + 'postman-token': z.boolean().optional(), + 'content-type': z.boolean().optional(), + 'content-length': z.boolean().optional(), + 'accept-encoding': z.boolean().optional(), + connection: z.boolean().optional(), + host: z.boolean().optional(), + }) + .describe('Disable the system headers which are added implicitly.') + .optional(), + insecureHTTPParser: z + .boolean() + .describe('If true, uses an insecure HTTP parser that accepts invalid HTTP headers.') + .optional(), + followOriginalHttpMethod: z + .boolean() + .describe( + 'If true, redirects with the original HTTP method. Redirects with the GET HTTP method by default.' + ) + .optional(), + followAuthorizationHeader: z + .boolean() + .describe( + 'If true, retains the `authorization` header when a redirect happens to a different hostname.' + ) + .optional(), + protocolVersion: z + .enum(['http1', 'http2', 'auto']) + .describe( + 'The HTTP protocol version to use. Supports the `http1`, `http2`, and `auto` values.' + ) + .optional(), + removeRefererHeaderOnRedirect: z + .boolean() + .describe('If true, removes the `referer` header when a redirect happens.') + .optional(), + tlsPreferServerCiphers: z + .boolean() + .describe( + "If true, uses the server's cipher suite order instead of the client's during negotiation." + ) + .optional(), + tlsDisabledProtocols: z + .array(z.string()) + .describe('The SSL and TLS protocol versions to disable during negotiation.') + .optional(), + tlsCipherSelection: z + .array(z.string()) + .describe( + 'The order of cipher suites that the SSL server profile uses to establish a secure connection.' + ) + .optional(), + }) + .describe( + 'The [settings](https://learning.postman.com/docs/sending-requests/create-requests/request-settings/) used to alter the [Protocol Profile Behavior](https://github.com/postmanlabs/postman-runtime/blob/develop/docs/protocol-profile-behavior.md) of sending a request.' + ) + .optional(), + }) + .optional(), +}); +export const annotations = { + title: + "Replaces the contents of a collection using the [Postman Collection v2.1.0 schema format](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html). Include the collection's ID values in the request body. If you do not, the endpoint removes the existing items and creates new items.\n\nTo perform an update asynchronously, use the \\`Prefer\\` header with the \\`respond-async\\` value. When performing an async update, this endpoint returns a HTTP \\`202 Accepted\\` response.\n\n> The maximum collection size this endpoint accepts cannot exceed 100 MB.\n\nFor a complete list of available property values for this endpoint, use the following references available in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html):\n- \\`info\\` object — Refer to the **Information** entry.\n- \\`item\\` object — Refer to the **Items** entry.\n- For all other possible values, refer to the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n- For protocol profile behavior, refer to Postman's [Protocol Profile Behavior documentation](https://github.com/postmanlabs/postman-runtime/blob/develop/docs/protocol-profile-behavior.md).\n\n**Note:**\n\n- If you don't include the collection items' ID values from the request body, the endpoint **removes** the existing items and recreates the items with new ID values.\n- To copy another collection's contents to the given collection, remove all ID values before you pass it in this endpoint. If you do not, this endpoint returns an error. These values include the \\`id\\`, \\`uid\\`, and \\`postman_id\\` values.\n", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.collection !== undefined) bodyPayload.collection = params.collection; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/put_environment.ts b/src/tools/put_environment.ts new file mode 100644 index 0000000..f99dd58 --- /dev/null +++ b/src/tools/put_environment.ts @@ -0,0 +1,63 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'put-environment'; +export const description = + 'Replaces all the contents of an environment with the given information.\n\n**Note:**\n\n- The request body size cannot exceed the maximum allowed size of 30MB.\n- If you receive an HTTP \\`411 Length Required\\` error response, manually pass the \\`Content-Length\\` header and its value in the request header.\n'; +export const parameters = z.object({ + environmentId: z.string().describe("The environment's ID."), + environment: z + .object({ + name: z.string().describe("The environment's name.").optional(), + values: z + .array( + z.object({ + enabled: z.boolean().describe('If true, the variable is enabled.').optional(), + key: z.string().describe("The variable's name.").optional(), + value: z.string().describe("The variable's value.").optional(), + type: z.enum(['secret', 'default', 'any']).describe('The variable type.').optional(), + }) + ) + .describe("Information about the environment's variables.") + .optional(), + }) + .optional(), +}); +export const annotations = { + title: + 'Replaces all the contents of an environment with the given information.\n\n**Note:**\n\n- The request body size cannot exceed the maximum allowed size of 30MB.\n- If you receive an HTTP \\`411 Length Required\\` error response, manually pass the \\`Content-Length\\` header and its value in the request header.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/environments/${params.environmentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.environment !== undefined) bodyPayload.environment = params.environment; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/resolve_comment_thread.ts b/src/tools/resolve_comment_thread.ts new file mode 100644 index 0000000..c1a3e18 --- /dev/null +++ b/src/tools/resolve_comment_thread.ts @@ -0,0 +1,43 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'resolve-comment-thread'; +export const description = + 'Resolves a comment and any associated replies. On success, this returns an HTTP \\`204 No Content\\` response.\n\nComment thread IDs return in the GET comments response for [APIs](https://www.postman.com/postman/workspace/postman-public-workspace/request/12959542-2103ea20-f7de-4628-90e6-b823b3084a52), [collections](https://www.postman.com/postman/workspace/postman-public-workspace/request/12959542-a6582e0a-9382-4760-8b91-53a8aa6cb8d7), and [collection items](https://www.postman.com/postman/workspace/postman-public-workspace/folder/12959542-efeda219-66e1-474c-a83b-253d15723bf7).\n'; +export const parameters = z.object({ + threadId: z.number().int().describe("The comment's thread ID."), +}); +export const annotations = { + title: + 'Resolves a comment and any associated replies. On success, this returns an HTTP \\`204 No Content\\` response.\n\nComment thread IDs return in the GET comments response for [APIs](https://www.postman.com/postman/workspace/postman-public-workspace/request/12959542-2103ea20-f7de-4628-90e6-b823b3084a52), [collections](https://www.postman.com/postman/workspace/postman-public-workspace/request/12959542-a6582e0a-9382-4760-8b91-53a8aa6cb8d7), and [collection items](https://www.postman.com/postman/workspace/postman-public-workspace/folder/12959542-efeda219-66e1-474c-a83b-253d15723bf7).\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/comments-resolutions/${params.threadId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'POST', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/run_monitor.ts b/src/tools/run_monitor.ts new file mode 100644 index 0000000..a474343 --- /dev/null +++ b/src/tools/run_monitor.ts @@ -0,0 +1,50 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'run-monitor'; +export const description = + 'Runs a monitor and returns its run results.\n\n**Note:**\n\n- This endpoint has a timeout restriction of 300 seconds. It is recommended that you include the \\`async=true\\` query parameter when using this endpoint.\n- If you pass the \\`async=true\\` query parameter, the response does not return the \\`stats\\`, \\`executions\\`, and \\`failures\\` responses. To get this information for an asynchronous run, call the GET \\`/monitors/{id}\\` endpoint.\n'; +export const parameters = z.object({ + monitorId: z.string().describe("The monitor's ID."), + async: z + .boolean() + .describe( + 'If true, runs the monitor asynchronously from the created monitor run task. By default, the server will not respond until the task finishes (`false`).' + ) + .default(false), +}); +export const annotations = { + title: + 'Runs a monitor and returns its run results.\n\n**Note:**\n\n- This endpoint has a timeout restriction of 300 seconds. It is recommended that you include the \\`async=true\\` query parameter when using this endpoint.\n- If you pass the \\`async=true\\` query parameter, the response does not return the \\`stats\\`, \\`executions\\`, and \\`failures\\` responses. To get this information for an asynchronous run, call the GET \\`/monitors/{id}\\` endpoint.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/monitors/${params.monitorId}/run`; + const query = new URLSearchParams(); + if (params.async !== undefined) query.set('async', String(params.async)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'POST', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/sync_collection_with_spec.ts b/src/tools/sync_collection_with_spec.ts new file mode 100644 index 0000000..0ec62a2 --- /dev/null +++ b/src/tools/sync_collection_with_spec.ts @@ -0,0 +1,45 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'sync-collection-with-spec'; +export const description = + 'Syncs a collection generated from an API specification. This is an asynchronous endpoint that returns an HTTP \\`202 Accepted\\` response.\n\n**Note:**\n\n- This endpoint only supports the OpenAPI 3.0 specification type.\n- You can only sync collections generated from the given spec ID.\n'; +export const parameters = z.object({ + collectionUid: z.string().describe("The collection's unique ID."), + specId: z.string().describe("The spec's ID."), +}); +export const annotations = { + title: + 'Syncs a collection generated from an API specification. This is an asynchronous endpoint that returns an HTTP \\`202 Accepted\\` response.\n\n**Note:**\n\n- This endpoint only supports the OpenAPI 3.0 specification type.\n- You can only sync collections generated from the given spec ID.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionUid}/synchronizations`; + const query = new URLSearchParams(); + if (params.specId !== undefined) query.set('specId', String(params.specId)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/sync_spec_with_collection.ts b/src/tools/sync_spec_with_collection.ts new file mode 100644 index 0000000..5c9cdf8 --- /dev/null +++ b/src/tools/sync_spec_with_collection.ts @@ -0,0 +1,46 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'sync-spec-with-collection'; +export const description = + 'Syncs an API specification linked to a collection. This is an asynchronous endpoint that returns an HTTP \\`202 Accepted\\` response.\n\n**Note:**\n\n- This endpoint only supports the OpenAPI 3.0 specification type.\n- You can only sync specs generated from the given collection ID.\n'; +export const parameters = z.object({ + specId: z.string().describe("The spec's ID."), + collectionUid: z.string().describe("The collection's unique ID."), +}); +export const annotations = { + title: + 'Syncs an API specification linked to a collection. This is an asynchronous endpoint that returns an HTTP \\`202 Accepted\\` response.\n\n**Note:**\n\n- This endpoint only supports the OpenAPI 3.0 specification type.\n- You can only sync specs generated from the given collection ID.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/specs/${params.specId}/synchronizations`; + const query = new URLSearchParams(); + if (params.collectionUid !== undefined) + query.set('collectionUid', String(params.collectionUid)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/transfer_collection_folders.ts b/src/tools/transfer_collection_folders.ts new file mode 100644 index 0000000..0c9ef45 --- /dev/null +++ b/src/tools/transfer_collection_folders.ts @@ -0,0 +1,83 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'transfer-collection-folders'; +export const description = 'Copies or moves folders into a collection or folder.'; +export const parameters = z.object({ + ids: z + .array(z.string()) + .describe('A list of collection request, response, or folder UIDs to transfer.'), + mode: z.enum(['copy', 'move']).describe('The transfer operation to perform.'), + target: z + .object({ + id: z.string().describe('The UID of the destination collection, folder, or request.'), + model: z + .enum(['collection', 'folder', 'request']) + .describe( + 'The collection, folder, or request the items will be transferred to. For response transfers, use the `request` value.' + ), + }) + .describe("Information about the item transfer's destination location."), + location: z + .object({ + id: z + .string() + .nullable() + .describe("For `before` or `after` positions, the model's UID.") + .optional(), + model: z + .string() + .nullable() + .describe( + 'For `before` or `after` positions, the type of item (model) that the transferred item will be positioned by. One of: `folder`, `request`, or `response.`\n' + ) + .optional(), + position: z + .enum(['start', 'end', 'before', 'after']) + .describe("The transferred item's position within the destination object.") + .default('end'), + }) + .describe( + "The transferred items' placement in the target destination:\n- For `start` or `end` — Do not include the `model` and `id` values.\n- For `before` or `after` — Include the `model` and `id` properties.\n" + ), +}); +export const annotations = { + title: 'Copies or moves folders into a collection or folder.', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collection-folders-transfers`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.ids !== undefined) bodyPayload.ids = params.ids; + if (params.mode !== undefined) bodyPayload.mode = params.mode; + if (params.target !== undefined) bodyPayload.target = params.target; + if (params.location !== undefined) bodyPayload.location = params.location; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/transfer_collection_requests.ts b/src/tools/transfer_collection_requests.ts new file mode 100644 index 0000000..af0db26 --- /dev/null +++ b/src/tools/transfer_collection_requests.ts @@ -0,0 +1,83 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'transfer-collection-requests'; +export const description = 'Copies or moves requests into a collection or folder.'; +export const parameters = z.object({ + ids: z + .array(z.string()) + .describe('A list of collection request, response, or folder UIDs to transfer.'), + mode: z.enum(['copy', 'move']).describe('The transfer operation to perform.'), + target: z + .object({ + id: z.string().describe('The UID of the destination collection, folder, or request.'), + model: z + .enum(['collection', 'folder', 'request']) + .describe( + 'The collection, folder, or request the items will be transferred to. For response transfers, use the `request` value.' + ), + }) + .describe("Information about the item transfer's destination location."), + location: z + .object({ + id: z + .string() + .nullable() + .describe("For `before` or `after` positions, the model's UID.") + .optional(), + model: z + .string() + .nullable() + .describe( + 'For `before` or `after` positions, the type of item (model) that the transferred item will be positioned by. One of: `folder`, `request`, or `response.`\n' + ) + .optional(), + position: z + .enum(['start', 'end', 'before', 'after']) + .describe("The transferred item's position within the destination object.") + .default('end'), + }) + .describe( + "The transferred items' placement in the target destination:\n- For `start` or `end` — Do not include the `model` and `id` values.\n- For `before` or `after` — Include the `model` and `id` properties.\n" + ), +}); +export const annotations = { + title: 'Copies or moves requests into a collection or folder.', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collection-requests-transfers`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.ids !== undefined) bodyPayload.ids = params.ids; + if (params.mode !== undefined) bodyPayload.mode = params.mode; + if (params.target !== undefined) bodyPayload.target = params.target; + if (params.location !== undefined) bodyPayload.location = params.location; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/transfer_collection_responses.ts b/src/tools/transfer_collection_responses.ts new file mode 100644 index 0000000..09b6aa0 --- /dev/null +++ b/src/tools/transfer_collection_responses.ts @@ -0,0 +1,83 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'transfer-collection-responses'; +export const description = 'Copies or moves responses into a request.'; +export const parameters = z.object({ + ids: z + .array(z.string()) + .describe('A list of collection request, response, or folder UIDs to transfer.'), + mode: z.enum(['copy', 'move']).describe('The transfer operation to perform.'), + target: z + .object({ + id: z.string().describe('The UID of the destination collection, folder, or request.'), + model: z + .enum(['collection', 'folder', 'request']) + .describe( + 'The collection, folder, or request the items will be transferred to. For response transfers, use the `request` value.' + ), + }) + .describe("Information about the item transfer's destination location."), + location: z + .object({ + id: z + .string() + .nullable() + .describe("For `before` or `after` positions, the model's UID.") + .optional(), + model: z + .string() + .nullable() + .describe( + 'For `before` or `after` positions, the type of item (model) that the transferred item will be positioned by. One of: `folder`, `request`, or `response.`\n' + ) + .optional(), + position: z + .enum(['start', 'end', 'before', 'after']) + .describe("The transferred item's position within the destination object.") + .default('end'), + }) + .describe( + "The transferred items' placement in the target destination:\n- For `start` or `end` — Do not include the `model` and `id` values.\n- For `before` or `after` — Include the `model` and `id` properties.\n" + ), +}); +export const annotations = { + title: 'Copies or moves responses into a request.', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collection-responses-transfers`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.ids !== undefined) bodyPayload.ids = params.ids; + if (params.mode !== undefined) bodyPayload.mode = params.mode; + if (params.target !== undefined) bodyPayload.target = params.target; + if (params.location !== undefined) bodyPayload.location = params.location; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/unpublish_documentation.ts b/src/tools/unpublish_documentation.ts new file mode 100644 index 0000000..a1e7a45 --- /dev/null +++ b/src/tools/unpublish_documentation.ts @@ -0,0 +1,43 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'unpublish-documentation'; +export const description = + "Unpublishes a collection's documentation. On success, this returns an HTTP \\`204 No Content\\` response."; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), +}); +export const annotations = { + title: + "Unpublishes a collection's documentation. On success, this returns an HTTP \\`204 No Content\\` response.", + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/public-documentations`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/unpublish_mock.ts b/src/tools/unpublish_mock.ts new file mode 100644 index 0000000..d340b83 --- /dev/null +++ b/src/tools/unpublish_mock.ts @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'unpublish-mock'; +export const description = + 'Unpublishes a mock server. Unpublishing a mock server sets its **Access Control** configuration setting to private.'; +export const parameters = z.object({ mockId: z.string().describe("The mock's ID.") }); +export const annotations = { + title: + 'Unpublishes a mock server. Unpublishing a mock server sets its **Access Control** configuration setting to private.', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/mocks/${params.mockId}/unpublish`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/update_api_collection_comment.ts b/src/tools/update_api_collection_comment.ts new file mode 100644 index 0000000..a3dfcdf --- /dev/null +++ b/src/tools/update_api_collection_comment.ts @@ -0,0 +1,65 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'update-api-collection-comment'; +export const description = + "Updates a comment on an API's collection.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n"; +export const parameters = z.object({ + apiId: z.string().describe("The API's ID."), + collectionId: z.string().describe("The collection's unique ID."), + commentId: z.number().int().describe("The comment's ID."), + body: z.string().describe('The contents of the comment.'), + tags: z + .object({ + userName: z + .object({ + type: z.literal('user').describe('The `user` value.'), + id: z.number().int().describe("The user's ID."), + }) + .describe( + "An object that contains information about the tagged user. The object's name is the user's Postman username. For example, `@user-postman`." + ) + .optional(), + }) + .describe('Information about users tagged in the `body` comment.') + .optional(), +}); +export const annotations = { + title: + "Updates a comment on an API's collection.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/apis/${params.apiId}/collections/${params.collectionId}/comments/${params.commentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.body !== undefined) bodyPayload.body = params.body; + if (params.tags !== undefined) bodyPayload.tags = params.tags; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/update_collection_comment.ts b/src/tools/update_collection_comment.ts new file mode 100644 index 0000000..6995234 --- /dev/null +++ b/src/tools/update_collection_comment.ts @@ -0,0 +1,64 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'update-collection-comment'; +export const description = + 'Updates a comment on a collection.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + commentId: z.number().int().describe("The comment's ID."), + body: z.string().describe('The contents of the comment.'), + tags: z + .object({ + userName: z + .object({ + type: z.literal('user').describe('The `user` value.'), + id: z.number().int().describe("The user's ID."), + }) + .describe( + "An object that contains information about the tagged user. The object's name is the user's Postman username. For example, `@user-postman`." + ) + .optional(), + }) + .describe('Information about users tagged in the `body` comment.') + .optional(), +}); +export const annotations = { + title: + 'Updates a comment on a collection.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/comments/${params.commentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.body !== undefined) bodyPayload.body = params.body; + if (params.tags !== undefined) bodyPayload.tags = params.tags; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/update_collection_folder.ts b/src/tools/update_collection_folder.ts new file mode 100644 index 0000000..95ecb23 --- /dev/null +++ b/src/tools/update_collection_folder.ts @@ -0,0 +1,51 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'update-collection-folder'; +export const description = + 'Updates a folder in a collection. For a complete list of properties, refer to the **Folder** entry in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\nThis endpoint acts like a PATCH method. It only updates the values that you pass in the request body (for example, the \\`name\\` property). The endpoint does not update the entire resource.\n'; +export const parameters = z.object({ + folderId: z.string().describe("The folder's ID."), + collectionId: z.string().describe("The collection's ID."), + name: z.string().describe("The folder's name.").optional(), + description: z.string().describe("The folder's description.").optional(), +}); +export const annotations = { + title: + 'Updates a folder in a collection. For a complete list of properties, refer to the **Folder** entry in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\nThis endpoint acts like a PATCH method. It only updates the values that you pass in the request body (for example, the \\`name\\` property). The endpoint does not update the entire resource.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/folders/${params.folderId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.name !== undefined) bodyPayload.name = params.name; + if (params.description !== undefined) bodyPayload.description = params.description; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/update_collection_request.ts b/src/tools/update_collection_request.ts new file mode 100644 index 0000000..f29ab8c --- /dev/null +++ b/src/tools/update_collection_request.ts @@ -0,0 +1,70 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'update-collection-request'; +export const description = + 'Updates a request in a collection. For a complete list of properties, refer to the **Request** entry in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\n- You must pass a collection ID (\\`12ece9e1-2abf-4edc-8e34-de66e74114d2\\`), not a collection(\\`12345678-12ece9e1-2abf-4edc-8e34-de66e74114d2\\`), in this endpoint.\n- This endpoint does not support changing the folder of a request.\n'; +export const parameters = z.object({ + requestId: z.string().describe("The request's ID."), + collectionId: z.string().describe("The collection's ID."), + name: z.string().describe("The request's name.").optional(), + method: z + .enum([ + 'GET', + 'PUT', + 'POST', + 'PATCH', + 'DELETE', + 'COPY', + 'HEAD', + 'OPTIONS', + 'LINK', + 'UNLINK', + 'PURGE', + 'LOCK', + 'UNLOCK', + 'PROPFIND', + 'VIEW', + ]) + .describe("The request's method.") + .optional(), +}); +export const annotations = { + title: + 'Updates a request in a collection. For a complete list of properties, refer to the **Request** entry in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\n- You must pass a collection ID (\\`12ece9e1-2abf-4edc-8e34-de66e74114d2\\`), not a collection(\\`12345678-12ece9e1-2abf-4edc-8e34-de66e74114d2\\`), in this endpoint.\n- This endpoint does not support changing the folder of a request.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/requests/${params.requestId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.name !== undefined) bodyPayload.name = params.name; + if (params.method !== undefined) bodyPayload.method = params.method; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/update_collection_response.ts b/src/tools/update_collection_response.ts new file mode 100644 index 0000000..8745ab3 --- /dev/null +++ b/src/tools/update_collection_response.ts @@ -0,0 +1,57 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'update-collection-response'; +export const description = + 'Updates a response in a collection. For a complete list of properties, see the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\n- You must pass a collection ID (\\`12ece9e1-2abf-4edc-8e34-de66e74114d2\\`), not a collection UID (\\`12345678-12ece9e1-2abf-4edc-8e34-de66e74114d2\\`), in this endpoint.\n- This endpoint acts like a PATCH method. It only updates the values that you pass in the request body (for example, the \\`name\\` property). The endpoint does not update the entire resource.\n'; +export const parameters = z.object({ + responseId: z.string().describe("The response's ID."), + collectionId: z.string().describe("The collection's ID."), + name: z.string().describe("The response's name.").optional(), + responseCode: z + .object({ + code: z.number().describe("The response's HTTP response status code.").optional(), + name: z.string().describe('The name of the status code.').optional(), + }) + .describe("The response's HTTP response code information.") + .optional(), +}); +export const annotations = { + title: + 'Updates a response in a collection. For a complete list of properties, see the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\n- You must pass a collection ID (\\`12ece9e1-2abf-4edc-8e34-de66e74114d2\\`), not a collection UID (\\`12345678-12ece9e1-2abf-4edc-8e34-de66e74114d2\\`), in this endpoint.\n- This endpoint acts like a PATCH method. It only updates the values that you pass in the request body (for example, the \\`name\\` property). The endpoint does not update the entire resource.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/responses/${params.responseId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.name !== undefined) bodyPayload.name = params.name; + if (params.responseCode !== undefined) bodyPayload.responseCode = params.responseCode; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/update_collection_tags.ts b/src/tools/update_collection_tags.ts new file mode 100644 index 0000000..61517d0 --- /dev/null +++ b/src/tools/update_collection_tags.ts @@ -0,0 +1,63 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'update-collection-tags'; +export const description = + "Updates a collection's associated tags. This endpoint replaces all existing tags with those you pass in the request body."; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + tags: z + .array( + z + .object({ + slug: z + .string() + .regex(new RegExp('^[a-z][a-z0-9-]*[a-z0-9]+$')) + .min(2) + .max(64) + .describe("The tag's ID within a team or individual (non-team) user scope."), + }) + .describe('Information about the tag.') + ) + .min(0) + .max(5) + .describe('A list of the associated tags as slugs.'), +}); +export const annotations = { + title: + "Updates a collection's associated tags. This endpoint replaces all existing tags with those you pass in the request body.", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/tags`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.tags !== undefined) bodyPayload.tags = params.tags; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/update_folder_comment.ts b/src/tools/update_folder_comment.ts new file mode 100644 index 0000000..df08cd9 --- /dev/null +++ b/src/tools/update_folder_comment.ts @@ -0,0 +1,65 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'update-folder-comment'; +export const description = + 'Updates a comment on a folder.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + folderId: z.string().describe("The folder's unique ID."), + commentId: z.number().int().describe("The comment's ID."), + body: z.string().describe('The contents of the comment.'), + tags: z + .object({ + userName: z + .object({ + type: z.literal('user').describe('The `user` value.'), + id: z.number().int().describe("The user's ID."), + }) + .describe( + "An object that contains information about the tagged user. The object's name is the user's Postman username. For example, `@user-postman`." + ) + .optional(), + }) + .describe('Information about users tagged in the `body` comment.') + .optional(), +}); +export const annotations = { + title: + 'Updates a comment on a folder.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/folders/${params.folderId}/comments/${params.commentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.body !== undefined) bodyPayload.body = params.body; + if (params.tags !== undefined) bodyPayload.tags = params.tags; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/update_mock.ts b/src/tools/update_mock.ts new file mode 100644 index 0000000..2726999 --- /dev/null +++ b/src/tools/update_mock.ts @@ -0,0 +1,71 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'update-mock'; +export const description = 'Updates a mock server.'; +export const parameters = z.object({ + mockId: z.string().describe("The mock's ID."), + mock: z + .object({ + name: z.string().describe("The mock server's name.").optional(), + environment: z.string().describe("The associated environment's unique ID.").optional(), + description: z.string().describe("The mock server's description.").optional(), + private: z + .boolean() + .describe( + 'If true, the mock server is set private. By default, mock servers are public and can receive requests from anyone and anywhere.' + ) + .default(false), + versionTag: z.string().describe("The API's version tag ID.").optional(), + config: z + .object({ + serverResponseId: z + .string() + .nullable() + .describe( + 'The server response ID. This sets the given server response as the default response for each request. To deactivate a server response, pass a null value.' + ) + .optional(), + }) + .describe("The mock server's configuration settings.") + .optional(), + }) + .optional(), +}); +export const annotations = { + title: 'Updates a mock server.', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/mocks/${params.mockId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.mock !== undefined) bodyPayload.mock = params.mock; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/update_monitor.ts b/src/tools/update_monitor.ts new file mode 100644 index 0000000..8241841 --- /dev/null +++ b/src/tools/update_monitor.ts @@ -0,0 +1,160 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'update-monitor'; +export const description = + "Updates a monitor's [configurations](https://learning.postman.com/docs/monitoring-your-api/setting-up-monitor/#configure-a-monitor)."; +export const parameters = z.object({ + monitorId: z.string().describe("The monitor's ID."), + monitor: z + .object({ + name: z.string().describe("The monitor's name.").optional(), + active: z + .boolean() + .describe('If true, the monitor is active and makes calls to the specified URL.') + .default(true), + notificationLimit: z + .number() + .gte(1) + .lte(99) + .describe('Stop email notifications after the given number consecutive failures.') + .optional(), + retry: z + .object({ + attempts: z + .number() + .gte(1) + .lte(2) + .describe( + 'The number of times to reattempt a monitor run if it fails or errors. This may impact your [monitor usage](https://learning.postman.com/docs/monitoring-your-api/monitor-usage/#view-monitor-usage).' + ) + .optional(), + }) + .optional(), + options: z + .object({ + followRedirects: z.boolean().describe('If true, follow redirects enabled.').optional(), + requestDelay: z + .number() + .gte(1) + .lte(900000) + .describe("The monitor's request delay value, in milliseconds.") + .optional(), + requestTimeout: z + .number() + .gte(1) + .lte(900000) + .describe("The monitor's request timeout value, in milliseconds.") + .optional(), + strictSSL: z.boolean().describe('If true, strict SSL enabled.').optional(), + }) + .describe("Information about the monitor's option settings.") + .optional(), + schedule: z + .object({ + cron: z + .string() + .describe( + 'The cron expression that defines when the monitor runs. Use standard five-field POSIX cron syntax.\n' + ) + .optional(), + timezone: z + .string() + .describe( + "The monitor's [timezone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)." + ) + .optional(), + }) + .describe("Information about the monitor's schedule.") + .optional(), + distribution: z + .array( + z.object({ + region: z + .enum([ + 'us-east', + 'us-west', + 'ap-southeast', + 'ca-central', + 'eu-central', + 'sa-east', + 'uk', + 'us-east-staticip', + 'us-west-staticip', + ]) + .describe('The assigned distribution region.') + .optional(), + }) + ) + .describe( + "A list of the monitor's [geographic regions](https://learning.postman.com/docs/monitoring-your-api/setting-up-monitor/#add-regions)." + ) + .optional(), + notifications: z + .object({ + onError: z + .array( + z.object({ + email: z + .string() + .email() + .describe('The email address of the user to notify on monitor error.') + .optional(), + }) + ) + .optional(), + onFailure: z + .array( + z.object({ + email: z + .string() + .email() + .describe('The email address of the user to notify on monitor failure.') + .optional(), + }) + ) + .optional(), + }) + .describe("Information about the monitor's notification settings.") + .optional(), + }) + .optional(), +}); +export const annotations = { + title: + "Updates a monitor's [configurations](https://learning.postman.com/docs/monitoring-your-api/setting-up-monitor/#configure-a-monitor).", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/monitors/${params.monitorId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.monitor !== undefined) bodyPayload.monitor = params.monitor; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/update_pan_element_or_folder.ts b/src/tools/update_pan_element_or_folder.ts new file mode 100644 index 0000000..ea927d6 --- /dev/null +++ b/src/tools/update_pan_element_or_folder.ts @@ -0,0 +1,48 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; + +export const method = 'update-pan-element-or-folder'; +export const description = + "Updates an element or folder in your team's [Private API Network](https://learning.postman.com/docs/collaborating-in-postman/adding-private-network/).\n\n**Note:**\n\nYou can only pass one element object type per call. For example, you cannot pass both \\`api\\` and \\`collection\\` in a single request.\n"; +export const parameters = z.object({ + elementId: z + .string() + .describe( + "The element's ID or UUID. For Postman Collections you must pass the collection's UID (`userId`-`collectionId`) value." + ), + elementType: z.enum(['api', 'folder', 'collection', 'workspace']).describe('The element type.'), +}); +export const annotations = { + title: + "Updates an element or folder in your team's [Private API Network](https://learning.postman.com/docs/collaborating-in-postman/adding-private-network/).\n\n**Note:**\n\nYou can only pass one element object type per call. For example, you cannot pass both \\`api\\` and \\`collection\\` in a single request.\n", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/network/private/${params.elementType}/${params.elementId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/update_request_comment.ts b/src/tools/update_request_comment.ts new file mode 100644 index 0000000..88722d6 --- /dev/null +++ b/src/tools/update_request_comment.ts @@ -0,0 +1,65 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'update-request-comment'; +export const description = + 'Updates a comment on a request.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + requestId: z.string().describe("The request's unique ID."), + commentId: z.number().int().describe("The comment's ID."), + body: z.string().describe('The contents of the comment.'), + tags: z + .object({ + userName: z + .object({ + type: z.literal('user').describe('The `user` value.'), + id: z.number().int().describe("The user's ID."), + }) + .describe( + "An object that contains information about the tagged user. The object's name is the user's Postman username. For example, `@user-postman`." + ) + .optional(), + }) + .describe('Information about users tagged in the `body` comment.') + .optional(), +}); +export const annotations = { + title: + 'Updates a comment on a request.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/requests/${params.requestId}/comments/${params.commentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.body !== undefined) bodyPayload.body = params.body; + if (params.tags !== undefined) bodyPayload.tags = params.tags; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/update_response_comment.ts b/src/tools/update_response_comment.ts new file mode 100644 index 0000000..75caa4b --- /dev/null +++ b/src/tools/update_response_comment.ts @@ -0,0 +1,65 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'update-response-comment'; +export const description = + 'Updates a comment on a response.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + responseId: z.string().describe("The response's unique ID."), + commentId: z.number().int().describe("The comment's ID."), + body: z.string().describe('The contents of the comment.'), + tags: z + .object({ + userName: z + .object({ + type: z.literal('user').describe('The `user` value.'), + id: z.number().int().describe("The user's ID."), + }) + .describe( + "An object that contains information about the tagged user. The object's name is the user's Postman username. For example, `@user-postman`." + ) + .optional(), + }) + .describe('Information about users tagged in the `body` comment.') + .optional(), +}); +export const annotations = { + title: + 'Updates a comment on a response.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/collections/${params.collectionId}/responses/${params.responseId}/comments/${params.commentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.body !== undefined) bodyPayload.body = params.body; + if (params.tags !== undefined) bodyPayload.tags = params.tags; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/update_spec_properties.ts b/src/tools/update_spec_properties.ts new file mode 100644 index 0000000..e8bbaa8 --- /dev/null +++ b/src/tools/update_spec_properties.ts @@ -0,0 +1,46 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'update-spec-properties'; +export const description = "Updates an API specification's properties, such as its name."; +export const parameters = z.object({ + specId: z.string().describe("The spec's ID."), + name: z.string().describe("The spec's name."), +}); +export const annotations = { + title: "Updates an API specification's properties, such as its name.", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/specs/${params.specId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.name !== undefined) bodyPayload.name = params.name; + const result = await fetchPostmanAPI(url, { + method: 'PATCH', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/update_workspace.ts b/src/tools/update_workspace.ts new file mode 100644 index 0000000..26313fb --- /dev/null +++ b/src/tools/update_workspace.ts @@ -0,0 +1,59 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'update-workspace'; +export const description = + 'Updates a workspace.\n\n**Note:**\n\n- There are rate limits when publishing public workspaces.\n- Public team workspace names must be unique.\n\n### Important\n\nWe deprecated linking collections or environments between workspaces. We do not recommend that you do this.\n\nIf you have a linked collection or environment, note the following:\n- The endpoint does not create a clone of a collection or environment.\n- Any changes you make to a linked collection or environment changes them in all workspaces.\n- If you delete a collection or environment linked between workspaces, the system deletes it in all the workspaces.\n'; +export const parameters = z.object({ + workspaceId: z.string().describe("The workspace's ID."), + workspace: z + .object({ + name: z.string().describe("The workspace's new name.").optional(), + type: z + .enum(['private', 'personal', 'team', 'public']) + .describe( + 'The new workspace visibility [type](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/managing-workspaces/#changing-workspace-visibility). This property does not support the following workspace visibility changes:\n- `private` to `public`, `public` to `private`, and `private` to `personal` for Free and Basic [plans](https://www.postman.com/pricing/).\n- `public` to `personal` for team users.\n' + ) + .optional(), + description: z.string().describe('The new workspace description.').optional(), + }) + .optional(), +}); +export const annotations = { + title: + 'Updates a workspace.\n\n**Note:**\n\n- There are rate limits when publishing public workspaces.\n- Public team workspace names must be unique.\n\n### Important\n\nWe deprecated linking collections or environments between workspaces. We do not recommend that you do this.\n\nIf you have a linked collection or environment, note the following:\n- The endpoint does not create a clone of a collection or environment.\n- Any changes you make to a linked collection or environment changes them in all workspaces.\n- If you delete a collection or environment linked between workspaces, the system deletes it in all the workspaces.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/workspaces/${params.workspaceId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.workspace !== undefined) bodyPayload.workspace = params.workspace; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/update_workspace_global_variables.ts b/src/tools/update_workspace_global_variables.ts new file mode 100644 index 0000000..e104333 --- /dev/null +++ b/src/tools/update_workspace_global_variables.ts @@ -0,0 +1,65 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'update-workspace-global-variables'; +export const description = + "Updates and replaces a workspace's global [variables](https://learning.postman.com/docs/sending-requests/variables/#variable-scopes). This endpoint replaces all existing global variables with the variables you pass in the request body."; +export const parameters = z.object({ + workspaceId: z.string().describe("The workspace's ID."), + values: z + .array( + z + .object({ + key: z.string().describe("The variable's name.").optional(), + type: z + .enum(['default', 'secret']) + .describe( + 'The [type](https://learning.postman.com/docs/sending-requests/variables/#variable-types) of variable.' + ) + .optional(), + value: z.string().describe("The variable's value.").optional(), + enabled: z.boolean().describe('If true, the variable is enabled.').optional(), + }) + .describe('Information about the global variable.') + ) + .describe("A list of the workspace's global variables.") + .optional(), +}); +export const annotations = { + title: + "Updates and replaces a workspace's global [variables](https://learning.postman.com/docs/sending-requests/variables/#variable-scopes). This endpoint replaces all existing global variables with the variables you pass in the request body.", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/workspaces/${params.workspaceId}/global-variables`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.values !== undefined) bodyPayload.values = params.values; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/update_workspace_tags.ts b/src/tools/update_workspace_tags.ts new file mode 100644 index 0000000..1a07603 --- /dev/null +++ b/src/tools/update_workspace_tags.ts @@ -0,0 +1,63 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; + +export const method = 'update-workspace-tags'; +export const description = + "Updates a workspace's associated tags. This endpoint replaces all existing tags with those you pass in the request body."; +export const parameters = z.object({ + workspaceId: z.string().describe("The workspace's ID."), + tags: z + .array( + z + .object({ + slug: z + .string() + .regex(new RegExp('^[a-z][a-z0-9-]*[a-z0-9]+$')) + .min(2) + .max(64) + .describe("The tag's ID within a team or individual (non-team) user scope."), + }) + .describe('Information about the tag.') + ) + .min(0) + .max(5) + .describe('A list of the associated tags as slugs.'), +}); +export const annotations = { + title: + "Updates a workspace's associated tags. This endpoint replaces all existing tags with those you pass in the request body.", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/workspaces/${params.workspaceId}/tags`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.tags !== undefined) bodyPayload.tags = params.tags; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } catch (e: any) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..08f91a6 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "display": "Default", + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "outDir": "./dist", + "moduleResolution": "node", + "baseUrl": ".", + "strict": true, + "esModuleInterop": true, + "useUnknownInCatchVariables": false, + "noImplicitAny": false, + "removeComments": true, + "skipLibCheck": true, + "resolveJsonModule": true + }, + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "node_modules", + "zod-schemas" + ] +} \ No newline at end of file From 19af46bc06cc1d164b2754b4580b74327dc2d133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diego=20Garc=C3=ADa?= Date: Wed, 11 Jun 2025 16:54:17 +0200 Subject: [PATCH 2/4] refactor: apply @akira28 suggestions --- eslint.config.mjs | 1 - package-lock.json | 10 +- package.json | 6 +- src/clients/postman.ts | 2 +- src/index.ts | 274 ++++++++++------------------------------- 5 files changed, 75 insertions(+), 218 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 121a357..35975c5 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,4 +1,3 @@ -// eslint.config.js import eslint from '@eslint/js'; import tseslint from 'typescript-eslint'; import unusedImports from "eslint-plugin-unused-imports"; diff --git a/package-lock.json b/package-lock.json index 84fe474..fcdf8d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { - "name": "postman-api-mcp-server", - "version": "0.0.1", + "name": "postman-api-mcp", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "postman-api-mcp-server", - "version": "0.0.1", + "name": "postman-api-mcp", + "version": "1.0.0", "license": "Apache-2.0", "dependencies": { "@apidevtools/swagger-parser": "^11.0.0", @@ -33,7 +33,7 @@ "typescript-eslint": "^8.32.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=20.0.0" } }, "node_modules/@ampproject/remapping": { diff --git a/package.json b/package.json index 48c8db8..a50fcf9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "postman-api-mcp-server", - "version": "0.0.1", + "name": "postman-api-mcp", + "version": "1.0.0", "description": "A simple MCP server to operate on the Postman API", "main": "index.js", "type": "module", @@ -38,7 +38,7 @@ "typescript-eslint": "^8.32.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=20.0.0" }, "author": "Postman, Inc.", "license": "Apache-2.0" diff --git a/src/clients/postman.ts b/src/clients/postman.ts index 6a2e53f..308efb4 100644 --- a/src/clients/postman.ts +++ b/src/clients/postman.ts @@ -1,5 +1,5 @@ import packageJson from '../../package.json' with { type: 'json' }; -const BASE_URL = 'https://api.getpostman.com'; +const BASE_URL = 'https://api.postman.com'; export enum ContentType { Json = 'application/json', diff --git a/src/index.ts b/src/index.ts index 2233dc5..d4103b5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -#!/usr/bin/env node +#!/usr/bin/env tsx import dotenv from 'dotenv'; import { Server } from '@modelcontextprotocol/sdk/server/index.js'; @@ -12,114 +12,74 @@ import { } from '@modelcontextprotocol/sdk/types.js'; import zodToJsonSchema from 'zod-to-json-schema'; +import packageJson from '../package.json' with { type: 'json' }; +import { readdir } from 'node:fs/promises'; +import { join, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import type { z } from 'zod'; import { createApp } from './servers/express.js'; -import * as update_api_collection_comment from './tools/update_api_collection_comment.js'; -import * as delete_api_collection_comment from './tools/delete_api_collection_comment.js'; -import * as get_status_of_an_async_task from './tools/get_status_of_an_async_task.js'; -import * as get_collections from './tools/get_collections.js'; -import * as create_collection from './tools/create_collection.js'; -import * as get_collections_forked_by_user from './tools/get_collections_forked_by_user.js'; -import * as create_collection_fork from './tools/create_collection_fork.js'; -import * as get_collection from './tools/get_collection.js'; -import * as put_collection from './tools/put_collection.js'; -import * as patch_collection from './tools/patch_collection.js'; -import * as delete_collection from './tools/delete_collection.js'; -import * as get_collection_comments from './tools/get_collection_comments.js'; -import * as create_collection_comment from './tools/create_collection_comment.js'; -import * as update_collection_comment from './tools/update_collection_comment.js'; -import * as delete_collection_comment from './tools/delete_collection_comment.js'; -import * as create_collection_folder from './tools/create_collection_folder.js'; -import * as get_folder_comments from './tools/get_folder_comments.js'; -import * as create_folder_comment from './tools/create_folder_comment.js'; -import * as update_folder_comment from './tools/update_folder_comment.js'; -import * as delete_folder_comment from './tools/delete_folder_comment.js'; -import * as get_collection_forks from './tools/get_collection_forks.js'; -import * as get_generated_collection_specs from './tools/get_generated_collection_specs.js'; -import * as generate_spec_from_collection from './tools/generate_spec_from_collection.js'; -import * as publish_documentation from './tools/publish_documentation.js'; -import * as unpublish_documentation from './tools/unpublish_documentation.js'; -import * as pull_collection_changes from './tools/pull_collection_changes.js'; -import * as create_collection_request from './tools/create_collection_request.js'; -import * as get_request_comments from './tools/get_request_comments.js'; -import * as create_request_comment from './tools/create_request_comment.js'; -import * as update_request_comment from './tools/update_request_comment.js'; -import * as delete_request_comment from './tools/delete_request_comment.js'; -import * as create_collection_response from './tools/create_collection_response.js'; -import * as get_response_comments from './tools/get_response_comments.js'; -import * as create_response_comment from './tools/create_response_comment.js'; -import * as update_response_comment from './tools/update_response_comment.js'; -import * as delete_response_comment from './tools/delete_response_comment.js'; -import * as get_source_collection_status from './tools/get_source_collection_status.js'; -import * as sync_collection_with_spec from './tools/sync_collection_with_spec.js'; -import * as get_collection_folder from './tools/get_collection_folder.js'; -import * as update_collection_folder from './tools/update_collection_folder.js'; -import * as delete_collection_folder from './tools/delete_collection_folder.js'; -import * as get_collection_request from './tools/get_collection_request.js'; -import * as update_collection_request from './tools/update_collection_request.js'; -import * as delete_collection_request from './tools/delete_collection_request.js'; -import * as get_collection_response from './tools/get_collection_response.js'; -import * as update_collection_response from './tools/update_collection_response.js'; -import * as delete_collection_response from './tools/delete_collection_response.js'; -import * as get_collection_tags from './tools/get_collection_tags.js'; -import * as update_collection_tags from './tools/update_collection_tags.js'; -import * as transfer_collection_folders from './tools/transfer_collection_folders.js'; -import * as transfer_collection_requests from './tools/transfer_collection_requests.js'; -import * as transfer_collection_responses from './tools/transfer_collection_responses.js'; -import * as get_collection_updates_tasks from './tools/get_collection_updates_tasks.js'; -import * as resolve_comment_thread from './tools/resolve_comment_thread.js'; -import * as get_async_spec_task_status from './tools/get_async_spec_task_status.js'; -import * as get_environments from './tools/get_environments.js'; -import * as create_environment from './tools/create_environment.js'; -import * as get_environment from './tools/get_environment.js'; -import * as patch_environment from './tools/patch_environment.js'; -import * as put_environment from './tools/put_environment.js'; -import * as delete_environment from './tools/delete_environment.js'; -import * as get_authenticated_user from './tools/get_authenticated_user.js'; -import * as get_mocks from './tools/get_mocks.js'; -import * as create_mock from './tools/create_mock.js'; -import * as get_mock from './tools/get_mock.js'; -import * as update_mock from './tools/update_mock.js'; -import * as delete_mock from './tools/delete_mock.js'; -import * as publish_mock from './tools/publish_mock.js'; -import * as unpublish_mock from './tools/unpublish_mock.js'; -import * as get_monitors from './tools/get_monitors.js'; -import * as create_monitor from './tools/create_monitor.js'; -import * as get_monitor from './tools/get_monitor.js'; -import * as update_monitor from './tools/update_monitor.js'; -import * as delete_monitor from './tools/delete_monitor.js'; -import * as run_monitor from './tools/run_monitor.js'; -import * as get_all_elements_and_folders from './tools/get_all_elements_and_folders.js'; -import * as post_pan_element_or_folder from './tools/post_pan_element_or_folder.js'; -import * as update_pan_element_or_folder from './tools/update_pan_element_or_folder.js'; -import * as delete_pan_element_or_folder from './tools/delete_pan_element_or_folder.js'; -import * as get_all_pan_add_element_requests from './tools/get_all_pan_add_element_requests.js'; -import * as get_tagged_entities from './tools/get_tagged_entities.js'; -import * as get_all_specs from './tools/get_all_specs.js'; -import * as create_spec from './tools/create_spec.js'; -import * as get_spec from './tools/get_spec.js'; -import * as delete_spec from './tools/delete_spec.js'; -import * as update_spec_properties from './tools/update_spec_properties.js'; -import * as get_spec_definition from './tools/get_spec_definition.js'; -import * as create_update_spec_file from './tools/create_update_spec_file.js'; -import * as get_spec_collections from './tools/get_spec_collections.js'; -import * as generate_collection from './tools/generate_collection.js'; -import * as sync_spec_with_collection from './tools/sync_spec_with_collection.js'; -import * as get_workspaces from './tools/get_workspaces.js'; -import * as create_workspace from './tools/create_workspace.js'; -import * as get_workspace from './tools/get_workspace.js'; -import * as update_workspace from './tools/update_workspace.js'; -import * as delete_workspace from './tools/delete_workspace.js'; -import * as get_workspace_global_variables from './tools/get_workspace_global_variables.js'; -import * as update_workspace_global_variables from './tools/update_workspace_global_variables.js'; -import * as get_workspace_tags from './tools/get_workspace_tags.js'; -import * as update_workspace_tags from './tools/update_workspace_tags.js'; +interface ToolModule { + method: string; + description: string; + parameters: z.ZodSchema; + annotations?: { + title?: string; + readOnlyHint?: boolean; + destructiveHint?: boolean; + idempotentHint?: boolean; + }; + handler: ( + params: any, + extra: { apiKey: string } + ) => Promise<{ + content: Array<{ type: string; text: string } & Record>; + }>; +} + +async function loadAllTools(): Promise { + const __filename = fileURLToPath(import.meta.url); + const __dirname = dirname(__filename); + const toolsDir = join(__dirname, 'tools'); + + try { + const files = await readdir(toolsDir); + const toolFiles = files.filter((file) => file.endsWith('.js')); + + const tools: ToolModule[] = []; + + for (const file of toolFiles) { + try { + const toolPath = join(toolsDir, file); + const toolModule = await import(toolPath); + + if ( + toolModule.method && + toolModule.description && + toolModule.parameters && + toolModule.handler + ) { + tools.push(toolModule as ToolModule); + } else { + console.warn(`Tool module ${file} is missing required exports. Skipping.`); + } + } catch (error) { + console.error(`Failed to load tool ${file}:`, error); + } + } + + return tools; + } catch (error) { + console.error('Failed to read tools directory:', error); + return []; + } +} dotenv.config(); -const SERVER_NAME = 'generated-postman-api-mcp-server'; -const APP_VERSION = '0.1.0'; +const SERVER_NAME = packageJson.name; +const APP_VERSION = packageJson.version; export const USER_AGENT = `${SERVER_NAME}/${APP_VERSION}`; const logger = { @@ -146,114 +106,14 @@ const logger = { let currentApiKey: string | undefined = undefined; -const allGeneratedTools = [ - update_api_collection_comment, - delete_api_collection_comment, - get_status_of_an_async_task, - get_collections, - create_collection, - get_collections_forked_by_user, - create_collection_fork, - get_collection, - put_collection, - patch_collection, - delete_collection, - get_collection_comments, - create_collection_comment, - update_collection_comment, - delete_collection_comment, - create_collection_folder, - get_folder_comments, - create_folder_comment, - update_folder_comment, - delete_folder_comment, - get_collection_forks, - get_generated_collection_specs, - generate_spec_from_collection, - publish_documentation, - unpublish_documentation, - pull_collection_changes, - create_collection_request, - get_request_comments, - create_request_comment, - update_request_comment, - delete_request_comment, - create_collection_response, - get_response_comments, - create_response_comment, - update_response_comment, - delete_response_comment, - get_source_collection_status, - sync_collection_with_spec, - get_collection_folder, - update_collection_folder, - delete_collection_folder, - get_collection_request, - update_collection_request, - delete_collection_request, - get_collection_response, - update_collection_response, - delete_collection_response, - get_collection_tags, - update_collection_tags, - transfer_collection_folders, - transfer_collection_requests, - transfer_collection_responses, - get_collection_updates_tasks, - resolve_comment_thread, - get_async_spec_task_status, - get_environments, - create_environment, - get_environment, - patch_environment, - put_environment, - delete_environment, - get_authenticated_user, - get_mocks, - create_mock, - get_mock, - update_mock, - delete_mock, - publish_mock, - unpublish_mock, - get_monitors, - create_monitor, - get_monitor, - update_monitor, - delete_monitor, - run_monitor, - get_all_elements_and_folders, - post_pan_element_or_folder, - update_pan_element_or_folder, - delete_pan_element_or_folder, - get_all_pan_add_element_requests, - get_tagged_entities, - get_all_specs, - create_spec, - get_spec, - delete_spec, - update_spec_properties, - get_spec_definition, - create_update_spec_file, - get_spec_collections, - generate_collection, - sync_spec_with_collection, - get_workspaces, - create_workspace, - get_workspace, - update_workspace, - delete_workspace, - get_workspace_global_variables, - update_workspace_global_variables, - get_workspace_tags, - update_workspace_tags, -]; - async function run() { const args = process.argv.slice(2); const isSSE = args.includes('--sse') || process.env.MCP_TRANSPORT === 'sse'; logger.info(`Transport mode determined: ${isSSE ? 'HTTP/SSE' : 'Stdio'}`); + const allGeneratedTools = await loadAllTools(); + logger.info(`Dynamically loaded ${allGeneratedTools.length} tools...`); + const server = new Server( { name: SERVER_NAME, version: APP_VERSION }, { capabilities: { tools: {} } } @@ -267,8 +127,6 @@ async function run() { process.exit(0); }); - logger.info(`Registering ${allGeneratedTools.length} tools...`); - server.setRequestHandler(CallToolRequestSchema, async (request) => { const toolName = request.params.name; const tool = allGeneratedTools.find((t) => t.method === toolName); From b1287584bc12424fe69554495085a46d47c6c4d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diego=20Garc=C3=ADa?= Date: Thu, 12 Jun 2025 09:23:00 +0200 Subject: [PATCH 3/4] docs: apply @akinard-postman suggestions Co-authored-by: Ashley Kinard <113702138+akinard-postman@users.noreply.github.com> --- DOCKER.md | 16 ++++++++-------- README.md | 1 - 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/DOCKER.md b/DOCKER.md index 2f6d388..99214e7 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -1,30 +1,30 @@ # Docker Build Instructions -This project uses a multi-stage Docker build to create either an HTTP API or STDIO version of the application. +This project uses a multi-stage Docker build to create either an HTTP API or an STDIO version of the application. ## Building with Docker -### HTTP API Version (default) +### HTTP API (default) ```bash docker build -t postman-api-mcp-server . ``` -### STDIO Version +### STDIO ```bash docker build --target production-stdio -t postman-api-mcp-stdio . ``` -### Running the Docker Container +## Running the Docker container -#### STDIO Version +### STDIO ```bash docker run -i -e POSTMAN_API_KEY="" postman-api-mcp-stdio ``` -#### HTTP API Version +### HTTP API ```bash docker run -p 1337:1337 postman-api-mcp-server ``` -### Accessing the HTTP API -You can access the HTTP API at `http://localhost:1337/mcp`. Use a tool like Postman or VS Code to connect to this endpoint (see the [README](./README.md) for VS Code integration). +## Accessing the HTTP API +You can access the HTTP API at `http://localhost:1337/mcp`. Use a tool like Postman or VS Code to connect to this endpoint. For more information about VS Code integration, see the [README](./README.md) file. diff --git a/README.md b/README.md index cee675c..a3b5b7b 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,6 @@ You can now use your Postman API tools with your VS Code extension through the M See [DOCKER.md](./DOCKER.md) for up-to-date build, Docker, and usage instructions. -## Contributing ## 💬 Questions and support From 0ab9076a42b8fc6d45a2ab2aed9c7e6969fd2e60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diego=20Garc=C3=ADa?= Date: Thu, 12 Jun 2025 09:37:31 +0200 Subject: [PATCH 4/4] refactor: README.md --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a3b5b7b..8ba10a9 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ # Postman API MCP Server -This project was created with the [Postman Agent Generator](https://postman.com/explore/agent-generator), configured to [Model Context Provider (MCP)](https://modelcontextprotocol.io/introduction) Server output mode. It provides: +**This project offers two MCP-compatible server options:** -- An MCP-compatible server (`dist/src/index.js`) using the [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http). -- Automatically generated JavaScript tools for each selected Postman API request. +1. **Streamable HTTP server** — A fully MCP-compliant server entrypoint (`dist/src/index.js`) using the [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http). +2. **STDIO server** — A lightweight MCP server that communicates over standard input/output, ideal for integration with editors and tools like [VS Code](https://code.visualstudio.com/). + +See more about the Model Context Protocol available transports in the [MCP specification](https://modelcontextprotocol.io/docs/concepts/transports). ## 🧰 VS Code Integration