From a5221e147c01d9f5361100688f36b7f3dc43358d Mon Sep 17 00:00:00 2001 From: mshlz Date: Wed, 31 Jan 2024 13:14:28 -0300 Subject: [PATCH] chore: build --- .gitignore | 9 +- .yarnrc.yml | 1 + dist/body-parser.d.ts | 19 ++++ dist/body-parser.js | 168 +++++++++++++++++++++++++++++++++++ dist/body-parser.mjs | 134 ++++++++++++++++++++++++++++ dist/body-parser.types.d.ts | 23 +++++ dist/body-parser.types.js | 29 ++++++ dist/body-parser.types.mjs | 5 ++ dist/body-parser.utils.d.ts | 27 ++++++ dist/body-parser.utils.js | 106 ++++++++++++++++++++++ dist/body-parser.utils.mjs | 69 +++++++++++++++ dist/index.d.ts | 4 + dist/index.js | 171 ++++++++++++++++++++++++++++++++++++ dist/index.mjs | 135 ++++++++++++++++++++++++++++ package.json | 4 + src/body-parser.ts | 1 + 16 files changed, 903 insertions(+), 2 deletions(-) create mode 100644 .yarnrc.yml create mode 100644 dist/body-parser.d.ts create mode 100644 dist/body-parser.js create mode 100644 dist/body-parser.mjs create mode 100644 dist/body-parser.types.d.ts create mode 100644 dist/body-parser.types.js create mode 100644 dist/body-parser.types.mjs create mode 100644 dist/body-parser.utils.d.ts create mode 100644 dist/body-parser.utils.js create mode 100644 dist/body-parser.utils.mjs create mode 100644 dist/index.d.ts create mode 100644 dist/index.js create mode 100644 dist/index.mjs diff --git a/.gitignore b/.gitignore index 1e39d9f..bef00bc 100644 --- a/.gitignore +++ b/.gitignore @@ -18,11 +18,16 @@ yarn-error.log # Build # ################### -dist -build +# dist +# build # NYC # ################### coverage *.lcov .nyc_output + + +# YARN # +################### +.yarn \ No newline at end of file diff --git a/.yarnrc.yml b/.yarnrc.yml new file mode 100644 index 0000000..3186f3f --- /dev/null +++ b/.yarnrc.yml @@ -0,0 +1 @@ +nodeLinker: node-modules diff --git a/dist/body-parser.d.ts b/dist/body-parser.d.ts new file mode 100644 index 0000000..b4037ea --- /dev/null +++ b/dist/body-parser.d.ts @@ -0,0 +1,19 @@ +import * as Koa from 'koa'; +import { BodyParserOptions } from './body-parser.types.js'; +import 'co-body'; + +declare module 'koa' { + interface Request { + body?: any; + rawBody: string; + } +} +declare module 'http' { + interface IncomingMessage { + body?: any; + rawBody: string; + } +} +declare function bodyParserWrapper(opts?: BodyParserOptions): (ctx: Koa.Context, next: Koa.Next) => Promise; + +export { bodyParserWrapper }; diff --git a/dist/body-parser.js b/dist/body-parser.js new file mode 100644 index 0000000..f9c834e --- /dev/null +++ b/dist/body-parser.js @@ -0,0 +1,168 @@ +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 = {}) { + opts.jsonLimit = opts.jsonLimit || "10mb"; + 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 = detectJSON?.(ctx) || shouldParseBodyAs("json") ? "json" : shouldParseBodyAs("form") ? "form" : shouldParseBodyAs("text") || shouldParseBodyAs("xml") ? "text" : 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`] + }; + return import_co_body.default[bodyType](ctx, parserOptions); + } + return async function(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(); + } + 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 +}); diff --git a/dist/body-parser.mjs b/dist/body-parser.mjs new file mode 100644 index 0000000..764d2b5 --- /dev/null +++ b/dist/body-parser.mjs @@ -0,0 +1,134 @@ +// src/body-parser.ts +import parser from "co-body"; + +// src/body-parser.utils.ts +import deepMerge from "lodash.merge"; +import typeis from "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 = deepMerge(defaultMimeTypes, extendTypes); + return mimeTypes; +} +function isTypes(contentTypeValue, types) { + if (typeof contentTypeValue === "string") { + contentTypeValue = contentTypeValue.replace(/;$/, ""); + } + return typeis.is(contentTypeValue, types); +} + +// src/body-parser.ts +function bodyParserWrapper(opts = {}) { + opts.jsonLimit = opts.jsonLimit || "10mb"; + 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 = detectJSON?.(ctx) || shouldParseBodyAs("json") ? "json" : shouldParseBodyAs("form") ? "form" : shouldParseBodyAs("text") || shouldParseBodyAs("xml") ? "text" : 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`] + }; + return parser[bodyType](ctx, parserOptions); + } + return async function(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(); + } + 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(); + }; +} +export { + bodyParserWrapper +}; diff --git a/dist/body-parser.types.d.ts b/dist/body-parser.types.d.ts new file mode 100644 index 0000000..a86a084 --- /dev/null +++ b/dist/body-parser.types.d.ts @@ -0,0 +1,23 @@ +import { Options } from 'co-body'; +import * as Koa from 'koa'; + +declare const supportedBodyTypes: readonly ["json", "form", "text", "xml"]; +type BodyType = (typeof supportedBodyTypes)[number]; +type BodyParserOptions = { + parsedMethods?: string[]; + patchNode?: boolean; + detectJSON?: (ctx: Koa.Context) => boolean; + onError?: (error: Error, ctx: Koa.Context) => void; + enableRawChecking?: boolean; + enableTypes?: BodyType[]; + extendTypes?: { + [K in BodyType]?: string[]; + }; + jsonStrict?: Options['strict']; + jsonLimit?: Options['limit']; + formLimit?: Options['limit']; + textLimit?: Options['limit']; + xmlLimit?: Options['limit']; +} & Pick; + +export { BodyParserOptions, BodyType, supportedBodyTypes }; diff --git a/dist/body-parser.types.js b/dist/body-parser.types.js new file mode 100644 index 0000000..47e0b35 --- /dev/null +++ b/dist/body-parser.types.js @@ -0,0 +1,29 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// src/body-parser.types.ts +var body_parser_types_exports = {}; +__export(body_parser_types_exports, { + supportedBodyTypes: () => supportedBodyTypes +}); +module.exports = __toCommonJS(body_parser_types_exports); +var supportedBodyTypes = ["json", "form", "text", "xml"]; +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + supportedBodyTypes +}); diff --git a/dist/body-parser.types.mjs b/dist/body-parser.types.mjs new file mode 100644 index 0000000..4c93006 --- /dev/null +++ b/dist/body-parser.types.mjs @@ -0,0 +1,5 @@ +// src/body-parser.types.ts +var supportedBodyTypes = ["json", "form", "text", "xml"]; +export { + supportedBodyTypes +}; diff --git a/dist/body-parser.utils.d.ts b/dist/body-parser.utils.d.ts new file mode 100644 index 0000000..9637e94 --- /dev/null +++ b/dist/body-parser.utils.d.ts @@ -0,0 +1,27 @@ +import { BodyType, BodyParserOptions } from './body-parser.types.js'; +import 'co-body'; +import 'koa'; + +declare class UnsupportedBodyTypeError extends Error { + constructor(wrongType: string); +} +declare function getIsEnabledBodyAs(enableTypes: BodyType[]): { + json?: string[] | undefined; + form?: string[] | undefined; + text?: string[] | undefined; + xml?: string[] | undefined; +}; +declare function getMimeTypes(extendTypes: NonNullable): { + json: string[]; + form: string[]; + text: string[]; + xml: string[]; +} & { + json?: string[] | undefined; + form?: string[] | undefined; + text?: string[] | undefined; + xml?: string[] | undefined; +}; +declare function isTypes(contentTypeValue: string, types: string[]): string | false; + +export { UnsupportedBodyTypeError, getIsEnabledBodyAs, getMimeTypes, isTypes }; diff --git a/dist/body-parser.utils.js b/dist/body-parser.utils.js new file mode 100644 index 0000000..b29f622 --- /dev/null +++ b/dist/body-parser.utils.js @@ -0,0 +1,106 @@ +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.utils.ts +var body_parser_utils_exports = {}; +__export(body_parser_utils_exports, { + UnsupportedBodyTypeError: () => UnsupportedBodyTypeError, + getIsEnabledBodyAs: () => getIsEnabledBodyAs, + getMimeTypes: () => getMimeTypes, + isTypes: () => isTypes +}); +module.exports = __toCommonJS(body_parser_utils_exports); +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); +} +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + UnsupportedBodyTypeError, + getIsEnabledBodyAs, + getMimeTypes, + isTypes +}); diff --git a/dist/body-parser.utils.mjs b/dist/body-parser.utils.mjs new file mode 100644 index 0000000..f2b72e4 --- /dev/null +++ b/dist/body-parser.utils.mjs @@ -0,0 +1,69 @@ +// src/body-parser.utils.ts +import deepMerge from "lodash.merge"; +import typeis from "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 = deepMerge(defaultMimeTypes, extendTypes); + return mimeTypes; +} +function isTypes(contentTypeValue, types) { + if (typeof contentTypeValue === "string") { + contentTypeValue = contentTypeValue.replace(/;$/, ""); + } + return typeis.is(contentTypeValue, types); +} +export { + UnsupportedBodyTypeError, + getIsEnabledBodyAs, + getMimeTypes, + isTypes +}; diff --git a/dist/index.d.ts b/dist/index.d.ts new file mode 100644 index 0000000..85c2a79 --- /dev/null +++ b/dist/index.d.ts @@ -0,0 +1,4 @@ +export { bodyParserWrapper as bodyParser, bodyParserWrapper as default } from './body-parser.js'; +import 'koa'; +import './body-parser.types.js'; +import 'co-body'; diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..5e20c69 --- /dev/null +++ b/dist/index.js @@ -0,0 +1,171 @@ +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/index.ts +var src_exports = {}; +__export(src_exports, { + bodyParser: () => bodyParserWrapper, + default: () => bodyParserWrapper +}); +module.exports = __toCommonJS(src_exports); + +// src/body-parser.ts +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 = {}) { + opts.jsonLimit = opts.jsonLimit || "10mb"; + 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 = detectJSON?.(ctx) || shouldParseBodyAs("json") ? "json" : shouldParseBodyAs("form") ? "form" : shouldParseBodyAs("text") || shouldParseBodyAs("xml") ? "text" : 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`] + }; + return import_co_body.default[bodyType](ctx, parserOptions); + } + return async function(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(); + } + 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 = { + bodyParser +}); diff --git a/dist/index.mjs b/dist/index.mjs new file mode 100644 index 0000000..b74efea --- /dev/null +++ b/dist/index.mjs @@ -0,0 +1,135 @@ +// src/body-parser.ts +import parser from "co-body"; + +// src/body-parser.utils.ts +import deepMerge from "lodash.merge"; +import typeis from "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 = deepMerge(defaultMimeTypes, extendTypes); + return mimeTypes; +} +function isTypes(contentTypeValue, types) { + if (typeof contentTypeValue === "string") { + contentTypeValue = contentTypeValue.replace(/;$/, ""); + } + return typeis.is(contentTypeValue, types); +} + +// src/body-parser.ts +function bodyParserWrapper(opts = {}) { + opts.jsonLimit = opts.jsonLimit || "10mb"; + 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 = detectJSON?.(ctx) || shouldParseBodyAs("json") ? "json" : shouldParseBodyAs("form") ? "form" : shouldParseBodyAs("text") || shouldParseBodyAs("xml") ? "text" : 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`] + }; + return parser[bodyType](ctx, parserOptions); + } + return async function(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(); + } + 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(); + }; +} +export { + bodyParserWrapper as bodyParser, + bodyParserWrapper as default +}; diff --git a/package.json b/package.json index 8e72cad..0113ab3 100644 --- a/package.json +++ b/package.json @@ -82,5 +82,9 @@ "homepage": "https://github.com/koajs/body-parser", "publishConfig": { "access": "public" + }, + "volta": { + "node": "20.11.0", + "yarn": "4.1.0" } } diff --git a/src/body-parser.ts b/src/body-parser.ts index 3b9993c..dfa3094 100644 --- a/src/body-parser.ts +++ b/src/body-parser.ts @@ -25,6 +25,7 @@ declare module 'http' { * Middleware wrapper which delegate options to the core code */ export function bodyParserWrapper(opts: BodyParserOptions = {}) { + opts.jsonLimit = opts.jsonLimit || "10mb" const { patchNode = false, parsedMethods = ['POST', 'PUT', 'PATCH'],