@worker-tools/middleware
Version:
A suite of standalone HTTP server middlewares for Worker Runtimes.
148 lines • 7.09 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.acceptsEncodings = exports.acceptsLanguages = exports.accepts = exports.providesEncodings = exports.providesLanguages = exports.provides = exports.contentEncodings = exports.contentLanguages = exports.contentTypes = void 0;
// deno-lint-ignore-file
const response_creators_1 = require("@worker-tools/response-creators");
const negotiated_1 = __importDefault(require("negotiated"));
const weightSortFn = (a, b) => a.weight >= b.weight ? a : b;
const ACCEPT = 'Accept';
const ACCEPT_ENCODING = 'Accept-Encoding';
const ACCEPT_LANGUAGE = 'Accept-Language';
const CONTENT_TYPE = 'Content-Type';
const CONTENT_LANGUAGE = 'Content-Language';
const CONTENT_ENCODING = 'Content-Encoding';
const VARY = 'Vary';
/**
* Performs content negotiation over the content type of the response.
* @param types The content types _provided_ by this endpoint.
*/
function contentTypes(types) {
return async (ax) => {
const ctx = await ax;
const { headers } = ctx.request;
const type = [...negotiated_1.default.mediaTypes(headers.get(ACCEPT))]
.filter(t => !types || types.includes(t.type))
.reduce(weightSortFn, { weight: -1 }).type;
if (headers.has(ACCEPT) && types && !type)
throw (0, response_creators_1.notAcceptable)();
ctx.effects.push(response => {
var _a;
if (!response.headers.has(CONTENT_TYPE))
response.headers.set(CONTENT_TYPE, type);
// If the server accepts more than 1 option, we set the vary header for correct caching
if (((_a = types === null || types === void 0 ? void 0 : types.length) !== null && _a !== void 0 ? _a : 0) > 1)
response.headers.append(VARY, ACCEPT);
return response;
});
return Object.assign(ctx, { type });
};
}
exports.contentTypes = contentTypes;
exports.provides = contentTypes;
/**
* Performs content negotiation over the content language of the response.
* @param languages The languages _provided_ by this endpoint.
*/
function contentLanguages(languages) {
return async (ax) => {
const ctx = await ax;
const { headers } = ctx.request;
const language = [...negotiated_1.default.languages(headers.get(ACCEPT_LANGUAGE))]
.filter(l => !languages || languages.includes(l.language))
.reduce(weightSortFn, { weight: -1 }).language;
if (headers.has(ACCEPT_LANGUAGE) && languages && !language)
throw (0, response_creators_1.notAcceptable)();
ctx.effects.push(response => {
var _a;
if (!response.headers.has(CONTENT_LANGUAGE))
response.headers.set(CONTENT_LANGUAGE, language);
// If the server accepts more than 1 option, we set the vary header for correct caching
if (((_a = languages === null || languages === void 0 ? void 0 : languages.length) !== null && _a !== void 0 ? _a : 0) > 1)
response.headers.append(VARY, ACCEPT_LANGUAGE);
return response;
});
return Object.assign(ctx, { language });
};
}
exports.contentLanguages = contentLanguages;
exports.providesLanguages = contentLanguages;
/**
* Performs content negotiation over the content encoding of the response.
* @param encodings The encodings _provided_ by this endpoint.
*/
function contentEncodings(encodings) {
return async (ax) => {
const ctx = await ax;
const { headers } = ctx.request;
const encoding = [...negotiated_1.default.encodings(headers.get(ACCEPT_ENCODING))]
.filter(e => !encodings || encodings.includes(e.encoding))
.reduce(weightSortFn, { weight: -1 }).encoding;
// TODO: how to handle status errors in middleware??
if (headers.has(ACCEPT_ENCODING) && encodings && !encoding)
throw (0, response_creators_1.notAcceptable)();
ctx.effects.push(response => {
var _a;
if (!response.headers.has(CONTENT_ENCODING))
response.headers.set(CONTENT_ENCODING, encoding);
// If the server accepts more than 1 option, we set the vary header for correct caching
if (((_a = encodings === null || encodings === void 0 ? void 0 : encodings.length) !== null && _a !== void 0 ? _a : 0) > 1)
response.headers.append(VARY, ACCEPT_ENCODING);
return response;
});
return Object.assign(ctx, { encoding });
};
}
exports.contentEncodings = contentEncodings;
exports.providesEncodings = contentEncodings;
/**
* Determines if a request body content type is _acceptable_ to this endpoint.
* @param types The content types _acceptable_ to this endpoint.
*/
function accepts(types) {
return async (ax) => {
var _a;
const ctx = await ax;
const { headers } = ctx.request;
const accepted = (_a = [...negotiated_1.default.mediaTypes(headers.get(CONTENT_TYPE))][0]) === null || _a === void 0 ? void 0 : _a.type;
if ((types === null || types === void 0 ? void 0 : types.length) && !types.includes(accepted))
throw (0, response_creators_1.unsupportedMediaType)();
return Object.assign(ctx, { accepted });
};
}
exports.accepts = accepts;
/**
* Determines if a request body content language is _acceptable_ to this endpoint.
* @param languages The languages (of the request body) _acceptable_ to this endpoint.
*/
function acceptsLanguages(languages) {
return async (ax) => {
var _a;
const ctx = await ax;
const { headers } = ctx.request;
const acceptedLanguage = (_a = [...negotiated_1.default.languages(headers.get(CONTENT_LANGUAGE))][0]) === null || _a === void 0 ? void 0 : _a.language;
if ((languages === null || languages === void 0 ? void 0 : languages.length) && !languages.includes(acceptedLanguage))
throw (0, response_creators_1.notAcceptable)();
return Object.assign(ctx, { acceptedLanguage });
};
}
exports.acceptsLanguages = acceptsLanguages;
/**
* Determines if a request body content encoding is _acceptable_ to this endpoint.
* @param encodings The body encodings _acceptable_ to this endpoint.
*/
function acceptsEncodings(encodings) {
return async (ax) => {
var _a;
const ctx = await ax;
const { headers } = ctx.request;
const acceptedEncoding = (_a = [...negotiated_1.default.encodings(headers.get(CONTENT_ENCODING))][0]) === null || _a === void 0 ? void 0 : _a.encoding;
if ((encodings === null || encodings === void 0 ? void 0 : encodings.length) && !encodings.includes(acceptedEncoding))
throw (0, response_creators_1.notAcceptable)();
return Object.assign(ctx, { acceptedEncoding });
};
}
exports.acceptsEncodings = acceptsEncodings;
//# sourceMappingURL=content-negotiation.js.map