├── .editorconfig ├── .gitattributes ├── .github ├── dependabot.yml ├── stale.yml └── workflows │ └── ci.yml ├── .gitignore ├── .npmrc ├── LICENSE ├── Readme.md ├── eslint.config.js ├── formbody.js ├── package.json ├── test └── integration.test.js └── types ├── formbody.d.ts └── formbody.test-d.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | insert_final_newline = true 8 | indent_style = space 9 | indent_size = 2 10 | trim_trailing_whitespace = true 11 | 12 | # [*.md] 13 | # trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behavior to automatically convert line endings 2 | * text=auto eol=lf 3 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "monthly" 7 | open-pull-requests-limit: 10 8 | 9 | - package-ecosystem: "npm" 10 | directory: "/" 11 | schedule: 12 | interval: "monthly" 13 | open-pull-requests-limit: 10 14 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 15 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - "discussion" 8 | - "feature request" 9 | - "bug" 10 | - "help wanted" 11 | - "plugin suggestion" 12 | - "good first issue" 13 | # Label to use when marking an issue as stale 14 | staleLabel: stale 15 | # Comment to post when marking an issue as stale. Set to `false` to disable 16 | markComment: > 17 | This issue has been automatically marked as stale because it has not had 18 | recent activity. It will be closed if no further activity occurs. Thank you 19 | for your contributions. 20 | # Comment to post when closing a stale issue. Set to `false` to disable 21 | closeComment: false 22 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - next 8 | - 'v*' 9 | paths-ignore: 10 | - 'docs/**' 11 | - '*.md' 12 | pull_request: 13 | paths-ignore: 14 | - 'docs/**' 15 | - '*.md' 16 | 17 | permissions: 18 | contents: read 19 | 20 | jobs: 21 | test: 22 | permissions: 23 | contents: write 24 | pull-requests: write 25 | uses: fastify/workflows/.github/workflows/plugins-ci.yml@v5 26 | with: 27 | license-check: true 28 | lint: true 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # Docusaurus cache and generated files 108 | .docusaurus 109 | 110 | # Serverless directories 111 | .serverless/ 112 | 113 | # FuseBox cache 114 | .fusebox/ 115 | 116 | # DynamoDB Local files 117 | .dynamodb/ 118 | 119 | # TernJS port file 120 | .tern-port 121 | 122 | # Stores VSCode versions used for testing VSCode extensions 123 | .vscode-test 124 | 125 | # yarn v2 126 | .yarn/cache 127 | .yarn/unplugged 128 | .yarn/build-state.yml 129 | .yarn/install-state.gz 130 | .pnp.* 131 | 132 | # Vim swap files 133 | *.swp 134 | 135 | # macOS files 136 | .DS_Store 137 | 138 | # Clinic 139 | .clinic 140 | 141 | # lock files 142 | bun.lockb 143 | package-lock.json 144 | pnpm-lock.yaml 145 | yarn.lock 146 | 147 | # editor files 148 | .vscode 149 | .idea 150 | 151 | #tap files 152 | .tap/ 153 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Fastify 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # @fastify/formbody 2 | 3 | [![CI](https://github.com/fastify/fastify-formbody/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/fastify/fastify-formbody/actions/workflows/ci.yml) 4 | [![NPM version](https://img.shields.io/npm/v/@fastify/formbody.svg?style=flat)](https://www.npmjs.com/package/@fastify/formbody) 5 | [![NPM downloads](https://img.shields.io/npm/dm/fastify-formbody.svg?style=flat)](https://www.npmjs.com/package/@fastify/formbody) 6 | [![neostandard javascript style](https://img.shields.io/badge/code_style-neostandard-brightgreen?style=flat)](https://github.com/neostandard/neostandard) 7 | 8 | A simple plugin for [Fastify][fastify] that adds a content type parser for 9 | the content type `application/x-www-form-urlencoded`. 10 | 11 | [fastify]: https://fastify.dev/ 12 | 13 | ## Install 14 | 15 | ``` 16 | npm i @fastify/formbody 17 | ``` 18 | 19 | 20 | ### Compatibility 21 | | Plugin version | Fastify version | 22 | | ---------------|-----------------| 23 | | `^8.x` | `^5.x` | 24 | | `^7.x` | `^4.x` | 25 | | `^6.x` | `^3.x` | 26 | | `^3.x` | `^2.x` | 27 | | `^2.x` | `^1.x` | 28 | 29 | 30 | Please note that if a Fastify version is out of support, then so are the corresponding versions of this plugin 31 | in the table above. 32 | See [Fastify's LTS policy](https://github.com/fastify/fastify/blob/main/docs/Reference/LTS.md) for more details. 33 | 34 | ## Example 35 | 36 | Given the following code: 37 | 38 | ```js 39 | const fastify = require('fastify')() 40 | 41 | fastify.register(require('@fastify/formbody')) 42 | 43 | fastify.post('/', (req, reply) => { 44 | reply.send(req.body) 45 | }) 46 | 47 | fastify.listen({ port: 8000 }, (err) => { 48 | if (err) throw err 49 | }) 50 | ``` 51 | 52 | And a `POST` body of: 53 | 54 | ```html 55 | foo=foo&bar=bar&answer=42 56 | ``` 57 | 58 | The sent reply would be the object: 59 | 60 | ```js 61 | { 62 | foo: 'foo', 63 | bar: 'bar', 64 | answer: 42 65 | } 66 | ``` 67 | 68 | ## Options 69 | 70 | The plugin accepts an options object with the following properties: 71 | 72 | + `bodyLimit`: The maximum amount of bytes to process 73 | before returning an error. If the limit is exceeded, a `500` error will be 74 | returned immediately. When set to `undefined` the limit will be set to whatever 75 | is configured on the parent Fastify instance. The default value is 76 | whatever is configured in 77 | [fastify](https://github.com/fastify/fastify/blob/main/docs/Reference/Server.md#bodylimit) 78 | (`1048576` by default). 79 | + `parser`: The default parser used is the querystring.parse built-in. You can change this default by passing a parser function e.g. `fastify.register(require('@fastify/formbody'), { parser: str => myParser(str) })` 80 | 81 | ## Upgrading from 4.x 82 | 83 | Previously, the external [qs lib](https://github.com/ljharb/qs) was used that did things like parse nested objects. For example: 84 | 85 | - ***Input:*** `foo[one]=foo&foo[two]=bar` 86 | - ***Parsed:*** `{ foo: { one: 'foo', two: 'bar' } }` 87 | 88 | The way this is handled now using the built-in querystring.parse: 89 | 90 | - ***Input:*** `foo[one]=foo&foo[two]=bar` 91 | - ***Parsed:*** `{ 'foo[one]': 'foo', 'foo[two]': 'bar' }` 92 | 93 | If you need nested parsing, you must configure it manually by installing the qs lib (`npm i qs`), and then configure an optional parser: 94 | 95 | ```js 96 | const fastify = require('fastify')() 97 | const qs = require('qs') 98 | fastify.register(require('@fastify/formbody'), { parser: str => qs.parse(str) }) 99 | ``` 100 | 101 | ## License 102 | 103 | Licensed under [MIT](./LICENSE). 104 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = require('neostandard')({ 4 | ignores: require('neostandard').resolveIgnoresFromGitignore(), 5 | ts: true 6 | }) 7 | -------------------------------------------------------------------------------- /formbody.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const fp = require('fastify-plugin') 4 | const { parse: defaultParser } = require('fast-querystring') 5 | 6 | function fastifyFormbody (fastify, options, next) { 7 | const opts = Object.assign({ parser: defaultParser }, options) 8 | if (typeof opts.parser !== 'function') { 9 | next(new Error('parser must be a function')) 10 | return 11 | } 12 | 13 | function contentParser (_req, body, done) { 14 | done(null, opts.parser(body.toString())) 15 | } 16 | 17 | fastify.addContentTypeParser( 18 | 'application/x-www-form-urlencoded', 19 | { parseAs: 'buffer', bodyLimit: opts.bodyLimit }, 20 | contentParser 21 | ) 22 | next() 23 | } 24 | 25 | module.exports = fp(fastifyFormbody, { 26 | fastify: '5.x', 27 | name: '@fastify/formbody' 28 | }) 29 | module.exports.default = fastifyFormbody 30 | module.exports.fastifyFormbody = fastifyFormbody 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@fastify/formbody", 3 | "version": "8.0.2", 4 | "description": "A module for Fastify to parse x-www-form-urlencoded bodies", 5 | "main": "formbody.js", 6 | "type": "commonjs", 7 | "scripts": { 8 | "codecov": "codecov", 9 | "lint": "eslint", 10 | "lint:fix": "eslint --fix", 11 | "test": "npm run test:unit && npm run test:typescript", 12 | "test:unit": "c8 --100 node --test", 13 | "test:typescript": "tsd" 14 | }, 15 | "precommit": [ 16 | "lint", 17 | "test" 18 | ], 19 | "repository": { 20 | "type": "git", 21 | "url": "git+ssh://git@github.com/fastify/fastify-formbody.git" 22 | }, 23 | "keywords": [ 24 | "fastify", 25 | "x-www-form-urlencoded" 26 | ], 27 | "author": "James Sumners ", 28 | "contributors": [ 29 | { 30 | "name": "Matteo Collina", 31 | "email": "hello@matteocollina.com" 32 | }, 33 | { 34 | "name": "Manuel Spigolon", 35 | "email": "behemoth89@gmail.com" 36 | }, 37 | { 38 | "name": "Aras Abbasi", 39 | "email": "aras.abbasi@gmail.com" 40 | }, 41 | { 42 | "name": "Frazer Smith", 43 | "email": "frazer.dev@icloud.com", 44 | "url": "https://github.com/fdawgs" 45 | } 46 | ], 47 | "license": "MIT", 48 | "bugs": { 49 | "url": "https://github.com/fastify/fastify-formbody/issues" 50 | }, 51 | "homepage": "https://github.com/fastify/fastify-formbody#readme", 52 | "funding": [ 53 | { 54 | "type": "github", 55 | "url": "https://github.com/sponsors/fastify" 56 | }, 57 | { 58 | "type": "opencollective", 59 | "url": "https://opencollective.com/fastify" 60 | } 61 | ], 62 | "devDependencies": { 63 | "@fastify/pre-commit": "^2.1.0", 64 | "@types/node": "^22.0.0", 65 | "c8": "^10.1.2", 66 | "eslint": "^9.17.0", 67 | "fastify": "^5.0.0", 68 | "form-auto-content": "^3.2.1", 69 | "neostandard": "^0.12.0", 70 | "qs": "^6.12.0", 71 | "tsd": "^0.32.0" 72 | }, 73 | "dependencies": { 74 | "fast-querystring": "^1.1.2", 75 | "fastify-plugin": "^5.0.0" 76 | }, 77 | "types": "types/formbody.d.ts", 78 | "publishConfig": { 79 | "access": "public" 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /test/integration.test.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const test = require('node:test') 4 | const Fastify = require('fastify') 5 | const plugin = require('../') 6 | const qs = require('qs') 7 | const formAutoContent = require('form-auto-content') 8 | 9 | test('success route succeeds', async (t) => { 10 | const fastify = Fastify() 11 | 12 | await fastify.register(plugin) 13 | fastify.post('/test1', (req, res) => { 14 | res.send(Object.assign({}, req.body, { message: 'done' })) 15 | }) 16 | 17 | await fastify.listen({ port: 0 }) 18 | fastify.server.unref() 19 | 20 | const response = await fastify.inject({ 21 | path: '/test1', 22 | method: 'POST', 23 | ...formAutoContent({ foo: 'foo' }) 24 | }) 25 | t.assert.ifError(response.error) 26 | t.assert.strictEqual(response.statusCode, 200) 27 | t.assert.deepStrictEqual(JSON.parse(response.body), { foo: 'foo', message: 'done' }) 28 | }) 29 | 30 | test('cannot exceed body limit', async (t) => { 31 | const fastify = Fastify() 32 | 33 | await fastify.register(plugin, { bodyLimit: 10 }) 34 | fastify.post('/limited', (req, res) => { 35 | res.send(Object.assign({}, req.body, { message: 'done' })) 36 | }) 37 | 38 | await fastify.listen({ port: 0 }) 39 | fastify.server.unref() 40 | 41 | const payload = require('node:crypto').randomBytes(128).toString('hex') 42 | const response = await fastify.inject({ 43 | path: '/limited', 44 | method: 'POST', 45 | ...formAutoContent({ foo: payload }) 46 | }) 47 | t.assert.ifError(response.error) 48 | t.assert.strictEqual(response.statusCode, 413) 49 | t.assert.strictEqual(JSON.parse(response.body).message, 'Request body is too large') 50 | }) 51 | 52 | test('cannot exceed body limit when Content-Length is not available', async (t) => { 53 | const fastify = Fastify() 54 | 55 | fastify.addHook('onSend', (_request, reply, _payload, next) => { 56 | reply.send = function mockSend () { 57 | t.assert.fail('reply.send() was called multiple times') 58 | } 59 | setTimeout(next, 1) 60 | }) 61 | 62 | await fastify.register(plugin, { bodyLimit: 10 }) 63 | fastify.post('/limited', (req, res) => { 64 | res.send(Object.assign({}, req.body, { message: 'done' })) 65 | }) 66 | 67 | await fastify.listen({ port: 0 }) 68 | fastify.server.unref() 69 | 70 | let sent = false 71 | const payload = require('node:stream').Readable({ 72 | read: function () { 73 | this.push(sent ? null : Buffer.alloc(70000, 'a')) 74 | sent = true 75 | } 76 | }) 77 | 78 | const response = await fastify.inject({ 79 | path: '/limited', 80 | method: 'POST', 81 | headers: { 'content-type': 'application/x-www-form-urlencoded' }, 82 | body: payload 83 | }) 84 | t.assert.ifError(response.error) 85 | t.assert.strictEqual(response.statusCode, 413) 86 | t.assert.strictEqual(JSON.parse(response.body).message, 'Request body is too large') 87 | }) 88 | 89 | test('cannot exceed body limit set on Fastify instance', async (t) => { 90 | const fastify = Fastify({ bodyLimit: 10 }) 91 | 92 | await fastify.register(plugin) 93 | fastify.post('/limited', (req, res) => { 94 | res.send(Object.assign({}, req.body, { message: 'done' })) 95 | }) 96 | 97 | await fastify.listen({ port: 0 }) 98 | fastify.server.unref() 99 | 100 | const payload = require('node:crypto').randomBytes(128).toString('hex') 101 | const response = await fastify.inject({ 102 | path: '/limited', 103 | method: 'POST', 104 | ...formAutoContent({ foo: payload }) 105 | }) 106 | t.assert.ifError(response.error) 107 | t.assert.strictEqual(response.statusCode, 413) 108 | t.assert.strictEqual(JSON.parse(response.body).message, 'Request body is too large') 109 | }) 110 | 111 | test('plugin bodyLimit should overwrite Fastify instance bodyLimit', async (t) => { 112 | const fastify = Fastify({ bodyLimit: 100000 }) 113 | 114 | fastify.register(plugin, { bodyLimit: 10 }) 115 | fastify.post('/limited', (req, res) => { 116 | res.send(Object.assign({}, req.body, { message: 'done' })) 117 | }) 118 | 119 | await fastify.listen({ port: 0 }) 120 | fastify.server.unref() 121 | 122 | const payload = require('node:crypto').randomBytes(128).toString('hex') 123 | const response = await fastify.inject({ 124 | path: '/limited', 125 | method: 'POST', 126 | ...formAutoContent({ foo: payload }) 127 | }) 128 | t.assert.ifError(response.error) 129 | t.assert.strictEqual(response.statusCode, 413) 130 | t.assert.strictEqual(JSON.parse(response.body).message, 'Request body is too large') 131 | }) 132 | 133 | test('plugin should throw if opts.parser is not a function', async (t) => { 134 | const fastify = Fastify() 135 | try { 136 | await fastify.register(plugin, { parser: 'invalid' }) 137 | await fastify.listen({ port: 0 }) 138 | } catch (err) { 139 | t.assert.ok(err) 140 | t.assert.match(err.message, /parser must be a function/) 141 | } finally { 142 | fastify.server.unref() 143 | } 144 | }) 145 | 146 | test('plugin should not parse nested objects by default', async (t) => { 147 | const fastify = Fastify() 148 | 149 | fastify.register(plugin) 150 | fastify.post('/test1', (req, res) => { 151 | res.send(Object.assign({}, req.body, { message: 'done' })) 152 | }) 153 | 154 | await fastify.listen({ port: 0 }) 155 | fastify.server.unref() 156 | 157 | const response = await fastify.inject({ 158 | path: '/test1', 159 | method: 'POST', 160 | ...formAutoContent({ 'foo[one]': 'foo', 'foo[two]': 'bar' }) 161 | }) 162 | t.assert.ifError(response.error) 163 | t.assert.strictEqual(response.statusCode, 200) 164 | t.assert.deepStrictEqual(JSON.parse(response.body), { 'foo[one]': 'foo', 'foo[two]': 'bar', message: 'done' }) 165 | }) 166 | 167 | test('plugin should allow providing custom parser as option', async (t) => { 168 | const fastify = Fastify() 169 | 170 | // this makes sure existing users for <= 4 have upgrade path 171 | fastify.register(plugin, { parser: str => qs.parse(str) }) 172 | fastify.post('/test1', (req, res) => { 173 | res.send(Object.assign({}, req.body, { message: 'done' })) 174 | }) 175 | 176 | await fastify.listen({ port: 0 }) 177 | fastify.server.unref() 178 | 179 | const response = await fastify.inject({ 180 | path: '/test1', 181 | method: 'POST', 182 | ...formAutoContent({ 'foo[one]': 'foo', 'foo[two]': 'bar' }) 183 | }) 184 | t.assert.ifError(response.error) 185 | t.assert.strictEqual(response.statusCode, 200) 186 | t.assert.deepStrictEqual(JSON.parse(response.body), { foo: { one: 'foo', two: 'bar' }, message: 'done' }) 187 | }) 188 | -------------------------------------------------------------------------------- /types/formbody.d.ts: -------------------------------------------------------------------------------- 1 | import { FastifyPluginCallback } from 'fastify' 2 | 3 | type FastifyFormbody = FastifyPluginCallback 4 | 5 | declare namespace fastifyFormbody { 6 | export interface FastifyFormbodyOptions { 7 | bodyLimit?: number 8 | parser?: (str: string) => Record 9 | } 10 | 11 | /** 12 | * @deprecated Use FastifyFormbodyOptions instead 13 | */ 14 | export type FormBodyPluginOptions = FastifyFormbodyOptions 15 | 16 | export const fastifyFormbody: FastifyFormbody 17 | export { fastifyFormbody as default } 18 | } 19 | 20 | declare function fastifyFormbody (...params: Parameters): ReturnType 21 | export = fastifyFormbody 22 | -------------------------------------------------------------------------------- /types/formbody.test-d.ts: -------------------------------------------------------------------------------- 1 | import fastify from 'fastify' 2 | import querystring from 'node:querystring' 3 | import { expectDeprecated, expectError, expectType } from 'tsd' 4 | import formBodyPlugin, { FastifyFormbodyOptions, FormBodyPluginOptions } from '..' 5 | 6 | const app = fastify() 7 | app.register(formBodyPlugin) 8 | 9 | app.register(formBodyPlugin, { }) 10 | app.register(formBodyPlugin, { 11 | bodyLimit: 1000 12 | }) 13 | app.register(formBodyPlugin, { 14 | parser: (s) => querystring.parse(s) 15 | }) 16 | 17 | expectType({} as FastifyFormbodyOptions) 18 | expectDeprecated({} as FormBodyPluginOptions) 19 | 20 | expectError(app.register(formBodyPlugin, { invalid: true })) 21 | --------------------------------------------------------------------------------