@koa/bodyparser
Version:
Koa body parsing middleware
176 lines (170 loc) • 6.28 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/body-parser.ts
var body_parser_exports = {};
__export(body_parser_exports, {
bodyParserWrapper: () => bodyParserWrapper
});
module.exports = __toCommonJS(body_parser_exports);
var import_co_body = __toESM(require("co-body"));
// src/body-parser.utils.ts
var import_lodash = __toESM(require("lodash.merge"));
var import_type_is = __toESM(require("type-is"));
// src/body-parser.types.ts
var supportedBodyTypes = ["json", "form", "text", "xml"];
// src/body-parser.utils.ts
var UnsupportedBodyTypeError = class extends Error {
constructor(wrongType) {
super();
this.name = "UnsupportedBodyTypeError";
this.message = `Invalid enabled type '${wrongType}'. make sure to pass an array contains supported types ([${supportedBodyTypes}]).`;
}
};
function getIsEnabledBodyAs(enableTypes) {
for (const enabledType of enableTypes) {
if (!supportedBodyTypes.includes(enabledType)) {
throw new UnsupportedBodyTypeError(enabledType);
}
}
const isEnabledBodyAs = supportedBodyTypes.reduce(
(prevResult, currentType) => ({
...prevResult,
[currentType]: enableTypes.includes(currentType)
}),
{}
);
return isEnabledBodyAs;
}
function getMimeTypes(extendTypes) {
for (const extendedTypeKey of Object.keys(extendTypes)) {
const extendedType = extendTypes[extendedTypeKey];
if (!supportedBodyTypes.includes(extendedTypeKey) || !Array.isArray(extendedType)) {
throw new UnsupportedBodyTypeError(extendedTypeKey);
}
}
const defaultMimeTypes = {
// default json mime types
json: [
"application/json",
"application/json-patch+json",
"application/vnd.api+json",
"application/csp-report",
"application/reports+json",
"application/scim+json"
],
// default form mime types
form: ["application/x-www-form-urlencoded"],
// default text mime types
text: ["text/plain"],
// default xml mime types
xml: ["text/xml", "application/xml"]
};
const mimeTypes = (0, import_lodash.default)(defaultMimeTypes, extendTypes);
return mimeTypes;
}
function isTypes(contentTypeValue, types) {
if (typeof contentTypeValue === "string") {
contentTypeValue = contentTypeValue.replace(/;$/, "");
}
return import_type_is.default.is(contentTypeValue, types);
}
// src/body-parser.ts
function bodyParserWrapper(opts = {}) {
const {
patchNode = false,
parsedMethods = ["POST", "PUT", "PATCH"],
detectJSON,
onError,
enableTypes = ["json", "form"],
extendTypes = {},
enableRawChecking = false,
...restOpts
} = opts;
const isEnabledBodyAs = getIsEnabledBodyAs(enableTypes);
const mimeTypes = getMimeTypes(extendTypes);
async function parseBody(ctx) {
const shouldParseBodyAs = (type) => {
return Boolean(
isEnabledBodyAs[type] && isTypes(ctx.request.get("content-type"), mimeTypes[type])
);
};
const bodyType = (() => {
if (detectJSON?.(ctx) || shouldParseBodyAs("json")) return "json";
if (shouldParseBodyAs("form")) return "form";
if (shouldParseBodyAs("text") || shouldParseBodyAs("xml")) return "text";
return null;
})();
if (!bodyType) return {};
const parserOptions = {
// force co-body return raw body
returnRawBody: true,
strict: bodyType === "json" ? restOpts.jsonStrict : void 0,
[`${bodyType}Types`]: mimeTypes[bodyType],
limit: restOpts[`${shouldParseBodyAs("xml") ? "xml" : bodyType}Limit`],
// eslint-disable-next-line unicorn/text-encoding-identifier-case
encoding: restOpts.encoding || "utf-8"
};
return import_co_body.default[bodyType](ctx, parserOptions);
}
return async function bodyParser(ctx, next) {
if (
// method souldn't be parsed
!parsedMethods.includes(ctx.method.toUpperCase()) || // patchNode enabled and raw request already parsed
patchNode && ctx.req.body !== void 0 || // koa request body already parsed
ctx.request.body !== void 0 || // bodyparser disabled
ctx.disableBodyParser
)
return next();
if (enableRawChecking && ctx.req.body !== void 0) {
ctx.request.body = ctx.req.body;
return next();
}
if (ctx.req.closed) {
ctx.status = 499;
ctx.body = "Request already closed";
return;
}
try {
const response = await parseBody(ctx);
if (patchNode) {
ctx.req.body = "parsed" in response ? response.parsed : {};
if (ctx.req.rawBody === void 0) ctx.req.rawBody = response.raw;
}
ctx.request.body = "parsed" in response ? response.parsed : {};
if (ctx.request.rawBody === void 0) ctx.request.rawBody = response.raw;
} catch (err) {
if (!onError) throw err;
onError(err, ctx);
}
return next();
};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
bodyParserWrapper
});