diff --git a/dist/src/tools/create_collection.js b/dist/src/tools/create_collection.js index 31e7f0d..3f61ae1 100644 --- a/dist/src/tools/create_collection.js +++ b/dist/src/tools/create_collection.js @@ -1,9 +1,9 @@ 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 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 the oldest personal Internal workspace you own.\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(), + workspace: z.string().describe("The workspace's ID."), collection: z .object({ info: z @@ -32,7 +32,10 @@ export const parameters = z.object({ .string() .describe("The variable's description. Doesn't apply to collection-level variables.") .optional(), - disabled: z.boolean().default(false), + disabled: z + .boolean() + .describe('If true, the variable is not enabled.') + .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.") @@ -515,7 +518,10 @@ export const parameters = z.object({ .string() .describe("The variable's description. Doesn't apply to collection-level variables.") .optional(), - disabled: z.boolean().default(false), + disabled: z + .boolean() + .describe('If true, the variable is not enabled.') + .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.") @@ -771,7 +777,7 @@ export const parameters = z.object({ .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', + 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 the oldest personal Internal workspace you own.\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, diff --git a/dist/src/tools/create_environment.js b/dist/src/tools/create_environment.js index 11f8f56..ec57266 100644 --- a/dist/src/tools/create_environment.js +++ b/dist/src/tools/create_environment.js @@ -1,9 +1,9 @@ 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 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 environment in the oldest personal Internal workspace you own.\n'; export const parameters = z.object({ - workspace: z.string().describe("The workspace's ID.").optional(), + workspace: z.string().describe("The workspace's ID."), environment: z .object({ name: z.string().describe("The environment's name."), @@ -17,10 +17,11 @@ export const parameters = z.object({ .describe("Information about the environment's variables.") .optional(), }) + .describe('Information about the environment.') .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', + 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 environment in the oldest personal Internal workspace you own.\n', readOnlyHint: false, destructiveHint: false, idempotentHint: false, diff --git a/dist/src/tools/create_mock.js b/dist/src/tools/create_mock.js index 5f5b06e..b6add34 100644 --- a/dist/src/tools/create_mock.js +++ b/dist/src/tools/create_mock.js @@ -1,9 +1,9 @@ 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 description = 'Creates a mock server in a collection.\n\n**Note:**\n\n- You cannot create mocks for collections added to an API definition.\n- If you do not include the \\`workspaceId\\` query parameter, the system creates the mock server in the oldest personal Internal workspace you own.\n'; export const parameters = z.object({ - workspaceId: z.string().describe("The workspace's ID.").optional(), + workspace: z.string().describe("The workspace's ID."), mock: z .object({ collection: z.string().describe("The unique ID of the mock's associated collection."), @@ -20,7 +20,7 @@ export const parameters = z.object({ .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', + title: 'Creates a mock server in a collection.\n\n**Note:**\n\n- You cannot create mocks for collections added to an API definition.\n- If you do not include the \\`workspaceId\\` query parameter, the system creates the mock server in the oldest personal Internal workspace you own.\n', readOnlyHint: false, destructiveHint: false, idempotentHint: false, @@ -29,8 +29,8 @@ export async function handler(params, extra) { try { const endpoint = `/mocks`; const query = new URLSearchParams(); - if (params.workspaceId !== undefined) - query.set('workspaceId', String(params.workspaceId)); + if (params.workspace !== undefined) + query.set('workspace', String(params.workspace)); const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; const bodyPayload = {}; if (params.mock !== undefined) diff --git a/dist/src/tools/create_monitor.js b/dist/src/tools/create_monitor.js index 805225e..f61cedd 100644 --- a/dist/src/tools/create_monitor.js +++ b/dist/src/tools/create_monitor.js @@ -1,9 +1,9 @@ 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 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\\` query parameter, the system creates the monitor in the oldest personal Internal workspace you own.\n'; export const parameters = z.object({ - workspace: z.string().describe("The workspace's ID.").optional(), + workspace: z.string().describe("The workspace's ID."), monitor: z .object({ name: z.string().describe("The monitor's name."), @@ -106,10 +106,11 @@ export const parameters = z.object({ .describe("Information about the monitor's notification settings.") .optional(), }) + .describe('Information about the monitor.') .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', + 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\\` query parameter, the system creates the monitor in the oldest personal Internal workspace you own.\n', readOnlyHint: false, destructiveHint: false, idempotentHint: false, diff --git a/dist/src/tools/create_spec.js b/dist/src/tools/create_spec.js index dd7811f..cf66913 100644 --- a/dist/src/tools/create_spec.js +++ b/dist/src/tools/create_spec.js @@ -1,22 +1,40 @@ 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 description = "Creates an API specification in Postman's [Spec Hub](https://learning.postman.com/docs/design-apis/specifications/overview/). Specifications can be single or multi-file.\n\n**Note:**\n- Postman supports OpenAPI 3.0 and AsyncAPI 2.0 specifications.\n- If the file path contains a \\`/\\` (forward slash) character, then a folder is created. For example, if the path is the \\`components/schemas.json\\` value, then a \\`components\\` folder is created with the \\`schemas.json\\` file inside.\n- Multi-file specifications can only have one root file.\n- Files cannot exceed a maximum of 10 MB in size.\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."), + .array(z.any().superRefine((x, ctx) => { + const schemas = [ + z.object({ + path: z.string().describe("The file's path. Accepts JSON or YAML files."), + content: z.string().describe("The file's stringified contents."), + type: z + .enum(['DEFAULT', 'ROOT']) + .describe('The type of file. This property is required when creating multi-file specifications:\n- `ROOT` — The file containing the full OpenAPI structure. This serves as the entry point for the API spec and references other (`DEFAULT`) spec files. Multi-file specs can only have one root file.\n- `DEFAULT` — A file referenced by the `ROOT` file.\n'), + }), + z.object({ + path: z.string().describe("The file's path. Accepts JSON or YAML files."), + content: z.string().describe("The file's stringified contents."), + }), + ]; + 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 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", + title: "Creates an API specification in Postman's [Spec Hub](https://learning.postman.com/docs/design-apis/specifications/overview/). Specifications can be single or multi-file.\n\n**Note:**\n- Postman supports OpenAPI 3.0 and AsyncAPI 2.0 specifications.\n- If the file path contains a \\`/\\` (forward slash) character, then a folder is created. For example, if the path is the \\`components/schemas.json\\` value, then a \\`components\\` folder is created with the \\`schemas.json\\` file inside.\n- Multi-file specifications can only have one root file.\n- Files cannot exceed a maximum of 10 MB in size.\n", readOnlyHint: false, destructiveHint: false, idempotentHint: false, diff --git a/dist/src/tools/create_spec_file.js b/dist/src/tools/create_spec_file.js new file mode 100644 index 0000000..6eedee9 --- /dev/null +++ b/dist/src/tools/create_spec_file.js @@ -0,0 +1,47 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'create-spec-file'; +export const description = 'Creates an API specification file.\n\n**Note:**\n\n- If the file path contains a \\`/\\` (forward slash) character, then a folder is created. For example, if the path is the \\`components/schemas.json\\` value, then a \\`components\\` folder is created with the \\`schemas.json\\` file inside.\n- Creating a spec file assigns it the \\`DEFAULT\\` file type.\n- Multi-file specifications can only have one root file.\n- Files cannot exceed a maximum of 10 MB in size.\n'; +export const parameters = z.object({ + specId: z.string().describe("The spec's ID."), + path: z.string().describe("The file's path. Accepts JSON or YAML files."), + content: z.string().describe("The file's stringified contents."), +}); +export const annotations = { + title: 'Creates an API specification file.\n\n**Note:**\n\n- If the file path contains a \\`/\\` (forward slash) character, then a folder is created. For example, if the path is the \\`components/schemas.json\\` value, then a \\`components\\` folder is created with the \\`schemas.json\\` file inside.\n- Creating a spec file assigns it the \\`DEFAULT\\` file type.\n- Multi-file specifications can only have one root file.\n- Files cannot exceed a maximum of 10 MB in size.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/specs/${params.specId}/files`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.path !== undefined) + bodyPayload.path = params.path; + if (params.content !== undefined) + bodyPayload.content = params.content; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/delete_spec_file.js b/dist/src/tools/delete_spec_file.js new file mode 100644 index 0000000..620a3f8 --- /dev/null +++ b/dist/src/tools/delete_spec_file.js @@ -0,0 +1,39 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'delete-spec-file'; +export const description = 'Deletes a file in 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."), + filePath: z.string().describe('The path to the file.'), +}); +export const annotations = { + title: 'Deletes a file in an API specification. On success, this returns an HTTP \\`204 No Content\\` response.', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/specs/${params.specId}/files/${params.filePath}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/create_update_spec_file.js b/dist/src/tools/get_spec_file.js similarity index 62% rename from dist/src/tools/create_update_spec_file.js rename to dist/src/tools/get_spec_file.js index eae8593..ce784f5 100644 --- a/dist/src/tools/create_update_spec_file.js +++ b/dist/src/tools/get_spec_file.js @@ -1,15 +1,14 @@ 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"; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-spec-file'; +export const description = "Gets the contents of an API specification's file."; 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, + title: "Gets the contents of an API specification's file.", + readOnlyHint: true, destructiveHint: false, idempotentHint: true, }; @@ -18,13 +17,8 @@ export async function handler(params, extra) { const endpoint = `/specs/${params.specId}/files/${params.filePath}`; const query = new URLSearchParams(); const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; - const bodyPayload = {}; - if (params.content !== undefined) - bodyPayload.content = params.content; const result = await fetchPostmanAPI(url, { - method: 'PATCH', - body: JSON.stringify(bodyPayload), - contentType: ContentType.Json, + method: 'GET', apiKey: extra.apiKey, headers: extra.headers, }); diff --git a/dist/src/tools/get_spec_files.js b/dist/src/tools/get_spec_files.js new file mode 100644 index 0000000..f5bd0ac --- /dev/null +++ b/dist/src/tools/get_spec_files.js @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-spec-files'; +export const description = 'Gets all the files in an API specification.'; +export const parameters = z.object({ specId: z.string().describe("The spec's ID.") }); +export const annotations = { + title: 'Gets all the files in an API specification.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/specs/${params.specId}/files`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/put_environment.js b/dist/src/tools/put_environment.js index c81fd57..7413616 100644 --- a/dist/src/tools/put_environment.js +++ b/dist/src/tools/put_environment.js @@ -17,6 +17,7 @@ export const parameters = z.object({ .describe("Information about the environment's variables.") .optional(), }) + .describe('Information about the environment.') .optional(), }); export const annotations = { diff --git a/dist/src/tools/update_monitor.js b/dist/src/tools/update_monitor.js index 03e290f..6453453 100644 --- a/dist/src/tools/update_monitor.js +++ b/dist/src/tools/update_monitor.js @@ -102,6 +102,7 @@ export const parameters = z.object({ .describe("Information about the monitor's notification settings.") .optional(), }) + .describe('Information about the monitor.') .optional(), }); export const annotations = { diff --git a/dist/src/tools/update_spec_file.js b/dist/src/tools/update_spec_file.js new file mode 100644 index 0000000..360f8fd --- /dev/null +++ b/dist/src/tools/update_spec_file.js @@ -0,0 +1,54 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'update-spec-file'; +export const description = "Updates an API specification's file.\n\n**Note:**\n\n- This endpoint does not accept an empty request body. You must pass one of the accepted values.\n- This endpoint does not accept multiple request body properties in a single call. For example, you cannot pass both the \\`content\\` and \\`type\\` property at the same time.\n- Multi-file specifications can only have one root file.\n- When updating a file type to \\`ROOT\\`, the previous root file is updated to the \\`DEFAULT\\` file type.\n- Files cannot exceed a maximum of 10 MB in size.\n"; +export const parameters = z.object({ + specId: z.string().describe("The spec's ID."), + filePath: z.string().describe('The path to the file.'), + name: z.string().describe("The file's name.").optional(), + type: z + .enum(['DEFAULT', 'ROOT']) + .describe('The type of file:\n- `ROOT` — The file containing the full OpenAPI structure. This serves as the entry point for the API spec and references other (`DEFAULT`) spec files. Multi-file specs can only have one root file.\n- `DEFAULT` — A file referenced by the `ROOT` file.\n') + .optional(), + content: z.string().describe("The specification's stringified contents.").optional(), +}); +export const annotations = { + title: "Updates an API specification's file.\n\n**Note:**\n\n- This endpoint does not accept an empty request body. You must pass one of the accepted values.\n- This endpoint does not accept multiple request body properties in a single call. For example, you cannot pass both the \\`content\\` and \\`type\\` property at the same time.\n- Multi-file specifications can only have one root file.\n- When updating a file type to \\`ROOT\\`, the previous root file is updated to the \\`DEFAULT\\` file type.\n- Files cannot exceed a maximum of 10 MB in size.\n", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/specs/${params.specId}/files/${params.filePath}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.name !== undefined) + bodyPayload.name = params.name; + if (params.type !== undefined) + bodyPayload.type = params.type; + 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, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/src/tools/create_collection.ts b/src/tools/create_collection.ts index 754549b..12fe83c 100644 --- a/src/tools/create_collection.ts +++ b/src/tools/create_collection.ts @@ -4,9 +4,9 @@ import { IsomorphicHeaders } from '@modelcontextprotocol/sdk/types.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'; + '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 the oldest personal Internal workspace you own.\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(), + workspace: z.string().describe("The workspace's ID."), collection: z .object({ info: z @@ -41,7 +41,10 @@ export const parameters = z.object({ "The variable's description. Doesn't apply to collection-level variables." ) .optional(), - disabled: z.boolean().default(false), + disabled: z + .boolean() + .describe('If true, the variable is not enabled.') + .default(false), }) .describe('Information about the variable.') ) @@ -664,7 +667,10 @@ export const parameters = z.object({ "The variable's description. Doesn't apply to collection-level variables." ) .optional(), - disabled: z.boolean().default(false), + disabled: z + .boolean() + .describe('If true, the variable is not enabled.') + .default(false), }) .describe('Information about the variable.') ) @@ -1000,7 +1006,7 @@ export const parameters = z.object({ }); 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', + '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 the oldest personal Internal workspace you own.\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, diff --git a/src/tools/create_environment.ts b/src/tools/create_environment.ts index 4c27f1d..8ca737e 100644 --- a/src/tools/create_environment.ts +++ b/src/tools/create_environment.ts @@ -4,9 +4,9 @@ import { IsomorphicHeaders } from '@modelcontextprotocol/sdk/types.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'; + '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 environment in the oldest personal Internal workspace you own.\n'; export const parameters = z.object({ - workspace: z.string().describe("The workspace's ID.").optional(), + workspace: z.string().describe("The workspace's ID."), environment: z .object({ name: z.string().describe("The environment's name."), @@ -22,11 +22,12 @@ export const parameters = z.object({ .describe("Information about the environment's variables.") .optional(), }) + .describe('Information about the environment.') .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', + '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 environment in the oldest personal Internal workspace you own.\n', readOnlyHint: false, destructiveHint: false, idempotentHint: false, diff --git a/src/tools/create_mock.ts b/src/tools/create_mock.ts index d1bcc91..8a81066 100644 --- a/src/tools/create_mock.ts +++ b/src/tools/create_mock.ts @@ -4,9 +4,9 @@ import { IsomorphicHeaders } from '@modelcontextprotocol/sdk/types.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'; + 'Creates a mock server in a collection.\n\n**Note:**\n\n- You cannot create mocks for collections added to an API definition.\n- If you do not include the \\`workspaceId\\` query parameter, the system creates the mock server in the oldest personal Internal workspace you own.\n'; export const parameters = z.object({ - workspaceId: z.string().describe("The workspace's ID.").optional(), + workspace: z.string().describe("The workspace's ID."), mock: z .object({ collection: z.string().describe("The unique ID of the mock's associated collection."), @@ -26,7 +26,7 @@ export const parameters = z.object({ }); 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', + 'Creates a mock server in a collection.\n\n**Note:**\n\n- You cannot create mocks for collections added to an API definition.\n- If you do not include the \\`workspaceId\\` query parameter, the system creates the mock server in the oldest personal Internal workspace you own.\n', readOnlyHint: false, destructiveHint: false, idempotentHint: false, @@ -39,7 +39,7 @@ export async function handler( try { const endpoint = `/mocks`; const query = new URLSearchParams(); - if (params.workspaceId !== undefined) query.set('workspaceId', String(params.workspaceId)); + if (params.workspace !== undefined) query.set('workspace', String(params.workspace)); const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; const bodyPayload: any = {}; if (params.mock !== undefined) bodyPayload.mock = params.mock; diff --git a/src/tools/create_monitor.ts b/src/tools/create_monitor.ts index c70d37c..d7feaae 100644 --- a/src/tools/create_monitor.ts +++ b/src/tools/create_monitor.ts @@ -4,9 +4,9 @@ import { IsomorphicHeaders } from '@modelcontextprotocol/sdk/types.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'; + '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\\` query parameter, the system creates the monitor in the oldest personal Internal workspace you own.\n'; export const parameters = z.object({ - workspace: z.string().describe("The workspace's ID.").optional(), + workspace: z.string().describe("The workspace's ID."), monitor: z .object({ name: z.string().describe("The monitor's name."), @@ -123,11 +123,12 @@ export const parameters = z.object({ .describe("Information about the monitor's notification settings.") .optional(), }) + .describe('Information about the monitor.') .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', + '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\\` query parameter, the system creates the monitor in the oldest personal Internal workspace you own.\n', readOnlyHint: false, destructiveHint: false, idempotentHint: false, diff --git a/src/tools/create_spec.ts b/src/tools/create_spec.ts index 6d29c57..94f5e13 100644 --- a/src/tools/create_spec.ts +++ b/src/tools/create_spec.ts @@ -4,25 +4,49 @@ import { IsomorphicHeaders } from '@modelcontextprotocol/sdk/types.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"; + "Creates an API specification in Postman's [Spec Hub](https://learning.postman.com/docs/design-apis/specifications/overview/). Specifications can be single or multi-file.\n\n**Note:**\n- Postman supports OpenAPI 3.0 and AsyncAPI 2.0 specifications.\n- If the file path contains a \\`/\\` (forward slash) character, then a folder is created. For example, if the path is the \\`components/schemas.json\\` value, then a \\`components\\` folder is created with the \\`schemas.json\\` file inside.\n- Multi-file specifications can only have one root file.\n- Files cannot exceed a maximum of 10 MB in size.\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."), + z.any().superRefine((x, ctx) => { + const schemas = [ + z.object({ + path: z.string().describe("The file's path. Accepts JSON or YAML files."), + content: z.string().describe("The file's stringified contents."), + type: z + .enum(['DEFAULT', 'ROOT']) + .describe( + 'The type of file. This property is required when creating multi-file specifications:\n- `ROOT` — The file containing the full OpenAPI structure. This serves as the entry point for the API spec and references other (`DEFAULT`) spec files. Multi-file specs can only have one root file.\n- `DEFAULT` — A file referenced by the `ROOT` file.\n' + ), + }), + z.object({ + path: z.string().describe("The file's path. Accepts JSON or YAML files."), + content: z.string().describe("The file's stringified contents."), + }), + ]; + 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 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", + "Creates an API specification in Postman's [Spec Hub](https://learning.postman.com/docs/design-apis/specifications/overview/). Specifications can be single or multi-file.\n\n**Note:**\n- Postman supports OpenAPI 3.0 and AsyncAPI 2.0 specifications.\n- If the file path contains a \\`/\\` (forward slash) character, then a folder is created. For example, if the path is the \\`components/schemas.json\\` value, then a \\`components\\` folder is created with the \\`schemas.json\\` file inside.\n- Multi-file specifications can only have one root file.\n- Files cannot exceed a maximum of 10 MB in size.\n", readOnlyHint: false, destructiveHint: false, idempotentHint: false, diff --git a/src/tools/create_spec_file.ts b/src/tools/create_spec_file.ts new file mode 100644 index 0000000..39ae28c --- /dev/null +++ b/src/tools/create_spec_file.ts @@ -0,0 +1,52 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +import { IsomorphicHeaders } from '@modelcontextprotocol/sdk/types.js'; + +export const method = 'create-spec-file'; +export const description = + 'Creates an API specification file.\n\n**Note:**\n\n- If the file path contains a \\`/\\` (forward slash) character, then a folder is created. For example, if the path is the \\`components/schemas.json\\` value, then a \\`components\\` folder is created with the \\`schemas.json\\` file inside.\n- Creating a spec file assigns it the \\`DEFAULT\\` file type.\n- Multi-file specifications can only have one root file.\n- Files cannot exceed a maximum of 10 MB in size.\n'; +export const parameters = z.object({ + specId: z.string().describe("The spec's ID."), + path: z.string().describe("The file's path. Accepts JSON or YAML files."), + content: z.string().describe("The file's stringified contents."), +}); +export const annotations = { + title: + 'Creates an API specification file.\n\n**Note:**\n\n- If the file path contains a \\`/\\` (forward slash) character, then a folder is created. For example, if the path is the \\`components/schemas.json\\` value, then a \\`components\\` folder is created with the \\`schemas.json\\` file inside.\n- Creating a spec file assigns it the \\`DEFAULT\\` file type.\n- Multi-file specifications can only have one root file.\n- Files cannot exceed a maximum of 10 MB in size.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string; headers?: IsomorphicHeaders } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/specs/${params.specId}/files`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload: any = {}; + if (params.path !== undefined) bodyPayload.path = params.path; + if (params.content !== undefined) bodyPayload.content = params.content; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + 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_file.ts b/src/tools/delete_spec_file.ts new file mode 100644 index 0000000..c8c379a --- /dev/null +++ b/src/tools/delete_spec_file.ts @@ -0,0 +1,46 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +import { IsomorphicHeaders } from '@modelcontextprotocol/sdk/types.js'; + +export const method = 'delete-spec-file'; +export const description = + 'Deletes a file in 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."), + filePath: z.string().describe('The path to the file.'), +}); +export const annotations = { + title: + 'Deletes a file in 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; headers?: IsomorphicHeaders } +): 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 result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + headers: extra.headers, + }); + 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/get_spec_file.ts similarity index 66% rename from src/tools/create_update_spec_file.ts rename to src/tools/get_spec_file.ts index 1fc634a..e467387 100644 --- a/src/tools/create_update_spec_file.ts +++ b/src/tools/get_spec_file.ts @@ -1,17 +1,16 @@ import { z } from 'zod'; -import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +import { fetchPostmanAPI } from '../clients/postman.js'; import { IsomorphicHeaders } from '@modelcontextprotocol/sdk/types.js'; -export const method = 'create-update-spec-file'; -export const description = "Creates or updates an API specification's file.\n"; +export const method = 'get-spec-file'; +export const description = "Gets the contents of an API specification's file."; 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, + title: "Gets the contents of an API specification's file.", + readOnlyHint: true, destructiveHint: false, idempotentHint: true, }; @@ -24,12 +23,8 @@ export async function handler( 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, + method: 'GET', apiKey: extra.apiKey, headers: extra.headers, }); diff --git a/src/tools/get_spec_files.ts b/src/tools/get_spec_files.ts new file mode 100644 index 0000000..209a700 --- /dev/null +++ b/src/tools/get_spec_files.ts @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +import { IsomorphicHeaders } from '@modelcontextprotocol/sdk/types.js'; + +export const method = 'get-spec-files'; +export const description = 'Gets all the files in an API specification.'; +export const parameters = z.object({ specId: z.string().describe("The spec's ID.") }); +export const annotations = { + title: 'Gets all the files in an API specification.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string; headers?: IsomorphicHeaders } +): Promise<{ content: Array<{ type: string; text: string } & Record> }> { + try { + const endpoint = `/specs/${params.specId}/files`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + 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 index 6ef439c..31f1f41 100644 --- a/src/tools/put_environment.ts +++ b/src/tools/put_environment.ts @@ -22,6 +22,7 @@ export const parameters = z.object({ .describe("Information about the environment's variables.") .optional(), }) + .describe('Information about the environment.') .optional(), }); export const annotations = { diff --git a/src/tools/update_monitor.ts b/src/tools/update_monitor.ts index 211723e..e1861e0 100644 --- a/src/tools/update_monitor.ts +++ b/src/tools/update_monitor.ts @@ -119,6 +119,7 @@ export const parameters = z.object({ .describe("Information about the monitor's notification settings.") .optional(), }) + .describe('Information about the monitor.') .optional(), }); export const annotations = { diff --git a/src/tools/update_spec_file.ts b/src/tools/update_spec_file.ts new file mode 100644 index 0000000..abacf55 --- /dev/null +++ b/src/tools/update_spec_file.ts @@ -0,0 +1,60 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +import { IsomorphicHeaders } from '@modelcontextprotocol/sdk/types.js'; + +export const method = 'update-spec-file'; +export const description = + "Updates an API specification's file.\n\n**Note:**\n\n- This endpoint does not accept an empty request body. You must pass one of the accepted values.\n- This endpoint does not accept multiple request body properties in a single call. For example, you cannot pass both the \\`content\\` and \\`type\\` property at the same time.\n- Multi-file specifications can only have one root file.\n- When updating a file type to \\`ROOT\\`, the previous root file is updated to the \\`DEFAULT\\` file type.\n- Files cannot exceed a maximum of 10 MB in size.\n"; +export const parameters = z.object({ + specId: z.string().describe("The spec's ID."), + filePath: z.string().describe('The path to the file.'), + name: z.string().describe("The file's name.").optional(), + type: z + .enum(['DEFAULT', 'ROOT']) + .describe( + 'The type of file:\n- `ROOT` — The file containing the full OpenAPI structure. This serves as the entry point for the API spec and references other (`DEFAULT`) spec files. Multi-file specs can only have one root file.\n- `DEFAULT` — A file referenced by the `ROOT` file.\n' + ) + .optional(), + content: z.string().describe("The specification's stringified contents.").optional(), +}); +export const annotations = { + title: + "Updates an API specification's file.\n\n**Note:**\n\n- This endpoint does not accept an empty request body. You must pass one of the accepted values.\n- This endpoint does not accept multiple request body properties in a single call. For example, you cannot pass both the \\`content\\` and \\`type\\` property at the same time.\n- Multi-file specifications can only have one root file.\n- When updating a file type to \\`ROOT\\`, the previous root file is updated to the \\`DEFAULT\\` file type.\n- Files cannot exceed a maximum of 10 MB in size.\n", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; + +export async function handler( + params: z.infer, + extra: { apiKey: string; headers?: IsomorphicHeaders } +): 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.name !== undefined) bodyPayload.name = params.name; + if (params.type !== undefined) bodyPayload.type = params.type; + 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, + headers: extra.headers, + }); + 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}` }], + }; + } +}