milliparsec 5.0.2 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,52 +1,36 @@
1
1
  import { Buffer } from 'node:buffer';
2
- import type { IncomingMessage, ServerResponse as Response } from 'node:http';
3
- type NextFunction = (err?: any) => void;
4
- /**
5
- * Request extension with a body
6
- */
7
- export type ReqWithBody<T = any> = IncomingMessage & {
8
- body?: T;
9
- };
10
- export declare const hasBody: (method: string) => boolean;
11
- export type LimitErrorFn = (limit: number) => Error;
12
- export type ParserOptions = Partial<{
13
- /**
14
- * Limit payload size (in bytes)
15
- * @default '100KB'
16
- */
17
- payloadLimit: number;
18
- /**
19
- * Custom error function for payload limit
20
- */
21
- payloadLimitErrorFn: LimitErrorFn;
22
- }>;
2
+ import type { ServerResponse as Response } from 'node:http';
3
+ import type { LimitErrorFn, NextFunction, ParserOptions, ReqWithBody } from './types.js';
4
+ export * from './types.js';
23
5
  export declare const p: <T = any>(fn: (body: Buffer) => void, payloadLimit?: number, payloadLimitErrorFn?: LimitErrorFn) => (req: ReqWithBody<T>, _res: Response, next?: (err?: any) => void) => Promise<void>;
24
6
  /**
25
7
  * Parse payload with a custom function
26
8
  * @param fn
27
9
  */
28
- declare const custom: <T = any>(fn: (body: Buffer) => any) => (req: ReqWithBody, _res: Response, next?: NextFunction) => Promise<void>;
10
+ declare const custom: <T = any>(fn: (body: Buffer) => any, type?: ParserOptions["type"]) => (req: ReqWithBody, _res: Response, next?: NextFunction) => Promise<void>;
29
11
  /**
30
12
  * Parse JSON payload
31
13
  * @param options
32
14
  */
33
- declare const json: ({ payloadLimit, payloadLimitErrorFn }?: ParserOptions) => (req: ReqWithBody, res: Response, next?: NextFunction) => Promise<void>;
15
+ declare const json: ({ payloadLimit, payloadLimitErrorFn, type, reviver }?: ParserOptions<{
16
+ reviver?: (this: any, key: string, value: any) => any;
17
+ }>) => (req: ReqWithBody, res: Response, next?: NextFunction) => Promise<void>;
34
18
  /**
35
19
  * Parse raw payload
36
20
  * @param options
37
21
  */
38
- declare const raw: ({ payloadLimit, payloadLimitErrorFn }?: ParserOptions) => (req: ReqWithBody, _res: Response, next?: NextFunction) => Promise<void>;
22
+ declare const raw: ({ payloadLimit, payloadLimitErrorFn, type }?: ParserOptions) => (req: ReqWithBody, _res: Response, next?: NextFunction) => Promise<void>;
39
23
  /**
40
24
  * Stringify request payload
41
25
  * @param param0
42
26
  * @returns
43
27
  */
44
- declare const text: ({ payloadLimit, payloadLimitErrorFn }?: ParserOptions) => (req: ReqWithBody, _res: Response, next?: NextFunction) => Promise<void>;
28
+ declare const text: ({ payloadLimit, payloadLimitErrorFn, type }?: ParserOptions) => (req: ReqWithBody, _res: Response, next?: NextFunction) => Promise<void>;
45
29
  /**
46
30
  * Parse urlencoded payload
47
31
  * @param options
48
32
  */
49
- declare const urlencoded: ({ payloadLimit, payloadLimitErrorFn }?: ParserOptions) => (req: ReqWithBody, _res: Response, next?: NextFunction) => Promise<void>;
33
+ declare const urlencoded: ({ payloadLimit, payloadLimitErrorFn, type }?: ParserOptions) => (req: ReqWithBody, _res: Response, next?: NextFunction) => Promise<void>;
50
34
  type MultipartOptions = Partial<{
51
35
  /**
52
36
  * Limit number of files
@@ -67,5 +51,5 @@ type MultipartOptions = Partial<{
67
51
  * Does not restrict total payload size by default.
68
52
  * @param options
69
53
  */
70
- declare const multipart: ({ payloadLimit, payloadLimitErrorFn, ...opts }?: MultipartOptions & ParserOptions) => (req: ReqWithBody, res: Response, next?: NextFunction) => Promise<void>;
54
+ declare const multipart: ({ payloadLimit, payloadLimitErrorFn, type, ...opts }?: MultipartOptions & ParserOptions) => (req: ReqWithBody, res: Response, next?: NextFunction) => Promise<void>;
71
55
  export { custom, json, raw, text, urlencoded, multipart };
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Buffer, File } from 'node:buffer';
2
- export const hasBody = (method) => ['POST', 'PUT', 'PATCH', 'DELETE'].includes(method);
3
- const defaultPayloadLimit = 102400; // 100KB
2
+ import { checkType, hasBody } from './utils.js';
3
+ export * from './types.js';
4
+ const defaultPayloadLimit = 102400; // 100KiB
4
5
  const defaultErrorFn = (payloadLimit) => new Error(`Payload too large. Limit: ${payloadLimit} bytes`);
