├── .npmrc ├── .gitattributes ├── eslint.config.js ├── .github ├── dependabot.yml ├── workflows │ └── ci.yml └── stale.yml ├── LICENSE ├── package.json ├── README.md ├── types ├── index.test-d.ts └── index.d.ts ├── index.js ├── .gitignore └── test └── index.test.js /.npmrc: -------------------------------------------------------------------------------- 1 | ignore-scripts=true 2 | package-lock=false 3 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behavior to automatically convert line endings 2 | * text=auto eol=lf 3 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = require('neostandard')({ 4 | ignores: require('neostandard').resolveIgnoresFromGitignore(), 5 | ts: true 6 | }) 7 | -------------------------------------------------------------------------------- /.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/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 | # This allows a subsequently queued workflow run to interrupt previous runs 18 | concurrency: 19 | group: "${{ github.workflow }}-${{ github.event.pull_request.head.label || github.head_ref || github.ref }}" 20 | cancel-in-progress: true 21 | 22 | permissions: 23 | contents: read 24 | 25 | jobs: 26 | test: 27 | permissions: 28 | contents: write 29 | pull-requests: write 30 | uses: fastify/workflows/.github/workflows/plugins-ci.yml@v5 31 | with: 32 | license-check: true 33 | lint: true 34 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-present The Fastify team 4 | 5 | The Fastify team members are listed at https://github.com/fastify/fastify#team. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@fastify/accepts", 3 | "version": "5.0.4", 4 | "description": "Add accept parser to fastify", 5 | "main": "index.js", 6 | "type": "commonjs", 7 | "types": "types/index.d.ts", 8 | "devDependencies": { 9 | "@types/node": "^24.0.8", 10 | "c8": "^10.1.3", 11 | "eslint": "^9.17.0", 12 | "fastify": "^5.0.0", 13 | "neostandard": "^0.12.0", 14 | "tsd": "^0.33.0" 15 | }, 16 | "dependencies": { 17 | "accepts": "^1.3.8", 18 | "fastify-plugin": "^5.0.0" 19 | }, 20 | "scripts": { 21 | "lint": "eslint", 22 | "lint:fix": "eslint --fix", 23 | "test": "npm run test:unit && npm run test:typescript", 24 | "test:typescript": "tsd", 25 | "test:unit": "c8 --100 node --test" 26 | }, 27 | "repository": { 28 | "type": "git", 29 | "url": "git+https://github.com/fastify/fastify-accepts.git" 30 | }, 31 | "author": "allevo", 32 | "contributors": [ 33 | { 34 | "name": "Matteo Collina", 35 | "email": "hello@matteocollina.com" 36 | }, 37 | { 38 | "name": "Manuel Spigolon", 39 | "email": "behemoth89@gmail.com" 40 | }, 41 | { 42 | "name": "James Sumners", 43 | "url": "https://james.sumners.info" 44 | }, 45 | { 46 | "name": "Frazer Smith", 47 | "email": "frazer.dev@icloud.com", 48 | "url": "https://github.com/fdawgs" 49 | } 50 | ], 51 | "license": "MIT", 52 | "bugs": { 53 | "url": "https://github.com/fastify/fastify-accepts/issues" 54 | }, 55 | "homepage": "https://github.com/fastify/fastify-accepts#readme", 56 | "funding": [ 57 | { 58 | "type": "github", 59 | "url": "https://github.com/sponsors/fastify" 60 | }, 61 | { 62 | "type": "opencollective", 63 | "url": "https://opencollective.com/fastify" 64 | } 65 | ], 66 | "publishConfig": { 67 | "access": "public" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # @fastify/accepts 2 | 3 | [![CI](https://github.com/fastify/fastify-accepts/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/fastify/fastify-accepts/actions/workflows/ci.yml) 4 | [![NPM version](https://img.shields.io/npm/v/@fastify/accepts.svg?style=flat)](https://www.npmjs.com/package/@fastify/accepts) 5 | [![neostandard javascript style](https://img.shields.io/badge/code_style-neostandard-brightgreen?style=flat)](https://github.com/neostandard/neostandard) 6 | 7 | Add an accepts parser to Fastify. 8 | 9 | ## Install 10 | 11 | `npm i @fastify/accepts` 12 | 13 | ### Compatibility 14 | 15 | | Plugin version | Fastify version | 16 | | ---------------|-----------------| 17 | | `>=5.x` | `^5.x` | 18 | | `^4.x` | `^4.x` | 19 | | `>=2.x <4.x` | `^3.x` | 20 | | `^1.x` | `^2.x` | 21 | | `^1.x` | `^1.x` | 22 | 23 | 24 | Please note that if a Fastify version is out of support, then so are the corresponding versions of this plugin 25 | in the table above. 26 | See [Fastify's LTS policy](https://github.com/fastify/fastify/blob/main/docs/Reference/LTS.md) for more details. 27 | 28 | ## Usage 29 | 30 | ```js 31 | const fastify = require('fastify') 32 | const Boom = require('@hapi/boom') 33 | 34 | fastify.register(require('@fastify/accepts')) 35 | 36 | fastify.post('/', function (req, reply) { 37 | const accept = req.accepts() // Accepts object 38 | switch(accept.type(['json', 'html'])) { 39 | case 'json': 40 | reply.type('application/json').send({hello: 'world'}) 41 | break 42 | case 'html': 43 | reply.type('text/html').send('hello, world!') 44 | break 45 | default: 46 | reply.send(Boom.notAcceptable('unacceptable')) 47 | break 48 | } 49 | }) 50 | ``` 51 | 52 | See [accepts package](https://www.npmjs.com/package/accepts) for all available APIs. 53 | 54 | This plugin adds to `Request` object all `Accepts` object methods. 55 | 56 | ```js 57 | fastify.post('/', function (req, reply) { 58 | req.charset(['utf-8']) 59 | req.charsets() 60 | req.encoding(['gzip', 'compress']) 61 | req.encodings() 62 | req.language(['es', 'en']) 63 | req.languages() 64 | req.type(['image/png', 'image/tiff']) 65 | req.types() 66 | }) 67 | ``` 68 | 69 | ### Options 70 | 71 | - `decorateReply` If `true`, the `Reply` object will be decorated with the `requestAccepts`, `requestTypes`, `requestCharsets`, `requestEncodings`, and `requestLanguages` methods, which will return the corresponding values from the `Request` object. Default: `false`. 72 | 73 | ## License 74 | 75 | Licensed under [MIT](./LICENSE). 76 | -------------------------------------------------------------------------------- /types/index.test-d.ts: -------------------------------------------------------------------------------- 1 | import fastify from 'fastify' 2 | import accepts from '..' 3 | 4 | const app = fastify() 5 | 6 | app.register(accepts) 7 | app.register(accepts, { decorateReply: true }) 8 | app.register(accepts, { decorateReply: false }) 9 | 10 | app.get('/', (request, reply) => { 11 | const accept = request.accepts() 12 | 13 | // Charsets 14 | accept.charsets() 15 | accept.charset() 16 | accept.charset('json', 'text') 17 | accept.charset(['json', 'text']) 18 | 19 | // Encoding 20 | accept.encodings() 21 | accept.encoding() 22 | accept.encoding('json', 'text') 23 | accept.encoding(['json', 'text']) 24 | 25 | // Languages 26 | accept.languages() 27 | accept.language() 28 | accept.language('json', 'text') 29 | accept.language(['json', 'text']) 30 | 31 | // Types 32 | accept.types() 33 | accept.type() 34 | accept.type('json', 'text') 35 | accept.type(['json', 'text']) 36 | 37 | request.charset() 38 | request.charsets() 39 | request.encoding() 40 | request.encodings() 41 | request.language() 42 | request.languages() 43 | request.type() 44 | request.types() 45 | 46 | request.charset(['aa', 'aa']) 47 | request.charsets(['aa', 'aa']) 48 | request.encoding(['aa', 'aa']) 49 | request.encodings(['aa', 'aa']) 50 | request.language(['aa', 'aa']) 51 | request.languages(['aa', 'aa']) 52 | request.type(['aa', 'aa']) 53 | request.types(['aa', 'aa']) 54 | 55 | request.charset('aa', 'aa') 56 | request.charsets('aa', 'aa') 57 | request.encoding('aa', 'aa') 58 | request.encodings('aa', 'aa') 59 | request.language('aa', 'aa') 60 | request.languages('aa', 'aa') 61 | request.type('aa', 'aa') 62 | request.types('aa', 'aa') 63 | 64 | reply.requestAccepts() 65 | 66 | reply.requestCharset() 67 | reply.requestCharsets() 68 | reply.requestEncoding() 69 | reply.requestEncodings() 70 | reply.requestLanguage() 71 | reply.requestLanguages() 72 | reply.requestType() 73 | reply.requestTypes() 74 | 75 | reply.requestCharset(['aa', 'aa']) 76 | reply.requestCharsets(['aa', 'aa']) 77 | reply.requestEncoding(['aa', 'aa']) 78 | reply.requestEncodings(['aa', 'aa']) 79 | reply.requestLanguage(['aa', 'aa']) 80 | reply.requestLanguages(['aa', 'aa']) 81 | reply.requestType(['aa', 'aa']) 82 | reply.requestTypes(['aa', 'aa']) 83 | 84 | reply.requestCharset('aa', 'aa') 85 | reply.requestCharsets('aa', 'aa') 86 | reply.requestEncoding('aa', 'aa') 87 | reply.requestEncodings('aa', 'aa') 88 | reply.requestLanguage('aa', 'aa') 89 | reply.requestLanguages('aa', 'aa') 90 | reply.requestType('aa', 'aa') 91 | reply.requestTypes('aa', 'aa') 92 | 93 | reply.send({ hello: 'world' }) 94 | }) 95 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const accepts = require('accepts') 4 | 5 | const fp = require('fastify-plugin') 6 | 7 | const acceptsObjectSymbol = Symbol('acceptsObject') 8 | 9 | const methodNames = [ 10 | 'charset', 'charsets', 11 | 'encoding', 'encodings', 12 | 'language', 'languages', 13 | 'type', 'types' 14 | ] 15 | 16 | /** @this {import('fastify').FastifyRequest} */ 17 | function acceptsMethod () { 18 | if (!this.raw[acceptsObjectSymbol]) { 19 | this.raw[acceptsObjectSymbol] = accepts(this.raw) 20 | } 21 | return this.raw[acceptsObjectSymbol] 22 | } 23 | 24 | /** @this {import('fastify').FastifyReply} */ 25 | function replyAcceptMethod () { 26 | if (!this.request[acceptsObjectSymbol]) { 27 | this.request[acceptsObjectSymbol] = accepts(this.request.raw) 28 | } 29 | return this.request[acceptsObjectSymbol] 30 | } 31 | 32 | /** @type {typeof import('./types/index').fastifyAccepts} */ 33 | function fastifyAccepts (fastify, options, done) { 34 | fastify.decorateRequest('accepts', acceptsMethod) 35 | 36 | const methodNamesLength = methodNames.length 37 | for (let i = 0; i < methodNamesLength; i += 1) { 38 | const methodName = methodNames[i] 39 | // Defining methods this way to ensure named functions show in stack traces 40 | fastify.decorateRequest(methodName, { 41 | [methodName]: function (arr) { 42 | const acceptsObject = this.accepts() 43 | if (arguments.length === 0) return acceptsObject[methodName]() 44 | return acceptsObject[methodName](arr) 45 | } 46 | }[methodName]) 47 | } 48 | 49 | if (options.decorateReply === true) { 50 | fastify.decorateReply('requestAccepts', replyAcceptMethod) 51 | 52 | for (let i = 0; i < methodNamesLength; i += 1) { 53 | const methodName = methodNames[i] 54 | const capitalizedMethodName = methodName.replace(/(?:^|\s)\S/gu, a => a.toUpperCase()) 55 | const replyMethodName = 'request' + capitalizedMethodName 56 | const acceptsMethodName = 'accepts' + capitalizedMethodName 57 | // Defining methods this way to ensure named functions show in stack traces 58 | fastify.decorateReply(replyMethodName, { 59 | [acceptsMethodName]: function (arr) { 60 | const acceptsObject = this.requestAccepts() 61 | if (arguments.length === 0) return acceptsObject[methodName]() 62 | return acceptsObject[methodName](arr) 63 | } 64 | }[acceptsMethodName]) 65 | } 66 | } 67 | 68 | done() 69 | } 70 | 71 | module.exports = fp(fastifyAccepts, { 72 | fastify: '5.x', 73 | name: '@fastify/accepts' 74 | }) 75 | module.exports.default = fastifyAccepts 76 | module.exports.fastifyAccepts = fastifyAccepts 77 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const { test } = require('node:test') 4 | 5 | const fastifyAccepts = require('..') 6 | 7 | const Fastify = require('fastify') 8 | 9 | /** @typedef {import('node:test').TestContext} TestContext */ 10 | 11 | const testCases = [ 12 | { 13 | name: 'request - no header', 14 | acceptHeader: '', 15 | url: '/request', 16 | expected: { 17 | types: [], 18 | charsets: ['*'], 19 | param1: 'utf1', 20 | param2: 'utf1', 21 | param3: 'utf1', 22 | param4: 'utf1', 23 | param5: 'utf1' 24 | } 25 | }, 26 | { 27 | name: 'request - simple', 28 | acceptHeader: 'text/html', 29 | url: '/request', 30 | expected: { 31 | types: ['text/html'], 32 | charsets: ['*'], 33 | param1: 'utf1', 34 | param2: 'utf1', 35 | param3: 'utf1', 36 | param4: 'utf1', 37 | param5: 'utf1' 38 | } 39 | }, 40 | { 41 | name: 'request - complex', 42 | acceptHeader: 'text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8', 43 | url: '/request', 44 | expected: { 45 | types: [ 46 | 'text/html', 47 | 'application/xhtml+xml', 48 | 'application/xml', 49 | '*/*' 50 | ], 51 | charsets: ['*'], 52 | param1: 'utf1', 53 | param2: 'utf1', 54 | param3: 'utf1', 55 | param4: 'utf1', 56 | param5: 'utf1' 57 | } 58 | }, 59 | { 60 | name: 'reply - no header', 61 | acceptHeader: '', 62 | url: '/reply', 63 | expected: { 64 | types: [], 65 | param1: 'utf1' 66 | } 67 | }, 68 | { 69 | name: 'reply - simple', 70 | acceptHeader: 'text/html', 71 | url: '/reply', 72 | expected: { 73 | types: ['text/html'], 74 | param1: 'utf1' 75 | } 76 | }, 77 | { 78 | name: 'reply - complex', 79 | acceptHeader: 'text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8', 80 | url: '/reply', 81 | expected: { 82 | types: [ 83 | 'text/html', 84 | 'application/xhtml+xml', 85 | 'application/xml', 86 | '*/*' 87 | ], 88 | param1: 'utf1' 89 | } 90 | } 91 | ] 92 | 93 | test('accept header', async (/** @type {TestContext} */ t) => { 94 | t.plan(testCases.length) 95 | 96 | const fastify = Fastify() 97 | fastify.register(fastifyAccepts, { decorateReply: true }) 98 | 99 | t.after(() => fastify.close()) 100 | 101 | fastify.get('/request', function (req, reply) { 102 | reply.send({ 103 | types: req.types(), 104 | charsets: req.charsets(), 105 | param1: req.charsets(['utf1']), 106 | param2: req.charsets(['utf1', 'utf2']), 107 | param3: req.charsets(['utf1', 'utf2', 'utf3']), 108 | param4: req.charsets(['utf1', 'utf2', 'utf3', 'utf4']), 109 | param5: req.charsets(['utf1', 'utf2', 'utf3', 'utf4', 'utf5']) 110 | }) 111 | }) 112 | 113 | fastify.get('/reply', function (_req, reply) { 114 | reply.send({ 115 | types: reply.requestTypes(), 116 | param1: reply.requestCharsets(['utf1']) 117 | }) 118 | }) 119 | 120 | await fastify.listen({ port: 0 }) 121 | 122 | const BASE_URL = `http://localhost:${fastify.server.address().port}` 123 | 124 | for (const testCase of testCases) { 125 | await t.test(testCase.name, async (/** @type {TestContext} */ t) => { 126 | t.plan(1) 127 | 128 | const result = await fetch(`${BASE_URL}${testCase.url}`, { 129 | headers: { 130 | accept: testCase.acceptHeader 131 | }, 132 | }) 133 | t.assert.deepStrictEqual(await result.json(), testCase.expected) 134 | }) 135 | } 136 | }) 137 | 138 | test('no reply decorator', async function (/** @type {TestContext} */ t) { 139 | const fastify = Fastify() 140 | fastify.register(fastifyAccepts, { decorateReply: false }) 141 | await fastify.ready() 142 | 143 | const methodNames = [ 144 | 'Charset', 'Charsets', 145 | 'Encoding', 'Encodings', 146 | 'Language', 'Languages', 147 | 'Type', 'Types' 148 | ] 149 | 150 | for (const method of methodNames) { 151 | t.assert.deepStrictEqual(fastify.hasReplyDecorator('request' + method, false), false) 152 | } 153 | }) 154 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | import { FastifyPluginCallback } from 'fastify' 2 | 3 | declare module 'fastify' { 4 | // Copied from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/accepts/index.d.ts 5 | // Definitions by: Stefan Reichel 6 | // Brice BERNARD 7 | interface Accepts { 8 | /** 9 | * Return the first accepted charset. If nothing in `charsets` is accepted, then `false` is returned. 10 | * If no charsets are supplied, all accepted charsets are returned, in the order of the client's preference 11 | * (most preferred first). 12 | */ 13 | charset(): string[]; 14 | charset(charsets: string[]): string | false; 15 | charset(...charsets: string[]): string | false; 16 | 17 | /** 18 | * Return the first accepted charset. If nothing in `charsets` is accepted, then `false` is returned. 19 | * If no charsets are supplied, all accepted charsets are returned, in the order of the client's preference 20 | * (most preferred first). 21 | */ 22 | charsets(): string[]; 23 | charsets(charsets: string[]): string | false; 24 | charsets(...charsets: string[]): string | false; 25 | 26 | /** 27 | * Return the first accepted encoding. If nothing in `encodings` is accepted, then `false` is returned. 28 | * If no encodings are supplied, all accepted encodings are returned, in the order of the client's preference 29 | * (most preferred first). 30 | */ 31 | encoding(): string[]; 32 | encoding(encodings: string[]): string | false; 33 | encoding(...encodings: string[]): string | false; 34 | 35 | /** 36 | * Return the first accepted encoding. If nothing in `encodings` is accepted, then `false` is returned. 37 | * If no encodings are supplied, all accepted encodings are returned, in the order of the client's preference 38 | * (most preferred first). 39 | */ 40 | encodings(): string[]; 41 | encodings(encodings: string[]): string | false; 42 | encodings(...encodings: string[]): string | false; 43 | 44 | /** 45 | * Return the first accepted language. If nothing in `languages` is accepted, then `false` is returned. 46 | * If no languages are supplied, all accepted languages are returned, in the order of the client's preference 47 | * (most preferred first). 48 | */ 49 | language(): string[]; 50 | language(languages: string[]): string | false; 51 | language(...languages: string[]): string | false; 52 | 53 | /** 54 | * Return the first accepted language. If nothing in `languages` is accepted, then `false` is returned. 55 | * If no languages are supplied, all accepted languages are returned, in the order of the client's preference 56 | * (most preferred first). 57 | */ 58 | languages(): string[]; 59 | languages(languages: string[]): string | false; 60 | languages(...languages: string[]): string | false; 61 | 62 | /** 63 | * Return the first accepted language. If nothing in `languages` is accepted, then `false` is returned. 64 | * If no languages are supplied, all accepted languages are returned, in the order of the client's preference 65 | * (most preferred first). 66 | */ 67 | lang(): string[]; 68 | lang(languages: string[]): string | false; 69 | lang(...languages: string[]): string | false; 70 | 71 | /** 72 | * Return the first accepted language. If nothing in `languages` is accepted, then `false` is returned. 73 | * If no languages are supplied, all accepted languages are returned, in the order of the client's preference 74 | * (most preferred first). 75 | */ 76 | langs(): string[]; 77 | langs(languages: string[]): string | false; 78 | langs(...languages: string[]): string | false; 79 | 80 | /** 81 | * Return the first accepted type (and it is returned as the same text as what appears in the `types` array). If nothing in `types` is accepted, then `false` is returned. 82 | * If no types are supplied, return the entire set of acceptable types. 83 | * 84 | * The `types` array can contain full MIME types or file extensions. Any value that is not a full MIME types is passed to `require('mime-types').lookup`. 85 | */ 86 | type(types: string[]): string[] | string | false; 87 | type(...types: string[]): string[] | string | false; 88 | types(types: string[]): string[] | string | false; 89 | types(...types: string[]): string[] | string | false; 90 | } 91 | 92 | interface FastifyRequest extends Accepts { 93 | accepts(): Accepts 94 | } 95 | 96 | interface FastifyReply { 97 | requestAccepts(): Accepts 98 | requestCharset: Accepts['charset'] 99 | requestCharsets: Accepts['charsets'] 100 | requestEncoding: Accepts['encoding'] 101 | requestEncodings: Accepts['charsets'] 102 | requestLanguage: Accepts['language'] 103 | requestLanguages: Accepts['languages'] 104 | requestType: Accepts['type'] 105 | requestTypes: Accepts['types'] 106 | } 107 | } 108 | type FastifyAccepts = FastifyPluginCallback 109 | 110 | declare namespace fastifyAccepts { 111 | export interface FastifyAcceptsOptions { 112 | decorateReply?: boolean | undefined 113 | } 114 | 115 | export const fastifyAccepts: FastifyAccepts 116 | export { fastifyAccepts as default } 117 | } 118 | 119 | declare function fastifyAccepts (...params: Parameters): ReturnType 120 | export = fastifyAccepts 121 | --------------------------------------------------------------------------------