diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f17596c..f1655a9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,12 +23,11 @@ jobs: steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v4 - - name: Enable corepack - run: corepack enable pnpm + - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: - node-version: 20 - cache: 'pnpm' + node-version: 18.13 + cache: "pnpm" - run: pnpm install - run: pnpm test:coverage - run: pnpm test:report diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 55c4adb..3fdd8a8 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -10,14 +10,12 @@ jobs: id-token: write steps: - uses: actions/checkout@v4 - - name: Enable corepack - run: corepack enable pnpm - + - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: - cache: 'pnpm' + cache: "pnpm" node-version: 20 - registry-url: 'https://registry.npmjs.org' + registry-url: "https://registry.npmjs.org" - run: pnpm install - run: pnpm build - name: Setup Biome @@ -29,4 +27,4 @@ jobs: run: biome ci . - run: pnpm publish --no-git-checks env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} \ No newline at end of file + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/README.md b/README.md index 128dfb0..42fa3cb 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,9 @@

-[![Version][v-badge-url]][npm-url] [![Coverage][cov-img]][cov-url] [![Github actions][gh-actions-img]][github-actions] [![Downloads][dl-badge-url]][npm-url] +[![Version][v-badge-url]][npm-url] [![Coverage][cov-img]][cov-url] +[![Github actions][gh-actions-img]][github-actions] +[![Downloads][dl-badge-url]][npm-url]
@@ -18,7 +20,7 @@ Check out [deno-libs/parsec](https://github.com/deno-libs/parsec) for Deno port. - 📦 tiny package size (8KB dist size) - 🔥 no dependencies - ✨ [tinyhttp](https://github.com/tinyhttp/tinyhttp) and Express support -- ⚡ 30% faster than body-parser +- ⚡ 40% faster than body-parser and 20x faster than formidable ## Install @@ -51,7 +53,8 @@ const server = createServer(async (req: ReqWithBody, res) => { ### What is "parsec"? -The parsec is a unit of length used to measure large distances to astronomical objects outside the Solar System. +The parsec is a unit of length used to measure large distances to astronomical +objects outside the Solar System. [v-badge-url]: https://img.shields.io/npm/v/milliparsec.svg?style=for-the-badge&color=25608B&logo=npm&label= [npm-url]: https://www.npmjs.com/package/milliparsec diff --git a/bench/index.md b/bench/index.md index 5d6b545..d747666 100644 --- a/bench/index.md +++ b/bench/index.md @@ -1,13 +1,16 @@ # Benchmark -Below are benchmarks of body-parser vs milliparsec and formidable vs milliparsec. Please take into account that these benchmarks are not entirely accurate, since they are taken on a regular desktop computer in usual conditions. +Below are benchmarks of body-parser vs milliparsec and formidable vs +milliparsec. Please take into account that these benchmarks are not entirely +accurate, since they are taken on a regular desktop computer in usual +conditions. ## Environment -- Node.js 22.3.0 -- System: Linux 6.10.10 -- CPU: Intel Core i9-13900H -- Machine: Asus ROG Zephyrus G16 +- Node.js 22.3.1 +- System: macOS Sequoia 15.3.1 / Darwin 24.3.0 arm64 kernel +- CPU: Apple M2 (8) @ 3.50 GHz +- Machine: MacBook Air (M2, 2022) ## JSON parsing @@ -22,40 +25,45 @@ autocannon -b '{"a":1}' -H "Content-Type=application/json" localhost:3002 # or 3 body-parser result: ``` -┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬────────┐ -│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │ -├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼────────┤ -│ Latency │ 0 ms │ 0 ms │ 0 ms │ 0 ms │ 0.01 ms │ 0.91 ms │ 272 ms │ -└─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴────────┘ -┌───────────┬─────────┬─────────┬─────────┬────────┬───────────┬──────────┬─────────┐ -│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │ -├───────────┼─────────┼─────────┼─────────┼────────┼───────────┼──────────┼─────────┤ -│ Req/Sec │ 30,767 │ 30,767 │ 41,343 │ 44,191 │ 39,307.64 │ 4,333.33 │ 30,762 │ -├───────────┼─────────┼─────────┼─────────┼────────┼───────────┼──────────┼─────────┤ -│ Bytes/Sec │ 3.97 MB │ 3.97 MB │ 5.33 MB │ 5.7 MB │ 5.07 MB │ 560 kB │ 3.97 MB │ -└───────────┴─────────┴─────────┴─────────┴────────┴───────────┴──────────┴─────────┘ +┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬───────┐ +│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │ +├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼───────┤ +│ Latency │ 0 ms │ 0 ms │ 0 ms │ 0 ms │ 0.01 ms │ 0.12 ms │ 22 ms │ +└─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴───────┘ +┌───────────┬─────────┬─────────┬─────────┬─────────┬──────────┬──────────┬─────────┐ +│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │ +├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼──────────┼─────────┤ +│ Req/Sec │ 54,591 │ 54,591 │ 61,759 │ 63,871 │ 61,436.8 │ 2,478.39 │ 54,589 │ +├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼──────────┼─────────┤ +│ Bytes/Sec │ 7.05 MB │ 7.05 MB │ 7.97 MB │ 8.24 MB │ 7.93 MB │ 319 kB │ 7.04 MB │ +└───────────┴─────────┴─────────┴─────────┴─────────┴──────────┴──────────┴─────────┘ Req/Bytes counts sampled once per second. -# of samples: 11 +# of samples: 10 -432k requests in 11.03s, 55.8 MB read +614k requests in 10.01s, 79.3 MB read ``` milliparsec result: ``` -┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬────────┐ -│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │ -├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼────────┤ -│ Latency │ 0 ms │ 0 ms │ 0 ms │ 0 ms │ 0.01 ms │ 0.68 ms │ 255 ms │ -└─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴────────┘ -┌───────────┬─────────┬─────────┬─────────┬─────────┬──────────┬──────────┬─────────┐ -│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │ -├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼──────────┼─────────┤ -│ Req/Sec │ 46,047 │ 46,047 │ 59,391 │ 64,255 │ 58,285.1 │ 4,625.15 │ 46,025 │ -├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼──────────┼─────────┤ -│ Bytes/Sec │ 5.62 MB │ 5.62 MB │ 7.25 MB │ 7.84 MB │ 7.11 MB │ 565 kB │ 5.62 MB │ -└───────────┴─────────┴─────────┴─────────┴─────────┴──────────┴──────────┴─────────┘ +┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬───────┐ +│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │ +├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼───────┤ +│ Latency │ 0 ms │ 0 ms │ 0 ms │ 0 ms │ 0.01 ms │ 0.04 ms │ 11 ms │ +└─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴───────┘ +┌───────────┬─────────┬─────────┬─────────┬─────────┬───────────┬──────────┬─────────┐ +│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │ +├───────────┼─────────┼─────────┼─────────┼─────────┼───────────┼──────────┼─────────┤ +│ Req/Sec │ 79,999 │ 79,999 │ 88,127 │ 88,767 │ 87,095.28 │ 2,370.01 │ 79,966 │ +├───────────┼─────────┼─────────┼─────────┼─────────┼───────────┼──────────┼─────────┤ +│ Bytes/Sec │ 9.76 MB │ 9.76 MB │ 10.7 MB │ 10.8 MB │ 10.6 MB │ 289 kB │ 9.76 MB │ +└───────────┴─────────┴─────────┴─────────┴─────────┴───────────┴──────────┴─────────┘ + +Req/Bytes counts sampled once per second. +# of samples: 11 + +958k requests in 11.01s, 117 MB read Req/Bytes counts sampled once per second. # of samples: 11 @@ -65,14 +73,14 @@ Req/Bytes counts sampled once per second. ### Verdict -milliparsec, on average, is ~30-40% faster. +milliparsec, on average, is ~40% faster. ## Multipart with files ### Benchmark command: ```sh -autocannon -m POST --form '{ "file": { "type": "file", "path": "./file.txt" } }' localhost:3004 +autocannon -m POST --form '{ "file": { "type": "file", "path": "./file.txt" } }' localhost:3004 ``` ### Results @@ -80,47 +88,47 @@ autocannon -m POST --form '{ "file": { "type": "file", "path": "./file.txt" } formidable result: ``` -┌─────────┬──────┬───────┬───────┬───────┬─────────┬─────────┬────────┐ -│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │ -├─────────┼──────┼───────┼───────┼───────┼─────────┼─────────┼────────┤ -│ Latency │ 1 ms │ 10 ms │ 29 ms │ 33 ms │ 11.1 ms │ 9.48 ms │ 261 ms │ -└─────────┴──────┴───────┴───────┴───────┴─────────┴─────────┴────────┘ -┌───────────┬───────┬───────┬────────┬────────┬────────┬────────┬───────┐ -│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │ -├───────────┼───────┼───────┼────────┼────────┼────────┼────────┼───────┤ -│ Req/Sec │ 500 │ 500 │ 630 │ 2,339 │ 860.9 │ 526.44 │ 500 │ -├───────────┼───────┼───────┼────────┼────────┼────────┼────────┼───────┤ -│ Bytes/Sec │ 99 kB │ 99 kB │ 125 kB │ 463 kB │ 170 kB │ 104 kB │ 99 kB │ -└───────────┴───────┴───────┴────────┴────────┴────────┴────────┴───────┘ +┌─────────┬──────┬──────┬───────┬───────┬─────────┬─────────┬───────┐ +│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │ +├─────────┼──────┼──────┼───────┼───────┼─────────┼─────────┼───────┤ +│ Latency │ 1 ms │ 5 ms │ 19 ms │ 26 ms │ 6.63 ms │ 5.86 ms │ 54 ms │ +└─────────┴──────┴──────┴───────┴───────┴─────────┴─────────┴───────┘ +┌───────────┬────────┬────────┬────────┬────────┬────────┬──────────┬────────┐ +│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │ +├───────────┼────────┼────────┼────────┼────────┼────────┼──────────┼────────┤ +│ Req/Sec │ 530 │ 530 │ 775 │ 4,595 │ 1,404 │ 1,179.32 │ 530 │ +├───────────┼────────┼────────┼────────┼────────┼────────┼──────────┼────────┤ +│ Bytes/Sec │ 105 kB │ 105 kB │ 153 kB │ 910 kB │ 278 kB │ 233 kB │ 105 kB │ +└───────────┴────────┴────────┴────────┴────────┴────────┴──────────┴────────┘ Req/Bytes counts sampled once per second. # of samples: 10 -9k requests in 10.03s, 1.7 MB read +14k requests in 10.02s, 2.78 MB read ``` milliparsec result: ``` -┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬────────┐ -│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │ -├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼────────┤ -│ Latency │ 0 ms │ 0 ms │ 1 ms │ 1 ms │ 0.09 ms │ 1.39 ms │ 267 ms │ -└─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴────────┘ +┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬───────┐ +│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │ +├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼───────┤ +│ Latency │ 0 ms │ 0 ms │ 0 ms │ 0 ms │ 0.02 ms │ 0.19 ms │ 20 ms │ +└─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴───────┘ ┌───────────┬─────────┬─────────┬─────────┬─────────┬───────────┬──────────┬─────────┐ │ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │ ├───────────┼─────────┼─────────┼─────────┼─────────┼───────────┼──────────┼─────────┤ -│ Req/Sec │ 8,543 │ 8,543 │ 17,775 │ 18,399 │ 16,962.55 │ 2,697.57 │ 8,537 │ +│ Req/Sec │ 24,063 │ 24,063 │ 29,727 │ 30,863 │ 29,263.28 │ 1,758.94 │ 24,051 │ ├───────────┼─────────┼─────────┼─────────┼─────────┼───────────┼──────────┼─────────┤ -│ Bytes/Sec │ 1.69 MB │ 1.69 MB │ 3.52 MB │ 3.64 MB │ 3.36 MB │ 534 kB │ 1.69 MB │ +│ Bytes/Sec │ 4.76 MB │ 4.76 MB │ 5.89 MB │ 6.11 MB │ 5.79 MB │ 348 kB │ 4.76 MB │ └───────────┴─────────┴─────────┴─────────┴─────────┴───────────┴──────────┴─────────┘ Req/Bytes counts sampled once per second. # of samples: 11 -187k requests in 11.03s, 36.9 MB read +322k requests in 11.01s, 63.7 MB read ``` ### Verdict -milliparsec, on average, is 10-20x faster. \ No newline at end of file +milliparsec, on average, is ~20x faster. diff --git a/bench/package.json b/bench/package.json index 654771c..a37a9f1 100644 --- a/bench/package.json +++ b/bench/package.json @@ -14,10 +14,10 @@ "devDependencies": { "@types/body-parser": "^1.19.5", "@types/formidable": "^3.4.5", - "autocannon": "^7.15.0", - "body-parser": "^1.20.2" + "autocannon": "^8.0.0", + "body-parser": "^1.20.3" }, "dependencies": { - "formidable": "^3.5.1" + "formidable": "^3.5.2" } } diff --git a/bench/pnpm-lock.yaml b/bench/pnpm-lock.yaml index 548235e..00b308e 100644 --- a/bench/pnpm-lock.yaml +++ b/bench/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: formidable: - specifier: ^3.5.1 - version: 3.5.1 + specifier: ^3.5.2 + version: 3.5.2 devDependencies: '@types/body-parser': specifier: ^1.19.5 @@ -19,11 +19,11 @@ importers: specifier: ^3.4.5 version: 3.4.5 autocannon: - specifier: ^7.15.0 - version: 7.15.0 + specifier: ^8.0.0 + version: 8.0.0 body-parser: - specifier: ^1.20.2 - version: 1.20.2 + specifier: ^1.20.3 + version: 1.20.3 packages: @@ -34,6 +34,9 @@ packages: resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} + '@minimistjs/subarg@1.0.0': + resolution: {integrity: sha512-Q/ONBiM2zNeYUy0mVSO44mWWKYM3UHuEK43PKIOzJCbvUnPoMH1K+gk3cf1kgnCVJFlWmddahQQCmrmBGlk9jQ==} + '@types/body-parser@1.19.5': resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} @@ -60,15 +63,15 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - autocannon@7.15.0: - resolution: {integrity: sha512-NaP2rQyA+tcubOJMFv2+oeW9jv2pq/t+LM6BL3cfJic0HEfscEcnWgAyU5YovE/oTHUzAgTliGdLPR+RQAWUbg==} + autocannon@8.0.0: + resolution: {integrity: sha512-fMMcWc2JPFcUaqHeR6+PbmEpTxCrPZyBUM95oG4w3ngJ8NfBNas/ZXA+pTHXLqJ0UlFVTcy05GC25WxKx/M20A==} hasBin: true base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - body-parser@1.20.2: - resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} + body-parser@1.20.3: + resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} buffer@5.7.1: @@ -160,8 +163,8 @@ packages: resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} engines: {node: '>= 6'} - formidable@3.5.1: - resolution: {integrity: sha512-WJWKelbRHN41m5dumb0/k8TeAx7Id/y3a+Z7QfhxP/htI9Js5zYaEDtG8uMgG0vM0lOlqnmjE99/kfpOYi/0Og==} + formidable@3.5.2: + resolution: {integrity: sha512-Jqc1btCy3QzRbJaICGwKcBfGWuLADRerLzDqi2NwSt/UkXLsHJw2TVResiaoBufHVHy9aSgClOHCeJsSsFLTbg==} function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} @@ -202,8 +205,8 @@ packages: hdr-histogram-percentiles-obj@3.0.0: resolution: {integrity: sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==} - hexoid@1.0.0: - resolution: {integrity: sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==} + hexoid@2.0.0: + resolution: {integrity: sha512-qlspKUK7IlSQv2o+5I7yhUd7TxlOG2Vr5LTa3ve2XSNVKAL/n/u/7KLvKmFNimomDIKvZFXWHv0T12mv7rT8Aw==} engines: {node: '>=8'} http-errors@2.0.0: @@ -286,8 +289,8 @@ packages: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} - qs@6.11.0: - resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} + qs@6.13.0: + resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} engines: {node: '>=0.6'} raw-body@2.5.2: @@ -331,9 +334,6 @@ packages: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} - subarg@1.0.0: - resolution: {integrity: sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg==} - supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -374,6 +374,10 @@ snapshots: '@colors/colors@1.5.0': optional: true + '@minimistjs/subarg@1.0.0': + dependencies: + minimist: 1.2.8 + '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.38 @@ -401,8 +405,9 @@ snapshots: asynckit@0.4.0: {} - autocannon@7.15.0: + autocannon@8.0.0: dependencies: + '@minimistjs/subarg': 1.0.0 chalk: 4.1.2 char-spinner: 1.0.1 cli-table3: 0.6.5 @@ -424,12 +429,11 @@ snapshots: reinterval: 1.1.0 retimer: 3.0.0 semver: 7.6.2 - subarg: 1.0.0 timestring: 6.0.0 base64-js@1.5.1: {} - body-parser@1.20.2: + body-parser@1.20.3: dependencies: bytes: 3.1.2 content-type: 1.0.5 @@ -439,7 +443,7 @@ snapshots: http-errors: 2.0.0 iconv-lite: 0.4.24 on-finished: 2.4.1 - qs: 6.11.0 + qs: 6.13.0 raw-body: 2.5.2 type-is: 1.6.18 unpipe: 1.0.0 @@ -527,10 +531,10 @@ snapshots: combined-stream: 1.0.8 mime-types: 2.1.35 - formidable@3.5.1: + formidable@3.5.2: dependencies: dezalgo: 1.0.4 - hexoid: 1.0.0 + hexoid: 2.0.0 once: 1.4.0 function-bind@1.1.2: {} @@ -571,7 +575,7 @@ snapshots: hdr-histogram-percentiles-obj@3.0.0: {} - hexoid@1.0.0: {} + hexoid@2.0.0: {} http-errors@2.0.0: dependencies: @@ -637,7 +641,7 @@ snapshots: progress@2.0.3: {} - qs@6.11.0: + qs@6.13.0: dependencies: side-channel: 1.0.6 @@ -686,10 +690,6 @@ snapshots: dependencies: ansi-regex: 5.0.1 - subarg@1.0.0: - dependencies: - minimist: 1.2.8 - supports-color@7.2.0: dependencies: has-flag: 4.0.0 diff --git a/package.json b/package.json index 9362ebb..bdf603c 100644 --- a/package.json +++ b/package.json @@ -17,13 +17,13 @@ "body-parsing" ], "engines": { - "node": ">=20" + "node": ">=18.13 || >=19.20 || >=20" }, "exports": "./dist/index.js", "devDependencies": { "@biomejs/biome": "1.9.3", "@tinyhttp/app": "^2.4.0", - "@types/node": "^22.7.4", + "@types/node": "^18.19.76", "c8": "10.1.2", "supertest-fetch": "^2.0.0", "tsx": "^4.19.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fcfa059..d35bcc5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,8 +15,8 @@ importers: specifier: ^2.4.0 version: 2.4.0 '@types/node': - specifier: ^22.7.4 - version: 22.7.4 + specifier: ^18.19.76 + version: 18.19.76 c8: specifier: 10.1.2 version: 10.1.2 @@ -325,8 +325,8 @@ packages: '@types/istanbul-lib-coverage@2.0.6': resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} - '@types/node@22.7.4': - resolution: {integrity: sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==} + '@types/node@18.19.76': + resolution: {integrity: sha512-yvR7Q9LdPz2vGpmpJX5LolrgRdWvB67MJKDPSgIIzpFbaf9a1j/f5DnLp5VDyHGMR0QZHlTr1afsD87QCXFHKw==} ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} @@ -578,8 +578,8 @@ packages: engines: {node: '>=14.17'} hasBin: true - undici-types@6.19.8: - resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} v8-to-istanbul@9.3.0: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} @@ -820,9 +820,9 @@ snapshots: '@types/istanbul-lib-coverage@2.0.6': {} - '@types/node@22.7.4': + '@types/node@18.19.76': dependencies: - undici-types: 6.19.8 + undici-types: 5.26.5 ansi-regex@5.0.1: {} @@ -1066,7 +1066,7 @@ snapshots: typescript@5.6.2: {} - undici-types@6.19.8: {} + undici-types@5.26.5: {} v8-to-istanbul@9.3.0: dependencies: diff --git a/src/index.ts b/src/index.ts index f633e7e..5dd51e4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -import { Buffer } from 'node:buffer' +import { Buffer, File } from 'node:buffer' import type { IncomingMessage, ServerResponse as Response } from 'node:http' type NextFunction = (err?: any) => void diff --git a/test.ts b/test.ts index ac4d401..179314a 100644 --- a/test.ts +++ b/test.ts @@ -1,5 +1,6 @@ import assert from 'node:assert/strict' import { Buffer } from 'node:buffer' +import { File } from 'node:buffer' import { createServer } from 'node:http' import { describe, it } from 'node:test' import { App } from '@tinyhttp/app' @@ -353,7 +354,7 @@ describe('Multipart', () => { it('should parse multipart with files', async () => { const fd = new FormData() const file = new File(['hello world'], 'hello.txt', { type: 'text/plain' }) - fd.set('file', file) + fd.set('file', file as Blob) const server = createServer(async (req: ReqWithBody<{ file: [File] }>, res) => { await multipart()(req, res, (err) => err && console.log(err)) @@ -380,8 +381,8 @@ describe('Multipart', () => { new File(['bye world'], 'bye.txt', { type: 'text/plain' }) ] - fd.set('file1', files[0]) - fd.set('file2', files[1]) + fd.set('file1', files[0] as Blob) + fd.set('file2', files[1] as Blob) const server = createServer(async (req: ReqWithBody<{ file1: [File]; file2: [File] }>, res) => { await multipart()(req, res, (err) => err && console.log(err)) @@ -405,7 +406,7 @@ describe('Multipart', () => { it('should support binary files', async () => { const fd = new FormData() const file = new File([new Uint8Array([1, 2, 3])], 'blob.bin', { type: 'application/octet-stream' }) - fd.set('file', file) + fd.set('file', file as Blob) const server = createServer(async (req: ReqWithBody<{ file: [File] }>, res) => { await multipart()(req, res, (err) => err && console.log(err)) @@ -495,8 +496,8 @@ describe('Limits', () => { const fd = new FormData() - fd.set('file1', new File(['hello world'], 'hello.txt', { type: 'text/plain' })) - fd.set('file2', new File(['bye world'], 'bye.txt', { type: 'text/plain' })) + fd.set('file1', new File(['hello world'], 'hello.txt', { type: 'text/plain' }) as Blob) + fd.set('file2', new File(['bye world'], 'bye.txt', { type: 'text/plain' }) as Blob) await makeFetch(server)('/', { body: fd, @@ -514,7 +515,7 @@ describe('Limits', () => { const fd = new FormData() - fd.set('file', new File(['hello world'], 'hello.txt', { type: 'text/plain' })) + fd.set('file', new File(['hello world'], 'hello.txt', { type: 'text/plain' }) as Blob) await makeFetch(server)('/', { body: fd, @@ -534,7 +535,7 @@ describe('Limits', () => { const fd = new FormData() - fd.set('file', new File(['hello world to everyone'], 'hello.txt', { type: 'text/plain' })) + fd.set('file', new File(['hello world to everyone'], 'hello.txt', { type: 'text/plain' }) as Blob) await makeFetch(server)('/', { body: fd,