5
6
  // Main function
6
7
  export const p = (fn, payloadLimit = defaultPayloadLimit, payloadLimitErrorFn = defaultErrorFn) => async (req, _res, next) => {
@@ -22,8 +23,8 @@ export const p = (fn, payloadLimit = defaultPayloadLimit, payloadLimitErrorFn =
22
23
  * Parse payload with a custom function
23
24
  * @param fn
24
25
  */
25
- const custom = (fn) => async (req, _res, next) => {
26
- if (hasBody(req.method))
26
+ const custom = (fn, type) => async (req, _res, next) => {
27
+ if (hasBody(req.method) && checkType(req, type))
27
28
  req.body = await p(fn)(req, _res, next);
28
29
  next === null || next === void 0 ? void 0 : next();
29
30
  };
@@ -31,11 +32,11 @@ const custom = (fn) => async (req, _res, next) => {
31
32
  * Parse JSON payload
32
33
  * @param options
33
34
  */
34
- const json = ({ payloadLimit, payloadLimitErrorFn } = {}) => async (req, res, next) => {
35
- if (hasBody(req.method)) {
35
+ const json = ({ payloadLimit, payloadLimitErrorFn, type, reviver } = {}) => async (req, res, next) => {
36
+ if (hasBody(req.method) && checkType(req, type)) {
36
37
  req.body = await p((x) => {
37
38
  const str = td.decode(x);
38
- return str ? JSON.parse(str) : {};
39
+ return str ? JSON.parse(str, reviver) : {};
39
40
  }, payloadLimit, payloadLimitErrorFn)(req, res, next);
40
41
  }
41
42
  next === null || next === void 0 ? void 0 : next();
@@ -44,8 +45,8 @@ const json = ({ payloadLimit, payloadLimitErrorFn } = {}) => async (req, res, ne
44
45
  * Parse raw payload
45
46
  * @param options
46
47
  */
47
- const raw = ({ payloadLimit, payloadLimitErrorFn } = {}) => async (req, _res, next) => {
48
- if (hasBody(req.method)) {
48
+ const raw = ({ payloadLimit, payloadLimitErrorFn, type } = {}) => async (req, _res, next) => {
49
+ if (hasBody(req.method) && checkType(req, type)) {
49
50
  req.body = await p((x) => x, payloadLimit, payloadLimitErrorFn)(req, _res, next);
50
51
  }
51
52
  next === null || next === void 0 ? void 0 : next();
@@ -56,8 +57,8 @@ const td = new TextDecoder();
56
57
  * @param param0
57
58
  * @returns
58
59
  */
59
- const text = ({ payloadLimit, payloadLimitErrorFn } = {}) => async (req, _res, next) => {
60
- if (hasBody(req.method)) {
60
+ const text = ({ payloadLimit, payloadLimitErrorFn, type } = {}) => async (req, _res, next) => {
61
+ if (hasBody(req.method) && checkType(req, type)) {
61
62
  req.body = await p((x) => td.decode(x), payloadLimit, payloadLimitErrorFn)(req, _res, next);
62
63
  }
63
64
  next === null || next === void 0 ? void 0 : next();
@@ -66,8 +67,8 @@ const text = ({ payloadLimit, payloadLimitErrorFn } = {}) => async (req, _res, n
66
67
  * Parse urlencoded payload
67
68
  * @param options
68
69
  */
69
- const urlencoded = ({ payloadLimit, payloadLimitErrorFn } = {}) => async (req, _res, next) => {
70
- if (hasBody(req.method)) {
70
+ const urlencoded = ({ payloadLimit, payloadLimitErrorFn, type } = {}) => async (req, _res, next) => {
71
+ if (hasBody(req.method) && checkType(req, type)) {
71
72
  req.body = await p((x) => Object.fromEntries(new URLSearchParams(x.toString()).entries()), payloadLimit, payloadLimitErrorFn)(req, _res, next);
72
73
  }
73
74
  next === null || next === void 0 ? void 0 : next();
@@ -77,13 +78,12 @@ const getBoundary = (contentType) => {
77
78
  return match ? `--${match[1]}` : null;
78
79
  };
79
80
  const defaultFileSizeLimitErrorFn = (limit) => new Error(`File too large. Limit: ${limit} bytes`);
80
- const defaultFileSizeLimit = 200 * 1024 * 1024;
81
+ const defaultFileSizeLimit = 200 * 1024 * 1024; // 200MiB
81
82
  const parseMultipart = (body, boundary, { fileCountLimit, fileSizeLimit = defaultFileSizeLimit, fileSizeLimitErrorFn = defaultFileSizeLimitErrorFn }) => {
82
83
  const parts = body.split(new RegExp(`${boundary}(--)?`)).filter((part) => !!part && /content-disposition/i.test(part));
83
84
  const parsedBody = {};
84
85
  if (fileCountLimit && parts.length > fileCountLimit)
85
86
  throw new Error(`Too many files. Limit: ${fileCountLimit}`);
86
- // biome-ignore lint/complexity/noForEach: for...of fails
87
87
  parts.forEach((part) => {
88
88
  const [headers, ...lines] = part.split('\r\n').filter((part) => !!part);
89
89
  const data = lines.join('\r\n').trim();
@@ -110,8 +110,8 @@ const parseMultipart = (body, boundary, { fileCountLimit, fileSizeLimit = defaul
110
110
  * Does not restrict total payload size by default.
111
111
  * @param options
112
112
  */
113
- const multipart = ({ payloadLimit = Number.POSITIVE_INFINITY, payloadLimitErrorFn, ...opts } = {}) => async (req, res, next) => {
114
- if (hasBody(req.method)) {
113
+ const multipart = ({ payloadLimit = Number.POSITIVE_INFINITY, payloadLimitErrorFn, type, ...opts } = {}) => async (req, res, next) => {
114
+ if (hasBody(req.method) && checkType(req, type)) {
115
115
  req.body = await p((x) => {
116
116
  const boundary = getBoundary(req.headers['content-type']);
117
117
  if (boundary)
@@ -0,0 +1,24 @@
1
+ import type { IncomingMessage } from 'node:http';
2
+ /**
3
+ * Request extension with a body
4
+ */
5
+ export type ReqWithBody<T = any> = IncomingMessage & {
6
+ body?: T;
7
+ };
8
+ export type LimitErrorFn = (limit: number) => Error;
9
+ export type ParserOptions<T extends Record<string, any> = Record<string, any>> = Partial<{
10
+ /**
11
+ * Limit payload size (in bytes)
12
+ * @default 102400
13
+ */
14
+ payloadLimit: number;
15
+ /**
16
+ * Custom error function for payload limit
17
+ */
18
+ payloadLimitErrorFn: LimitErrorFn;
19
+ /**
20
+ * Middleware content type
21
+ */
22
+ type: (req: IncomingMessage) => boolean;
23
+ }> & T;
24
+ export type NextFunction = (err?: any) => void;
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ import type { IncomingMessage } from 'node:http';
2
+ import type { ParserOptions } from './types.js';
3
+ export declare const hasBody: (method: string) => boolean;
4
+ export declare const checkType: (req: IncomingMessage, type: ParserOptions["type"]) => boolean;
package/dist/utils.js ADDED
@@ -0,0 +1,2 @@
1
+ export const hasBody = (method) => ['POST', 'PUT', 'PATCH', 'DELETE'].includes(method);
2
+ export const checkType = (req, type) => typeof type === 'function' ? type(req) : true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "milliparsec",
3
- "version": "5.0.2",
3
+ "version": "5.1.0",
4
4
  "description": "tiniest body parser in the universe",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,10 +21,12 @@
21
21
  },
22
22
  "exports": "./dist/index.js",
23
23
  "devDependencies": {
24
- "@biomejs/biome": "1.9.3",
24
+ "@biomejs/biome": "2.2.2",
25
25
  "@tinyhttp/app": "^2.4.0",
26
- "@types/node": "^18.19.76",
26
+ "@types/express": "^5.0.3",
27
+ "@types/node": "^18",
27
28
  "c8": "10.1.2",
29
+ "express": "^5.1.0",
28
30
  "supertest-fetch": "^2.0.0",
29
31
  "tsx": "^4.19.1",
30
32
  "typescript": "^5.6.2"
@@ -32,14 +34,13 @@
32
34
  "files": [
33
35
  "dist"
34
36
  ],
35
- "publishConfig": {
36
- "provenance": true
37
- },
38
37
  "scripts": {
39
38
  "test": "tsx --test test.ts",
40
39
  "test:coverage": "c8 --include=src pnpm test",
41
40
  "test:report": "c8 report --reporter=text-lcov > coverage.lcov",
42
41
  "build": "tsc -p tsconfig.build.json",
42
+ "prepublishOnly": "pnpm build && pnpm test",
43
43
  "check": "biome check --write"
44
- }
45
- }
44
+ },
45
+ "packageManager": "pnpm@10.11.0"
46
+ }