UNPKG

@jupiterone/jupiterone-mcp

Version:

Model Context Protocol server for JupiterOne account rules and rule details

72 lines 3.19 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SanitizingGraphQLClient = exports.JupiterOneApiError = void 0; exports.sanitizeGraphQLError = sanitizeGraphQLError; const graphql_request_1 = require("graphql-request"); /** * Error surfaced to callers in place of graphql-request's `ClientError`. * * `ClientError.message` embeds `JSON.stringify({ response, request })` — i.e. the full * GraphQL query, its variables, and the response status/headers/body. Surfacing that into * model context or stderr leaks internal API structure and (via variables) potentially * sensitive values. This type exposes only the upstream error message and status code. */ class JupiterOneApiError extends Error { statusCode; /** * The first GraphQL error's `extensions.code` (e.g. `FORBIDDEN`, `UNAUTHENTICATED`) when the * upstream delivered the failure as a GraphQL error inside an HTTP 200. Authorization rejections * arrive this way, so preserving the code lets the error layer frame them as access-denied even * though the transport status is 200. */ code; constructor(message, statusCode, code) { super(message); this.name = 'JupiterOneApiError'; this.statusCode = statusCode; this.code = code; } } exports.JupiterOneApiError = JupiterOneApiError; /** * Convert any thrown value into a sanitized error safe for model context and logs. * * For a `ClientError`, keeps only the upstream GraphQL error message (which the J1QL * validator pattern-matches on) and the status code; drops the query, variables, headers, * and raw response body. Other errors are reduced to their message with no object dumping. */ function sanitizeGraphQLError(error) { if (error instanceof JupiterOneApiError) { return error; } if (error instanceof graphql_request_1.ClientError) { const status = error.response?.status; const firstError = error.response?.errors?.[0]; const message = firstError?.message ?? `JupiterOne API error${status ? ` (status ${status})` : ''}`; const code = firstError?.extensions?.code; return new JupiterOneApiError(message, status, typeof code === 'string' ? code : undefined); } if (error instanceof Error) { return new JupiterOneApiError(error.message); } return new JupiterOneApiError('JupiterOne API request failed'); } /** * GraphQLClient that routes every thrown error through {@link sanitizeGraphQLError}. Fixing * the leak at the single shared client means downstream services and tool handlers never * see the raw `ClientError`, without editing every call site. */ class SanitizingGraphQLClient extends graphql_request_1.GraphQLClient { // The base `request` is overloaded; accept/forward args opaquely and sanitize on throw. async request(...args) { const baseRequest = super.request.bind(this); try { return await baseRequest(...args); } catch (error) { throw sanitizeGraphQLError(error); } } } exports.SanitizingGraphQLClient = SanitizingGraphQLClient; //# sourceMappingURL=sanitize-error.js.map