@jupiterone/jupiterone-mcp
Version:
Model Context Protocol server for JupiterOne account rules and rule details
72 lines • 3.19 kB
JavaScript
;
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