graphql-yoga
Version:
107 lines (106 loc) • 4.69 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.INCREMENTAL_DELIVERY_SPECS = exports.getMultipartContentType = exports.DEFAULT_MULTIPART_CONTENT_TYPE = void 0;
exports.getMediaTypesForRequestInOrder = getMediaTypesForRequestInOrder;
exports.isMatchingMediaType = isMatchingMediaType;
exports.negotiateIncrementalSpecFromMediaType = negotiateIncrementalSpecFromMediaType;
exports.getIncrementalSpecForRequest = getIncrementalSpecForRequest;
const utils_1 = require("@graphql-tools/utils");
var utils_2 = require("@graphql-tools/utils");
Object.defineProperty(exports, "DEFAULT_MULTIPART_CONTENT_TYPE", { enumerable: true, get: function () { return utils_2.DEFAULT_MULTIPART_CONTENT_TYPE; } });
Object.defineProperty(exports, "getMultipartContentType", { enumerable: true, get: function () { return utils_2.getMultipartContentType; } });
Object.defineProperty(exports, "INCREMENTAL_DELIVERY_SPECS", { enumerable: true, get: function () { return utils_2.INCREMENTAL_DELIVERY_SPECS; } });
function typeAndSubtype(mediaType) {
const [essence] = mediaType.split(';');
const [pre, suf] = (essence ?? '').split('/');
return [pre ?? '', suf ?? ''];
}
function parseMediaTypeParams(mediaType) {
const params = {};
const parts = mediaType.split(';');
for (let i = 1; i < parts.length; i++) {
const part = parts[i];
if (part == null)
continue;
const eq = part.indexOf('=');
if (eq === -1)
continue;
let value = part.slice(eq + 1);
if (value.startsWith('"') && value.endsWith('"') && value.length >= 2) {
value = value.slice(1, -1);
}
params[part.slice(0, eq)] = value;
}
return params;
}
function getMediaTypesForRequestInOrder(request, specs = utils_1.INCREMENTAL_DELIVERY_SPECS) {
const specParamNames = (0, utils_1.getIncrementalSpecParameterNames)(specs);
const accepts = (request.headers.get('accept') || '*/*')
.replace(/\s/g, '')
.toLowerCase()
.split(',');
const mediaTypes = [];
for (const accept of accepts) {
const [mediaType, ...params] = accept.split(';');
if (mediaType === undefined)
continue; // If true, malformed header.
const charset = params?.find(param => param.includes('charset=')) || 'charset=utf-8'; // utf-8 is assumed when not specified;
if (charset !== 'charset=utf-8') {
// only utf-8 is supported
continue;
}
const specParams = params.filter(param => {
const name = param.split('=')[0];
return name != null && specParamNames.has(name);
});
mediaTypes.push(specParams.length ? `${mediaType};${specParams.join(';')}` : mediaType);
}
return mediaTypes.reverse();
}
function isMatchingMediaType(askedMediaType, processorMediaType) {
const [askedPre, askedSuf] = typeAndSubtype(askedMediaType);
const [pre, suf] = typeAndSubtype(processorMediaType);
if ((pre === '*' || pre === askedPre) && (suf === '*' || suf === askedSuf)) {
return true;
}
return false;
}
/**
* Map a single Accept media type to an executor `incrementalSpec` using the
* registered HTTP parameter table. Non-multipart types return `undefined`.
*/
function negotiateIncrementalSpecFromMediaType(mediaType, specs = utils_1.INCREMENTAL_DELIVERY_SPECS) {
const [type, subtype] = typeAndSubtype(mediaType);
if (type !== 'multipart' || subtype !== 'mixed') {
return undefined;
}
const lookedUp = (0, utils_1.lookupIncrementalDeliverySpec)(parseMediaTypeParams(mediaType), specs);
if (lookedUp === 'unsupported') {
return 'unsupported';
}
if (lookedUp) {
return {
spec: lookedUp.id,
contentType: (0, utils_1.getMultipartContentType)(lookedUp, { echoSpec: true }),
};
}
const fallback = (0, utils_1.getDefaultIncrementalDeliverySpec)(specs);
return {
spec: fallback.id,
contentType: (0, utils_1.getMultipartContentType)(fallback, { echoSpec: false }),
};
}
/**
* Last matching `multipart/mixed` in the request Accept list (same last-match
* rule as result-processor selection). `undefined` leaves the executor default.
*/
function getIncrementalSpecForRequest(request, specs = utils_1.INCREMENTAL_DELIVERY_SPECS) {
let spec;
for (const mediaType of getMediaTypesForRequestInOrder(request, specs)) {
const negotiated = negotiateIncrementalSpecFromMediaType(mediaType, specs);
if (negotiated && negotiated !== 'unsupported') {
spec = negotiated.spec;
}
}
return spec;
}