milliparsec 3.0.0 → 4.0.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/README.md CHANGED
@@ -17,7 +17,7 @@ Check out [deno-libs/parsec](https://github.com/deno-libs/parsec) for Deno port.
17
17
 
18
18
  - ⏩ built with `async` / `await`
19
19
  - 🛠 JSON / raw / urlencoded data support
20
- - 📦 tiny package size (675B)
20
+ - 📦 tiny package size (8KB dist size)
21
21
  - 🔥 no dependencies
22
22
  - ✨ [tinyhttp](https://github.com/tinyhttp/tinyhttp) and Express support
23
23
  - ⚡ 30% faster than body-parser
@@ -28,11 +28,8 @@ Check out [deno-libs/parsec](https://github.com/deno-libs/parsec) for Deno port.
28
28
  # pnpm
29
29
  pnpm i milliparsec
30
30
 
31
- # yarn
32
- yarn add milliparsec
33
-
34
- # npm
35
- npm i milliparsec
31
+ # bun
32
+ bun i milliparsec
36
33
  ```
37
34
 
38
35
  ## Usage
@@ -42,7 +39,7 @@ npm i milliparsec
42
39
  Use a middleware inside a server:
43
40
 
44
41
  ```js
45
- import { createServer } from 'http'
42
+ import { createServer } from 'node:http'
46
43
  import { json } from 'milliparsec'
47
44
 
48
45
  const server = createServer(async (req: ReqWithBody, res) => {
@@ -86,12 +83,22 @@ Parses request body using `new URLSearchParams`.
86
83
 
87
84
  Parses request body using `JSON.parse`.
88
85
 
86
+ ### `multipart(req, res, cb)`
87
+
88
+ Parses request body using `multipart/form-data` content type and boundary. Supports files as well.
89
+
90
+ ```js
91
+ // curl -F "textfield=textfield" -F "someother=textfield with text" localhost:3000
92
+ await multipart()(req, res, (err) => void err && console.log(err))
93
+ res.end(req.body) // { textfield: "textfield", someother: "textfield with text" }
94
+ ```
95
+
89
96
  ### `custom(fn)(req, res, cb)`
90
97
 
91
98
  Custom function for `parsec`.
92
99
 
93
100
  ```js
94
- // curl -d "this text must be uppercased" localhost
101
+ // curl -d "this text must be uppercased" localhost:3000
95
102
  await custom(
96
103
  req,
97
104
  (d) => d.toUpperCase(),
package/dist/index.d.ts CHANGED
@@ -11,4 +11,5 @@ declare const json: () => (req: ReqWithBody, res: Response, next: NextFunction)
11
11
  declare const raw: () => (req: ReqWithBody, _res: Response, next: NextFunction) => Promise<void>;
12
12
  declare const text: () => (req: ReqWithBody, _res: Response, next: NextFunction) => Promise<void>;
13
13
  declare const urlencoded: () => (req: ReqWithBody, res: Response, next: NextFunction) => Promise<void>;
14
- export { custom, json, raw, text, urlencoded };
14
+ declare const multipart: () => (req: ReqWithBody, res: Response, next: NextFunction) => Promise<void>;
15
+ export { custom, json, raw, text, urlencoded, multipart };
package/dist/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  export const hasBody = (method) => ['POST', 'PUT', 'PATCH', 'DELETE'].includes(method);
2
- // Main function
3
2
  export const p = (fn) => async (req, _res, next) => {
4
3
  try {
5
4
  let body = '';
@@ -11,9 +10,8 @@ export const p = (fn) => async (req, _res, next) => {
11
10
  next(e);
12
11
  }
13
12
  };
14
- // JSON, raw, FormData
15
13
  const custom = (fn) => async (req, _res, next) => {
16
- req.body = await p(fn)(req, undefined, next);
14
+ req.body = await p(fn)(req, _res, next);
17
15
  next();
18
16
  };
19
17
  const json = () => async (req, res, next) => {
@@ -51,4 +49,39 @@ const urlencoded = () => async (req, res, next) => {
51
49
  else
52
50
  next();
53
51
  };
54
- export { custom, json, raw, text, urlencoded };
52
+ const getBoundary = (contentType) => {
53
+ const match = /boundary=(.+);?/.exec(contentType);
54
+ return match ? `--${match[1]}` : null;
55
+ };
56
+ const parseMultipart = (body, boundary) => {
57
+ const parts = body.split(new RegExp(`${boundary}(--)?`)).filter((part) => !!part && /content-disposition/i.test(part));
58
+ const parsedBody = {};
59
+ parts.map((part) => {
60
+ const [headers, ...lines] = part.split('\r\n').filter((part) => !!part);
61
+ const data = lines.join('\r\n').trim();
62
+ const name = /name="(.+?)"/.exec(headers)[1];
63
+ const filename = /filename="(.+?)"/.exec(headers);
64
+ if (filename) {
65
+ const contentTypeMatch = /Content-Type: (.+)/i.exec(data);
66
+ const fileContent = data.slice(contentTypeMatch[0].length + 2);
67
+ return Object.assign(parsedBody, {
68
+ [name]: new File([fileContent], filename[1], { type: contentTypeMatch[1] })
69
+ });
70
+ }
71
+ return Object.assign(parsedBody, { [name]: data });
72
+ });
73
+ return parsedBody;
74
+ };
75
+ const multipart = () => async (req, res, next) => {
76
+ if (hasBody(req.method)) {
77
+ req.body = await p((x) => {
78
+ const boundary = getBoundary(req.headers['content-type']);
79
+ if (boundary)
80
+ return parseMultipart(x, boundary);
81
+ })(req, res, next);
82
+ next();
83
+ }
84
+ else
85
+ next();
86
+ };
87
+ export { custom, json, raw, text, urlencoded, multipart };
package/package.json CHANGED
@@ -1,9 +1,12 @@
1
1
  {
2
2
  "name": "milliparsec",
3
- "version": "3.0.0",
3
+ "version": "4.0.0",
4
4
  "description": "tiniest body parser in the universe",
5
- "repository": "https://github.com/talentlessguy/parsec.git",
6
- "author": "talentlessguy <pilll.PL22@gmail.com>",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/tinyhttp/milliparsec"
8
+ },
9
+ "author": "talentlessguy <hi@v1rtl.site>",
7
10
  "license": "MIT",
8
11
  "types": "./dist/index.d.ts",
9
12
  "type": "module",
@@ -14,12 +17,11 @@
14
17
  "body-parsing"
15
18
  ],
16
19
  "engines": {
17
- "node": ">=12.20"
20
+ "node": ">=20"
18
21
  },
19
22
  "exports": "./dist/index.js",
20
23
  "devDependencies": {
21
24
  "@biomejs/biome": "1.8.3",
22
- "@tinyhttp/app": "^2.2.4",
23
25
  "@types/node": "^20.14.9",
24
26
  "c8": "10.1.2",
25
27
  "supertest-fetch": "^2.0.0",
@@ -30,6 +32,9 @@
30
32
  "files": [
31
33
  "dist"
32
34
  ],
35
+ "publishConfig": {
36
+ "provenance": true
37
+ },
33
38
  "scripts": {
34
39
  "test": "uvu -r tsm",
35
40
  "test:coverage": "c8 --include=src pnpm test",