UNPKG

@graphql-hive/cli

Version:

A CLI util to manage and control your GraphQL Hive

136 lines • 8.19 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.graphqlRequest = graphqlRequest; exports.cleanRequestId = cleanRequestId; exports.isIntrospectionDisabledError = isIntrospectionDisabledError; const graphql_1 = require("graphql"); const core_1 = require("@graphql-hive/core"); const errors_1 = require("./errors"); function graphqlRequest(config) { const requestHeaders = Object.assign({ 'Content-Type': 'application/json', Accept: 'application/json', 'User-Agent': `hive-cli/${config.version}` }, config.additionalHeaders); return { request: async (args) => { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l; let response; try { response = await core_1.http.post(config.endpoint, JSON.stringify({ query: typeof args.operation === 'string' ? args.operation : (0, graphql_1.print)(args.operation), variables: args.variables, }), { logger: config.logger, headers: requestHeaders, timeout: args.timeout, }); } catch (e) { if (typeof (e === null || e === void 0 ? void 0 : e.status) === 'number') { throw new errors_1.HTTPError(config.endpoint, e.status, e.statusText || e.message); } if (config.isHiveRegistry && (0, errors_1.isTimeoutError)(e)) { throw new errors_1.RequestTimeoutError(config.endpoint, (_a = e === null || e === void 0 ? void 0 : e.cause) !== null && _a !== void 0 ? _a : e); } const sourceError = (_b = e === null || e === void 0 ? void 0 : e.cause) !== null && _b !== void 0 ? _b : e; if ((0, errors_1.isAggregateError)(sourceError)) { throw new errors_1.NetworkError((_c = sourceError.errors[0]) === null || _c === void 0 ? void 0 : _c.message); } else { throw new errors_1.NetworkError(sourceError); } } if (!response.ok) { throw new errors_1.HTTPError(config.endpoint, response.status, (_d = response.statusText) !== null && _d !== void 0 ? _d : 'Invalid status code for HTTP call'); } let jsonData; try { jsonData = (await response.json()); } catch (err) { (_f = (_e = config.logger) === null || _e === void 0 ? void 0 : _e.debug) === null || _f === void 0 ? void 0 : _f.call(_e, String(err)); const contentType = (_g = response === null || response === void 0 ? void 0 : response.headers) === null || _g === void 0 ? void 0 : _g.get('content-type'); throw new errors_1.APIError(`Response from graphql was not valid JSON.${contentType ? ` Received "content-type": "${contentType}".` : ''}`, cleanRequestId((_h = response === null || response === void 0 ? void 0 : response.headers) === null || _h === void 0 ? void 0 : _h.get('x-request-id'))); } if (jsonData.errors && jsonData.errors.length > 0) { (_k = (_j = config.logger) === null || _j === void 0 ? void 0 : _j.debug) === null || _k === void 0 ? void 0 : _k.call(_j, jsonData.errors.map(String).join('\n')); const requestId = cleanRequestId((_l = response === null || response === void 0 ? void 0 : response.headers) === null || _l === void 0 ? void 0 : _l.get('x-request-id')); if (config.isHiveRegistry) { throwRegistryError(config.endpoint, jsonData.errors, requestId); } else if (isIntrospectionDisabledError(jsonData.errors[0])) { throw new errors_1.IntrospectionError(config.endpoint); } throw new errors_1.APIError(jsonData.errors.map(e => e.message).join('\n'), requestId, jsonData.errors); } return jsonData.data; }, }; } const missingPermissionPattern = /Missing permission for performing '([^']+)'/; /** GraphQL validation errors caused by the server not knowing a field, argument, input field or type the CLI sends. */ const unsupportedByServerPatterns = [ /^Cannot query field "[^"]+" on type "[^"]+"\./, /^Unknown argument "[^"]+" on field "[^"]+"\./, /^Unknown type "[^"]+"\./, /^Variable "\$[^"]+" got invalid value [\s\S]*; Field "[^"]+" is not defined by type "[^"]+"\./, ]; /** Reported alongside "Unknown type" when a variable of that type exists. */ const unusedVariablePattern = /^Variable "\$[^"]+" is never used/; function isUnsupportedByServer(errors) { return (errors.some(error => unsupportedByServerPatterns.some(pattern => pattern.test(error.message))) && errors.every(error => unusedVariablePattern.test(error.message) || unsupportedByServerPatterns.some(pattern => pattern.test(error.message)))); } /** * Hive registry API errors that have a dedicated CLI error. * The registry reports authentication failures either as "Invalid token provided" (access tokens) * or with the UNAUTHENTICATED / NEEDS_REFRESH codes (session tokens), * and authorization failures with the UNAUTHORISED code. */ function throwRegistryError(endpoint, errors, requestId) { var _a, _b; if (errors.some(error => { var _a; return ((_a = error.extensions) === null || _a === void 0 ? void 0 : _a.code) === 'ERR_MISSING_TARGET'; })) { throw new errors_1.MissingArgumentsError([ 'target', 'The target on which the action is performed.' + ' This can either be a slug following the format "$organizationSlug/$projectSlug/$targetSlug" (e.g "the-guild/graphql-hive/staging")' + ' or an UUID (e.g. "a0f4c605-6541-4350-8cfe-b31f21a4bf80").', ]); } if (errors.some(error => { var _a, _b; return error.message === 'Invalid token provided' || ((_a = error.extensions) === null || _a === void 0 ? void 0 : _a.code) === 'UNAUTHENTICATED' || ((_b = error.extensions) === null || _b === void 0 ? void 0 : _b.code) === 'NEEDS_REFRESH'; })) { throw new errors_1.InvalidRegistryTokenError(); } const accessError = errors.find(error => { var _a; return ((_a = error.extensions) === null || _a === void 0 ? void 0 : _a.code) === 'UNAUTHORISED'; }); if (accessError) { throw new errors_1.AccessDeniedError(accessError.message, (_b = (_a = accessError.message.match(missingPermissionPattern)) === null || _a === void 0 ? void 0 : _a[1]) !== null && _b !== void 0 ? _b : null, requestId); } if (isUnsupportedByServer(errors)) { throw new errors_1.UnsupportedServerError(endpoint, errors); } } function cleanRequestId(requestId) { return requestId ? requestId.split(',')[0].trim() : undefined; } function isIntrospectionDisabledError(error) { var _a, _b, _c; // Default implementation - this is the string used by graphql-js and thus the majority of all other implementations // as they use graphql-js as a reference. // https://github.com/graphql/graphql-js/blob/8eb6383ae7447514343457abb2063c40e5dc81bc/src/validation/rules/custom/NoSchemaIntrospectionCustomRule.ts#L30 if ((_a = error.message) === null || _a === void 0 ? void 0 : _a.includes('GraphQL introspection has been disabled')) { return true; } // Apollo Server // https://github.com/apollographql/apollo-server/blob/19d0ffca703f85f0184532393aa3fff687f30bca/packages/server/src/validationRules/NoIntrospection.ts#L20 if (((_b = error.extensions) === null || _b === void 0 ? void 0 : _b['validationErrorCode']) === 'INTROSPECTION_DISABLED') { return true; } // https://github.com/apollographql/apollo-server/blob/19d0ffca703f85f0184532393aa3fff687f30bca/packages/server/src/validationRules/NoIntrospection.ts#L15 if ((_c = error.message) === null || _c === void 0 ? void 0 : _c.includes('GraphQL introspection is not allowed')) { return true; } return false; } //# sourceMappingURL=graphql-request.js.map