[
  {
    "path": ".borp.yaml",
    "content": "files:\n  - 'test/**/*.test.js'\n"
  },
  {
    "path": ".gitattributes",
    "content": "# Set the default behavior, in case people don't have core.autocrlf set\n* text=auto\n\n# Require Unix line endings\n* text eol=lf\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"monthly\"\n    open-pull-requests-limit: 10\n\n  - package-ecosystem: \"npm\"\n    directory: \"/\"\n    schedule:\n      interval: \"monthly\"\n    open-pull-requests-limit: 10\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\non:\n  push:\n    branches:\n     - main\n     - next\n     - 'v*'\n    paths-ignore:\n      - 'docs/**'\n      - '*.md'\n  pull_request:\n    paths-ignore:\n      - 'docs/**'\n      - '*.md'\n\n# This allows a subsequently queued workflow run to interrupt previous runs\nconcurrency:\n    group: \"${{ github.workflow }}-${{ github.event.pull_request.head.label || github.head_ref || github.ref }}\"\n    cancel-in-progress: true\n\npermissions:\n  contents: read\n\njobs:\n  test:\n    permissions:\n      contents: write\n      pull-requests: write\n    uses: fastify/workflows/.github/workflows/plugins-ci.yml@v6\n    with:\n      license-check: true\n      lint: true\n"
  },
  {
    "path": ".github/workflows/lock-threads.yml",
    "content": "name: Lock Threads\n\non:\n  schedule:\n    - cron: '0 0 1 * *'\n  workflow_dispatch:\n\nconcurrency:\n  group: lock\n\npermissions:\n  contents: read\n\njobs:\n  lock-threads:\n    permissions:\n      issues: write\n      pull-requests: write\n    uses: fastify/workflows/.github/workflows/lock-threads.yml@v6\n"
  },
  {
    "path": ".gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n.pnpm-debug.log*\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n*.lcov\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# Snowpack dependency directory (https://snowpack.dev/)\nweb_modules/\n\n# TypeScript cache\n*.tsbuildinfo\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional stylelint cache\n.stylelintcache\n\n# Microbundle cache\n.rpt2_cache/\n.rts2_cache_cjs/\n.rts2_cache_es/\n.rts2_cache_umd/\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variable files\n.env\n.env.development.local\n.env.test.local\n.env.production.local\n.env.local\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n.parcel-cache\n\n# Next.js build output\n.next\nout\n\n# Nuxt.js build / generate output\n.nuxt\ndist\n\n# Gatsby files\n.cache/\n# Comment in the public line in if your project uses Gatsby and not Next.js\n# https://nextjs.org/blog/next-9-1#public-directory-support\n# public\n\n# vuepress build output\n.vuepress/dist\n\n# vuepress v2.x temp and cache directory\n.temp\n.cache\n\n# Docusaurus cache and generated files\n.docusaurus\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# TernJS port file\n.tern-port\n\n# Stores VSCode versions used for testing VSCode extensions\n.vscode-test\n\n# yarn v2\n.yarn/cache\n.yarn/unplugged\n.yarn/build-state.yml\n.yarn/install-state.gz\n.pnp.*\n\n# Vim swap files\n*.swp\n\n# macOS files\n.DS_Store\n\n# Clinic\n.clinic\n\n# lock files\nbun.lockb\npackage-lock.json\npnpm-lock.yaml\nyarn.lock\n\n# editor files\n.vscode\n.idea\n\n#tap files\n.tap/\n"
  },
  {
    "path": ".npmrc",
    "content": "ignore-scripts=true\npackage-lock=false\n\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018-present Tomas Della Vedova and The Fastify team <https://github.com/fastify/fastify#team>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# @fastify/sensible\n\n[![CI](https://github.com/fastify/fastify-sensible/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/fastify/fastify-sensible/actions/workflows/ci.yml)\n[![NPM version](https://img.shields.io/npm/v/@fastify/sensible.svg?style=flat)](https://www.npmjs.com/package/@fastify/sensible)\n[![neostandard javascript style](https://img.shields.io/badge/code_style-neostandard-brightgreen?style=flat)](https://github.com/neostandard/neostandard)\n\nDefaults for Fastify that everyone can agree on™.<br>\nThis plugin adds some useful utilities to your Fastify instance, see the API section to learn more.\n\n*Why are these APIs here and not included with Fastify?<br>\nBecause Fastify aims to be as small and focused as possible, every utility that is not essential should be shipped as a standalone plugin.*\n\n## Install\n```\nnpm i @fastify/sensible\n```\n\n### Compatibility\n\n| Plugin version | Fastify version |\n| -------------- | --------------- |\n| `>=6.x`        | `^5.x`          |\n| `^5.x`         | `^4.x`          |\n| `^4.x`         | `^3.x`          |\n| `>=2.x <4.x`   | `^2.x`          |\n| `^1.x`         | `^1.x`          |\n\n\nPlease note that if a Fastify version is out of support, then so are the corresponding versions of this plugin\nin the table above.\nSee [Fastify's LTS policy](https://github.com/fastify/fastify/blob/main/docs/Reference/LTS.md) for more details.\n\n## Usage\n```js\nconst fastify = require('fastify')()\nfastify.register(require('@fastify/sensible'))\n\nfastify.get('/', (req, reply) => {\n  reply.notFound()\n})\n\nfastify.get('/async', async (req, reply) => {\n  throw fastify.httpErrors.notFound()\n})\n\nfastify.get('/async-return', async (req, reply) => {\n  return reply.notFound()\n})\n\nfastify.listen({ port: 3000 })\n```\n\n## Shared JSON Schema for HTTP errors\nIf you set the `sharedSchemaId` option, a shared JSON Schema is added and can be used in your routes.\n```js\nconst fastify = require('fastify')()\nfastify.register(require('@fastify/sensible'), {\n  sharedSchemaId: 'HttpError'\n})\n\nfastify.get('/async', {\n  schema: {\n    response: {\n      404: { $ref: 'HttpError' }\n    }\n  },\n  handler: async (req, reply) => {\n    return reply.notFound()\n  }\n})\n\nfastify.listen({ port: 3000 })\n```\n\n## API\n#### `fastify.httpErrors`\nObject that exposes `createError` and all of the `4xx` and `5xx` error constructors.\n\nUse of `4xx` and `5xx` error constructors follows the same structure as [`new createError[code || name]([msg]))`](https://github.com/jshttp/http-errors#new-createerrorcode--namemsg) in [http-errors](https://github.com/jshttp/http-errors):\n\n```js\n // the custom message is optional\nconst notFoundErr = fastify.httpErrors.notFound('custom message')\n```\n\n`4xx`\n- <code>fastify.httpErrors.<b>badRequest()</b></code>\n- <code>fastify.httpErrors.<b>unauthorized()</b></code>\n- <code>fastify.httpErrors.<b>paymentRequired()</b></code>\n- <code>fastify.httpErrors.<b>forbidden()</b></code>\n- <code>fastify.httpErrors.<b>notFound()</b></code>\n- <code>fastify.httpErrors.<b>methodNotAllowed()</b></code>\n- <code>fastify.httpErrors.<b>notAcceptable()</b></code>\n- <code>fastify.httpErrors.<b>proxyAuthenticationRequired()</b></code>\n- <code>fastify.httpErrors.<b>requestTimeout()</b></code>\n- <code>fastify.httpErrors.<b>conflict()</b></code>\n- <code>fastify.httpErrors.<b>gone()</b></code>\n- <code>fastify.httpErrors.<b>lengthRequired()</b></code>\n- <code>fastify.httpErrors.<b>preconditionFailed()</b></code>\n- <code>fastify.httpErrors.<b>payloadTooLarge()</b></code>\n- <code>fastify.httpErrors.<b>uriTooLong()</b></code>\n- <code>fastify.httpErrors.<b>unsupportedMediaType()</b></code>\n- <code>fastify.httpErrors.<b>rangeNotSatisfiable()</b></code>\n- <code>fastify.httpErrors.<b>expectationFailed()</b></code>\n- <code>fastify.httpErrors.<b>imateapot()</b></code>\n- <code>fastify.httpErrors.<b>misdirectedRequest()</b></code>\n- <code>fastify.httpErrors.<b>unprocessableEntity()</b></code>\n- <code>fastify.httpErrors.<b>locked()</b></code>\n- <code>fastify.httpErrors.<b>failedDependency()</b></code>\n- <code>fastify.httpErrors.<b>tooEarly()</b></code>\n- <code>fastify.httpErrors.<b>upgradeRequired()</b></code>\n- <code>fastify.httpErrors.<b>preconditionRequired()</b></code>\n- <code>fastify.httpErrors.<b>tooManyRequests()</b></code>\n- <code>fastify.httpErrors.<b>requestHeaderFieldsTooLarge()</b></code>\n- <code>fastify.httpErrors.<b>unavailableForLegalReasons()</b></code>\n\n`5xx`\n- <code>fastify.httpErrors.<b>internalServerError()</b></code>\n- <code>fastify.httpErrors.<b>notImplemented()</b></code>\n- <code>fastify.httpErrors.<b>badGateway()</b></code>\n- <code>fastify.httpErrors.<b>serviceUnavailable()</b></code>\n- <code>fastify.httpErrors.<b>gatewayTimeout()</b></code>\n- <code>fastify.httpErrors.<b>httpVersionNotSupported()</b></code>\n- <code>fastify.httpErrors.<b>variantAlsoNegotiates()</b></code>\n- <code>fastify.httpErrors.<b>insufficientStorage()</b></code>\n- <code>fastify.httpErrors.<b>loopDetected()</b></code>\n- <code>fastify.httpErrors.<b>bandwidthLimitExceeded()</b></code>\n- <code>fastify.httpErrors.<b>notExtended()</b></code>\n- <code>fastify.httpErrors.<b>networkAuthenticationRequired()</b></code>\n\n`createError`\n\nUse of `createError` follows the same structure as [`createError([status], [message], [properties])`](https://github.com/jshttp/http-errors#createerrorstatus-message-properties) in [http-errors](https://github.com/jshttp/http-errors):\n\n```js\nconst err = fastify.httpErrors.createError(404, 'This video does not exist!')\n```\n\n#### `reply.[httpError]`\nThe `reply` interface is decorated with all of the functions declared above, using it is easy:\n```js\nfastify.get('/', (req, reply) => {\n  reply.notFound()\n})\n```\n\n#### `reply.vary`\nThe `reply` interface is decorated with [`jshttp/vary`](https://github.com/jshttp/vary), the API is the same, but you do not need to pass the res object.\n```js\nfastify.get('/', (req, reply) => {\n  reply.vary('Accept')\n  reply.send('ok')\n})\n```\n\n#### `reply.cacheControl`\nThe `reply` interface is decorated with a helper to configure cache control response headers.\n```js\n// configure a single type\nfastify.get('/', (req, reply) => {\n  reply.cacheControl('public')\n  reply.send('ok')\n})\n\n// configure multiple types\nfastify.get('/', (req, reply) => {\n  reply.cacheControl('public')\n  reply.cacheControl('immutable')\n  reply.send('ok')\n})\n\n// configure a type time\nfastify.get('/', (req, reply) => {\n  reply.cacheControl('max-age', 42)\n  reply.send('ok')\n})\n\n// the time can be defined as string\nfastify.get('/', (req, reply) => {\n  // all the formats of github.com/vercel/ms are supported\n  reply.cacheControl('max-age', '1d') // will set to 'max-age=86400'\n  reply.send('ok')\n})\n```\n\n#### `reply.preventCache`\nThe `reply` interface is decorated with a helper to set the cache control header to a no caching configuration.\n```js\nfastify.get('/', (req, reply) => {\n  // will set cache-control to 'no-store, max-age=0, private'\n  // and for HTTP/1.0 compatibility\n  // will set pragma to 'no-cache' and expires to 0\n  reply.preventCache()\n  reply.send('ok')\n})\n```\n\n#### `reply.revalidate`\nThe `reply` interface is decorated with a helper to set the cache control header to a no caching configuration.\n```js\nfastify.get('/', (req, reply) => {\n  reply.revalidate() // will set to 'max-age=0, must-revalidate'\n  reply.send('ok')\n})\n```\n\n#### `reply.staticCache`\nThe `reply` interface is decorated with a helper to set the cache control header to a public and immutable configuration.\n```js\nfastify.get('/', (req, reply) => {\n  // the time can be defined as a string\n  reply.staticCache(42) // will set to 'public, max-age=42, immutable'\n  reply.send('ok')\n})\n```\n\n#### `reply.stale`\nThe `reply` interface is decorated with a helper to set the cache control header for [stale content](https://tools.ietf.org/html/rfc5861).\n```js\nfastify.get('/', (req, reply) => {\n  // the time can be defined as a string\n  reply.stale('while-revalidate', 42)\n  reply.stale('if-error', 1)\n  reply.send('ok')\n})\n```\n\n#### `reply.maxAge`\nThe `reply` interface is decorated with a helper to set max age of the response. It can be used in conjunction with `reply.stale`, see [here](https://web.dev/stale-while-revalidate/).\n```js\nfastify.get('/', (req, reply) => {\n  // the time can be defined as a string\n  reply.maxAge(86400)\n  reply.stale('while-revalidate', 42)\n  reply.send('ok')\n})\n```\n\n#### `request.forwarded`\nThe `request` interface is decorated with [`jshttp/forwarded`](https://github.com/jshttp/forwarded), the API is the same, but you do not need to pass the request object:\n```js\nfastify.get('/', (req, reply) => {\n  reply.send(req.forwarded())\n})\n```\n\n#### `request.is`\nThe `request` interface is decorated with [`jshttp/type-is`](https://github.com/jshttp/type-is), the API is the same but you do not need to pass the request object:\n```js\nfastify.get('/', (req, reply) => {\n  reply.send(req.is(['html', 'json']))\n})\n```\n\n#### `assert`\nVerify if a given condition is true, if not it throws the specified http error.<br> Useful if you work with *async* routes:\n```js\n// the custom message is optional\nfastify.assert(\n  req.headers.authorization, 400, 'Missing authorization header'\n)\n```\nThe `assert` API also exposes the following methods:\n- <code>fastify.assert.<b>ok()</b></code>\n- <code>fastify.assert.<b>equal()</b></code>\n- <code>fastify.assert.<b>notEqual()</b></code>\n- <code>fastify.assert.<b>strictEqual()</b></code>\n- <code>fastify.assert.<b>notStrictEqual()</b></code>\n- <code>fastify.assert.<b>deepEqual()</b></code>\n- <code>fastify.assert.<b>notDeepEqual()</b></code>\n\n#### `to`\nAsync await wrapper for easy error handling without try-catch, inspired by [`await-to-js`](https://github.com/scopsy/await-to-js):\n\n```js\nconst [err, user] = await fastify.to(\n  db.findOne({ user: 'tyrion' })\n)\n```\n\n## Contributing\nDo you feel there is some utility that *everyone can agree on* that is not present?<br>\nOpen an issue and let's discuss it! Even better a pull request!\n\n## Acknowledgments\n\nThe project name is inspired by [`vim-sensible`](https://github.com/tpope/vim-sensible), an awesome package that if you use vim you should use too.\n\n## License\n\nLicensed under [MIT](./LICENSE).\n"
  },
  {
    "path": "eslint.config.js",
    "content": "'use strict'\n\nmodule.exports = require('neostandard')({\n  ignores: require('neostandard').resolveIgnoresFromGitignore(),\n  ts: true\n})\n"
  },
  {
    "path": "index.js",
    "content": "'use strict'\n\nconst fp = require('fastify-plugin')\n// External utilities\nconst forwarded = require('forwarded')\nconst typeis = require('type-is')\n// Internals Utilities\nconst httpErrors = require('./lib/httpErrors')\nconst assert = require('./lib/assert')\nconst vary = require('./lib/vary')\nconst cache = require('./lib/cache-control')\n\n/** @type {typeof import('./types/index').fastifySensible} */\nfunction fastifySensible (fastify, opts, next) {\n  fastify.decorate('httpErrors', httpErrors)\n  fastify.decorate('assert', assert)\n  fastify.decorate('to', to)\n\n  fastify.decorateRequest('forwarded', function requestForwarded () {\n    return forwarded(this.raw)\n  })\n\n  fastify.decorateRequest('is', function requestIs (types) {\n    return typeis(this.raw, Array.isArray(types) ? types : [types])\n  })\n\n  fastify.decorateReply('vary', vary)\n  fastify.decorateReply('cacheControl', cache.cacheControl)\n  fastify.decorateReply('preventCache', cache.preventCache)\n  fastify.decorateReply('revalidate', cache.revalidate)\n  fastify.decorateReply('staticCache', cache.staticCache)\n  fastify.decorateReply('stale', cache.stale)\n  fastify.decorateReply('maxAge', cache.maxAge)\n\n  const httpErrorsKeys = Object.keys(httpErrors)\n  const httpErrorsKeysLength = httpErrorsKeys.length\n  for (let i = 0; i < httpErrorsKeysLength; ++i) {\n    const httpError = httpErrorsKeys[i]\n\n    switch (httpError) {\n      case 'HttpError':\n        // skip abstract class constructor\n        break\n      case 'getHttpError':\n        fastify.decorateReply('getHttpError', function replyGetHttpError (errorCode, message) {\n          this.send(httpErrors.getHttpError(errorCode, message))\n          return this\n        })\n        break\n      default: {\n        const capitalizedMethodName = httpError.replace(/(?:^|\\s)\\S/gu, a => a.toUpperCase())\n        const replyMethodName = 'sensible' + capitalizedMethodName\n        fastify.decorateReply(httpError, {\n          [replyMethodName]: function (message) {\n            this.send(httpErrors[httpError](message))\n            return this\n          }\n        }[replyMethodName])\n      }\n    }\n  }\n\n  if (opts?.sharedSchemaId) {\n    // The schema must be the same as:\n    // https://github.com/fastify/fastify/blob/c08b67e0bfedc9935b51c787ae4cd6b250ad303c/build/build-error-serializer.js#L8-L16\n    fastify.addSchema({\n      $id: opts.sharedSchemaId,\n      type: 'object',\n      properties: {\n        statusCode: { type: 'number' },\n        code: { type: 'string' },\n        error: { type: 'string' },\n        message: { type: 'string' }\n      }\n    })\n  }\n\n  /**\n   * Wraps a promise for easier error handling without try/catch.\n   * @template T\n   * @param {Promise<T>} promise - The promise to wrap.\n   * @returns {Promise<[Error, undefined] | [null, T]>} A promise that resolves to a tuple containing either an error or the resolved data.\n   */\n  function to (promise) {\n    return promise.then(data => [null, data], err => [err, undefined])\n  }\n\n  next()\n}\n\nmodule.exports = fp(fastifySensible, {\n  name: '@fastify/sensible',\n  fastify: '5.x'\n})\nmodule.exports.default = fastifySensible\nmodule.exports.fastifySensible = fastifySensible\nmodule.exports.httpErrors = httpErrors\nmodule.exports.HttpError = httpErrors.HttpError\n"
  },
  {
    "path": "lib/assert.js",
    "content": "/* eslint-disable eqeqeq */\n'use strict'\n\nconst { dequal: deepEqual } = require('dequal')\nconst { getHttpError } = require('./httpErrors')\n\nfunction assert (condition, code, message) {\n  if (condition) return\n  throw getHttpError(code, message)\n}\n\nassert.ok = assert\n\nassert.equal = function (a, b, code, message) {\n  assert(a == b, code, message)\n}\n\nassert.notEqual = function (a, b, code, message) {\n  assert(a != b, code, message)\n}\n\nassert.strictEqual = function (a, b, code, message) {\n  assert(a === b, code, message)\n}\n\nassert.notStrictEqual = function (a, b, code, message) {\n  assert(a !== b, code, message)\n}\n\nassert.deepEqual = function (a, b, code, message) {\n  assert(deepEqual(a, b), code, message)\n}\n\nassert.notDeepEqual = function (a, b, code, message) {\n  assert(!deepEqual(a, b), code, message)\n}\n\nmodule.exports = assert\n"
  },
  {
    "path": "lib/cache-control.js",
    "content": "'use strict'\n\n// Cache control header utilities, for more info see:\n// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control\n// Useful reads:\n// - https://odino.org/http-cache-101-scaling-the-web/\n// - https://web.dev/stale-while-revalidate/\n// - https://csswizardry.com/2019/03/cache-control-for-civilians/\n// - https://jakearchibald.com/2016/caching-best-practices/\n\nconst assert = require('node:assert')\nconst ms = require('@lukeed/ms').parse\n\nconst validSingletimes = [\n  'must-revalidate',\n  'no-cache',\n  'no-store',\n  'no-transform',\n  'public',\n  'private',\n  'proxy-revalidate',\n  'immutable'\n]\n\nconst validMultitimes = [\n  'max-age',\n  's-maxage',\n  'stale-while-revalidate',\n  'stale-if-error'\n]\n\nfunction cacheControl (type, time) {\n  const previoustime = this.getHeader('Cache-Control')\n  if (time == null) {\n    assert(validSingletimes.indexOf(type) !== -1, `Invalid Cache Control type: ${type}`)\n    this.header('Cache-Control', previoustime ? `${previoustime}, ${type}` : type)\n  } else {\n    if (typeof time === 'string') {\n      time = ms(time) / 1000\n    }\n    assert(validMultitimes.indexOf(type) !== -1, `Invalid Cache Control type: ${type}`)\n    assert(typeof time === 'number', 'The cache control time should be a number')\n    this.header('Cache-Control', previoustime ? `${previoustime}, ${type}=${time}` : `${type}=${time}`)\n  }\n  return this\n}\n\nfunction preventCache () {\n  this\n    .header('Cache-Control', 'no-store, max-age=0, private')\n    // compatibility support for HTTP/1.0\n    // see: https://owasp.org/www-community/OWASP_Application_Security_FAQ#how-do-i-ensure-that-sensitive-pages-are-not-cached-on-the-users-browser\n    .header('Pragma', 'no-cache')\n    .header('Expires', 0)\n\n  return this\n}\n\nfunction maxAge (time) {\n  return this.cacheControl('max-age', time)\n}\n\nfunction revalidate () {\n  this.header('Cache-Control', 'max-age=0, must-revalidate')\n  return this\n}\n\nfunction staticCache (time) {\n  if (typeof time === 'string') {\n    time = ms(time) / 1000\n  }\n  assert(typeof time === 'number', 'The cache control time should be a number')\n  this.header('Cache-Control', `public, max-age=${time}, immutable`)\n  return this\n}\n\nfunction stale (type, time) {\n  if (type === 'while-revalidate') {\n    return this.cacheControl('stale-while-revalidate', time)\n  } else if (type === 'if-error') {\n    return this.cacheControl('stale-if-error', time)\n  } else {\n    throw new Error(`Invalid cache control stale time ${time}`)\n  }\n}\n\nmodule.exports = {\n  cacheControl,\n  preventCache,\n  revalidate,\n  staticCache,\n  stale,\n  maxAge\n}\n"
  },
  {
    "path": "lib/httpError.d.ts",
    "content": "export declare class HttpError<N extends number = number> extends Error {\n  status: N\n  statusCode: N\n  expose: boolean\n  message: string\n  headers?: {\n    [key: string]: string;\n  };\n\n  [key: string]: any;\n}\n\ntype UnknownError = Error | string | number | { [key: string]: any }\n\nexport type HttpErrorTypes = {\n  badRequest: 400,\n  unauthorized: 401,\n  paymentRequired: 402,\n  forbidden: 403,\n  notFound: 404,\n  methodNotAllowed: 405,\n  notAcceptable: 406,\n  proxyAuthenticationRequired: 407,\n  requestTimeout: 408,\n  conflict: 409,\n  gone: 410,\n  lengthRequired: 411,\n  preconditionFailed: 412,\n  payloadTooLarge: 413,\n  uriTooLong: 414,\n  unsupportedMediaType: 415,\n  rangeNotSatisfiable: 416,\n  expectationFailed: 417,\n  imateapot: 418,\n  misdirectedRequest: 421,\n  unprocessableEntity: 422,\n  locked: 423,\n  failedDependency: 424,\n  tooEarly: 425,\n  upgradeRequired: 426,\n  preconditionRequired: 428,\n  tooManyRequests: 429,\n  requestHeaderFieldsTooLarge: 431,\n  unavailableForLegalReasons: 451,\n  internalServerError: 500,\n  notImplemented: 501,\n  badGateway: 502,\n  serviceUnavailable: 503,\n  gatewayTimeout: 504,\n  httpVersionNotSupported: 505,\n  variantAlsoNegotiates: 506,\n  insufficientStorage: 507,\n  loopDetected: 508,\n  bandwidthLimitExceeded: 509,\n  notExtended: 510\n  networkAuthenticationRequired: 511\n}\n\ntype ValueOf<ObjectType, ValueType extends keyof ObjectType = keyof ObjectType> = ObjectType[ValueType]\n\nexport type HttpErrorNames = keyof HttpErrorTypes\nexport type HttpErrorCodes = ValueOf<HttpErrorTypes>\n// Permissive type for getHttpError lookups\nexport type HttpErrorCodesLoose = HttpErrorCodes | `${HttpErrorCodes}`\n// Helper to go from stringified error codes back to numeric\ntype AsCode<T> = T extends `${infer N extends HttpErrorCodes}` ? N : never\n\nexport type HttpErrors = {\n  HttpError: typeof HttpError;\n  getHttpError: <T extends HttpErrorCodesLoose>(code: T, message?: string) => HttpError<AsCode<T>>;\n  createError: (...args: UnknownError[]) => HttpError;\n} & {\n  [Property in keyof HttpErrorTypes]: (...args: UnknownError[]) => HttpError<HttpErrorTypes[Property]>\n}\n\n// eslint-disable-next-line @typescript-eslint/no-redeclare\ndeclare const HttpErrors: HttpErrors\nexport default HttpErrors\n"
  },
  {
    "path": "lib/httpErrors.js",
    "content": "'use strict'\n\nconst createError = require('http-errors')\nconst statusCodes = require('node:http').STATUS_CODES\n\nconst statusCodesMap = Object.assign({}, statusCodes)\nObject.keys(statusCodesMap).forEach(code => {\n  statusCodesMap[code] = normalize(code, statusCodesMap[code])\n})\n\nfunction normalize (code, msg) {\n  if (code === '414') return 'uriTooLong'\n  if (code === '505') return 'httpVersionNotSupported'\n  msg = msg.split(' ').join('').replace(/'/g, '')\n  msg = msg[0].toLowerCase() + msg.slice(1)\n  return msg\n}\n\nconst httpErrors = {\n  badRequest: function badRequest (message) {\n    return new createError.BadRequest(message)\n  },\n\n  unauthorized: function unauthorized (message) {\n    return new createError.Unauthorized(message)\n  },\n\n  paymentRequired: function paymentRequired (message) {\n    return new createError.PaymentRequired(message)\n  },\n\n  forbidden: function forbidden (message) {\n    return new createError.Forbidden(message)\n  },\n\n  notFound: function notFound (message) {\n    return new createError.NotFound(message)\n  },\n\n  methodNotAllowed: function methodNotAllowed (message) {\n    return new createError.MethodNotAllowed(message)\n  },\n\n  notAcceptable: function notAcceptable (message) {\n    return new createError.NotAcceptable(message)\n  },\n\n  proxyAuthenticationRequired: function proxyAuthenticationRequired (message) {\n    return new createError.ProxyAuthenticationRequired(message)\n  },\n\n  requestTimeout: function requestTimeout (message) {\n    return new createError.RequestTimeout(message)\n  },\n\n  conflict: function conflict (message) {\n    return new createError.Conflict(message)\n  },\n\n  gone: function gone (message) {\n    return new createError.Gone(message)\n  },\n\n  lengthRequired: function lengthRequired (message) {\n    return new createError.LengthRequired(message)\n  },\n\n  preconditionFailed: function preconditionFailed (message) {\n    return new createError.PreconditionFailed(message)\n  },\n\n  payloadTooLarge: function payloadTooLarge (message) {\n    return new createError.PayloadTooLarge(message)\n  },\n\n  uriTooLong: function uriTooLong (message) {\n    return new createError.URITooLong(message)\n  },\n\n  unsupportedMediaType: function unsupportedMediaType (message) {\n    return new createError.UnsupportedMediaType(message)\n  },\n\n  rangeNotSatisfiable: function rangeNotSatisfiable (message) {\n    return new createError.RangeNotSatisfiable(message)\n  },\n\n  expectationFailed: function expectationFailed (message) {\n    return new createError.ExpectationFailed(message)\n  },\n\n  imateapot: function imateapot (message) {\n    return new createError.ImATeapot(message)\n  },\n\n  misdirectedRequest: function misdirectedRequest (message) {\n    return new createError.MisdirectedRequest(message)\n  },\n\n  unprocessableEntity: function unprocessableEntity (message) {\n    return new createError.UnprocessableEntity(message)\n  },\n\n  locked: function locked (message) {\n    return new createError.Locked(message)\n  },\n\n  failedDependency: function failedDependency (message) {\n    return new createError.FailedDependency(message)\n  },\n\n  tooEarly: function tooEarly (message) {\n    return new createError.TooEarly(message)\n  },\n\n  upgradeRequired: function upgradeRequired (message) {\n    return new createError.UpgradeRequired(message)\n  },\n\n  preconditionRequired: function preconditionRequired (message) {\n    return new createError.PreconditionRequired(message)\n  },\n\n  tooManyRequests: function tooManyRequests (message) {\n    return new createError.TooManyRequests(message)\n  },\n\n  requestHeaderFieldsTooLarge: function requestHeaderFieldsTooLarge (message) {\n    return new createError.RequestHeaderFieldsTooLarge(message)\n  },\n\n  unavailableForLegalReasons: function unavailableForLegalReasons (message) {\n    return new createError.UnavailableForLegalReasons(message)\n  },\n\n  internalServerError: function internalServerError (message) {\n    return new createError.InternalServerError(message)\n  },\n\n  notImplemented: function notImplemented (message) {\n    return new createError.NotImplemented(message)\n  },\n\n  badGateway: function badGateway (message) {\n    return new createError.BadGateway(message)\n  },\n\n  serviceUnavailable: function serviceUnavailable (message) {\n    return new createError.ServiceUnavailable(message)\n  },\n\n  gatewayTimeout: function gatewayTimeout (message) {\n    return new createError.GatewayTimeout(message)\n  },\n\n  httpVersionNotSupported: function httpVersionNotSupported (message) {\n    return new createError.HTTPVersionNotSupported(message)\n  },\n\n  variantAlsoNegotiates: function variantAlsoNegotiates (message) {\n    return new createError.VariantAlsoNegotiates(message)\n  },\n\n  insufficientStorage: function insufficientStorage (message) {\n    return new createError.InsufficientStorage(message)\n  },\n\n  loopDetected: function loopDetected (message) {\n    return new createError.LoopDetected(message)\n  },\n\n  bandwidthLimitExceeded: function bandwidthLimitExceeded (message) {\n    return new createError.BandwidthLimitExceeded(message)\n  },\n\n  notExtended: function notExtended (message) {\n    return new createError.NotExtended(message)\n  },\n\n  networkAuthenticationRequired: function networkAuthenticationRequired (message) {\n    return new createError.NetworkAuthenticationRequired(message)\n  }\n}\n\nfunction getHttpError (code, message) {\n  return httpErrors[statusCodesMap[code + '']](message)\n}\n\nmodule.exports = httpErrors\nmodule.exports.getHttpError = getHttpError\nmodule.exports.HttpError = createError.HttpError\nmodule.exports.createError = createError\n"
  },
  {
    "path": "lib/vary.js",
    "content": "'use strict'\n\nconst append = require('vary').append\n\n// Same implementation of https://github.com/jshttp/vary\n// but adapted to the Fastify API\nfunction vary (field) {\n  let value = this.getHeader('Vary') || ''\n  const header = Array.isArray(value)\n    ? value.join(', ')\n    : String(value)\n\n  // set new header\n  value = append(header, field)\n  this.header('Vary', value)\n}\n\nmodule.exports = vary\nmodule.exports.append = append\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"@fastify/sensible\",\n  \"version\": \"6.0.4\",\n  \"description\": \"Defaults for Fastify that everyone can agree on\",\n  \"main\": \"index.js\",\n  \"type\": \"commonjs\",\n  \"types\": \"types/index.d.ts\",\n  \"scripts\": {\n    \"lint\": \"eslint\",\n    \"lint:fix\": \"eslint --fix\",\n    \"test\": \"npm run test:unit && npm run test:typescript\",\n    \"test:typescript\": \"tsd\",\n    \"test:unit\": \"borp -C --check-coverage --reporter=@jsumners/line-reporter\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/fastify/fastify-sensible.git\"\n  },\n  \"keywords\": [\n    \"fastify\",\n    \"http\",\n    \"defaults\",\n    \"helper\"\n  ],\n  \"author\": \"Tomas Della Vedova - @delvedor (http://delved.org)\",\n  \"contributors\": [\n    {\n      \"name\": \"Matteo Collina\",\n      \"email\": \"hello@matteocollina.com\"\n    },\n    {\n      \"name\": \"Manuel Spigolon\",\n      \"email\": \"behemoth89@gmail.com\"\n    },\n    {\n      \"name\": \"Cemre Mengu\",\n      \"email\": \"cemremengu@gmail.com\"\n    },\n    {\n      \"name\": \"Frazer Smith\",\n      \"email\": \"frazer.dev@icloud.com\",\n      \"url\": \"https://github.com/fdawgs\"\n    }\n  ],\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/fastify/fastify-sensible/issues\"\n  },\n  \"homepage\": \"https://github.com/fastify/fastify-sensible#readme\",\n  \"funding\": [\n    {\n      \"type\": \"github\",\n      \"url\": \"https://github.com/sponsors/fastify\"\n    },\n    {\n      \"type\": \"opencollective\",\n      \"url\": \"https://opencollective.com/fastify\"\n    }\n  ],\n  \"devDependencies\": {\n    \"@jsumners/line-reporter\": \"^1.0.1\",\n    \"@types/node\": \"^25.0.3\",\n    \"borp\": \"^1.0.0\",\n    \"eslint\": \"^9.17.0\",\n    \"fastify\": \"^5.0.0\",\n    \"neostandard\": \"^0.13.0\",\n    \"tsd\": \"^0.33.0\"\n  },\n  \"dependencies\": {\n    \"@lukeed/ms\": \"^2.0.2\",\n    \"dequal\": \"^2.0.3\",\n    \"fastify-plugin\": \"^5.0.0\",\n    \"forwarded\": \"^0.2.0\",\n    \"http-errors\": \"^2.0.0\",\n    \"type-is\": \"^2.0.1\",\n    \"vary\": \"^1.1.2\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "test/assert.test.js",
    "content": "'use strict'\n\nconst { test } = require('node:test')\n\nconst Fastify = require('fastify')\nconst Sensible = require('../index')\n\ntest('Should support basic assert', (t, done) => {\n  t.plan(2)\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.ready(err => {\n    t.assert.ifError(err)\n    try {\n      fastify.assert.ok(true)\n      t.assert.ok('Works correctly')\n    } catch (err) {\n      t.assert.fail(err)\n    }\n    done()\n  })\n})\n\ntest('Should support ok assert', (t, done) => {\n  t.plan(2)\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.ready(err => {\n    t.assert.ifError(err)\n    try {\n      fastify.assert.ok(true)\n      t.assert.ok('Works correctly')\n    } catch (err) {\n      t.assert.fail(err)\n    }\n    done()\n  })\n})\n\ntest('Should support equal assert', (t, done) => {\n  t.plan(2)\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.ready(err => {\n    t.assert.ifError(err)\n    try {\n      fastify.assert.equal(1, '1')\n      t.assert.ok('Works correctly')\n    } catch (err) {\n      t.assert.fail(err)\n    }\n    done()\n  })\n})\n\ntest('Should support not equal assert', (t, done) => {\n  t.plan(2)\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.ready(err => {\n    t.assert.ifError(err)\n    try {\n      fastify.assert.notEqual(1, '2')\n      t.assert.ok('Works correctly')\n    } catch (err) {\n      t.assert.fail(err)\n    }\n    done()\n  })\n})\n\ntest('Should support strict equal assert', (t, done) => {\n  t.plan(2)\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.ready(err => {\n    t.assert.ifError(err)\n    try {\n      fastify.assert.strictEqual(1, 1)\n      t.assert.ok('Works correctly')\n    } catch (err) {\n      t.assert.fail(err)\n    }\n    done()\n  })\n})\n\ntest('Should support not strict equal assert', (t, done) => {\n  t.plan(2)\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.ready(err => {\n    t.assert.ifError(err)\n    try {\n      fastify.assert.notStrictEqual(1, 2)\n      t.assert.ok('Works correctly')\n    } catch (err) {\n      t.assert.fail(err)\n    }\n    done()\n  })\n})\n\ntest('Should support deep equal assert', (t, done) => {\n  t.plan(2)\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.ready(err => {\n    t.assert.ifError(err)\n    try {\n      fastify.assert.deepEqual({ a: 1 }, { a: 1 })\n      t.assert.ok('Works correctly')\n    } catch (err) {\n      t.assert.fail(err)\n    }\n    done()\n  })\n})\n\ntest('Should support not deep equal assert', (t, done) => {\n  t.plan(2)\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.ready(err => {\n    t.assert.ifError(err)\n    try {\n      fastify.assert.notDeepEqual({ hello: 'world' }, { hello: 'dlrow' })\n      t.assert.ok('Works correctly')\n    } catch (err) {\n      t.assert.fail(err)\n    }\n    done()\n  })\n})\n\ntest('Should support basic assert (throw)', (t, done) => {\n  t.plan(2)\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.ready(err => {\n    t.assert.ifError(err)\n    try {\n      fastify.assert(false)\n      t.assert.fail('Should throw')\n    } catch (err) {\n      t.assert.ok(err)\n    }\n    done()\n  })\n})\n\ntest('Should support equal assert (throw)', (t, done) => {\n  t.plan(2)\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.ready(err => {\n    t.assert.ifError(err)\n    try {\n      fastify.assert.equal(1, '2')\n      t.assert.fail('Should throw')\n    } catch (err) {\n      t.assert.ok(err)\n    }\n    done()\n  })\n})\n\ntest('Should support not equal assert (throw)', (t, done) => {\n  t.plan(2)\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.ready(err => {\n    t.assert.ifError(err)\n    try {\n      fastify.assert.notEqual(1, '1')\n      t.assert.fail('Should throw')\n    } catch (err) {\n      t.assert.ok(err)\n    }\n    done()\n  })\n})\n\ntest('Should support strict equal assert (throw)', (t, done) => {\n  t.plan(2)\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.ready(err => {\n    t.assert.ifError(err)\n    try {\n      fastify.assert.equal(1, 2)\n      t.assert.fail('Should throw')\n    } catch (err) {\n      t.assert.ok(err)\n    }\n    done()\n  })\n})\n\ntest('Should support not strict equal assert (throw)', (t, done) => {\n  t.plan(2)\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.ready(err => {\n    t.assert.ifError(err)\n    try {\n      fastify.assert.notStrictEqual(1, 1)\n      t.assert.fail('Should throw')\n    } catch (err) {\n      t.assert.ok(err)\n    }\n    done()\n  })\n})\n\ntest('Should support deep equal assert (throw)', (t, done) => {\n  t.plan(2)\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.ready(err => {\n    t.assert.ifError(err)\n    try {\n      fastify.assert.deepEqual({ hello: 'world' }, { hello: 'dlrow' })\n      t.assert.fail('Should throw')\n    } catch (err) {\n      t.assert.ok(err)\n    }\n    done()\n  })\n})\n\ntest('Should support not deep equal assert (throw)', (t, done) => {\n  t.plan(2)\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.ready(err => {\n    t.assert.ifError(err)\n    try {\n      fastify.assert.notDeepEqual({ hello: 'world' }, { hello: 'world' })\n      t.assert.fail('Should throw')\n    } catch (err) {\n      t.assert.ok(err)\n    }\n    done()\n  })\n})\n\ntest('Should generate the correct http error', (t, done) => {\n  t.plan(4)\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.ready(err => {\n    t.assert.ifError(err)\n    try {\n      fastify.assert(false, 400, 'Wrong!')\n      t.assert.fail('Should throw')\n    } catch (err) {\n      t.assert.strictEqual(err.message, 'Wrong!')\n      t.assert.strictEqual(err.name, 'BadRequestError')\n      t.assert.strictEqual(err.statusCode, 400)\n    }\n    done()\n  })\n})\n"
  },
  {
    "path": "test/cache-control.test.js",
    "content": "'use strict'\n\nconst { test } = require('node:test')\nconst Fastify = require('fastify')\nconst Sensible = require('../index')\n\ntest('reply.cacheControl API', (t, done) => {\n  t.plan(4)\n\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.get('/', (_req, reply) => {\n    reply.cacheControl('public')\n    reply.send('ok')\n  })\n\n  fastify.inject({\n    method: 'GET',\n    url: '/'\n  }, (err, res) => {\n    t.assert.ifError(err)\n    t.assert.strictEqual(res.statusCode, 200)\n    t.assert.strictEqual(res.headers['cache-control'], 'public')\n    t.assert.strictEqual(res.payload, 'ok')\n    done()\n  })\n})\n\ntest('reply.cacheControl API (multiple values)', (t, done) => {\n  t.plan(4)\n\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.get('/', (_req, reply) => {\n    reply\n      .cacheControl('public')\n      .cacheControl('max-age', 604800)\n      .cacheControl('immutable')\n      .send('ok')\n  })\n\n  fastify.inject({\n    method: 'GET',\n    url: '/'\n  }, (err, res) => {\n    t.assert.ifError(err)\n    t.assert.strictEqual(res.statusCode, 200)\n    t.assert.strictEqual(res.headers['cache-control'], 'public, max-age=604800, immutable')\n    t.assert.strictEqual(res.payload, 'ok')\n    done()\n  })\n})\n\ntest('reply.preventCache API', (t, done) => {\n  t.plan(6)\n\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.get('/', (_req, reply) => {\n    reply.preventCache().send('ok')\n  })\n\n  fastify.inject({\n    method: 'GET',\n    url: '/'\n  }, (err, res) => {\n    t.assert.ifError(err)\n    t.assert.strictEqual(res.statusCode, 200)\n    t.assert.strictEqual(res.headers['cache-control'], 'no-store, max-age=0, private')\n    t.assert.strictEqual(res.headers.pragma, 'no-cache')\n    t.assert.strictEqual(res.headers.expires, '0')\n    t.assert.strictEqual(res.payload, 'ok')\n    done()\n  })\n})\n\ntest('reply.stale API', (t, done) => {\n  t.plan(4)\n\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.get('/', (_req, reply) => {\n    reply.stale('while-revalidate', 42).send('ok')\n  })\n\n  fastify.inject({\n    method: 'GET',\n    url: '/'\n  }, (err, res) => {\n    t.assert.ifError(err)\n    t.assert.strictEqual(res.statusCode, 200)\n    t.assert.strictEqual(res.headers['cache-control'], 'stale-while-revalidate=42')\n    t.assert.strictEqual(res.payload, 'ok')\n    done()\n  })\n})\n\ntest('reply.stale API (multiple values)', (t, done) => {\n  t.plan(4)\n\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.get('/', (_req, reply) => {\n    reply\n      .stale('while-revalidate', 42)\n      .stale('if-error', 1)\n      .send('ok')\n  })\n\n  fastify.inject({\n    method: 'GET',\n    url: '/'\n  }, (err, res) => {\n    t.assert.ifError(err)\n    t.assert.strictEqual(res.statusCode, 200)\n    t.assert.strictEqual(res.headers['cache-control'], 'stale-while-revalidate=42, stale-if-error=1')\n    t.assert.strictEqual(res.payload, 'ok')\n    done()\n  })\n})\n\ntest('reply.stale API (bad value)', (t, done) => {\n  t.plan(5)\n\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.get('/', (_req, reply) => {\n    try {\n      reply.stale('foo', 42).send('ok')\n      t.assert.fail('Should throw')\n    } catch (err) {\n      t.assert.ok(err)\n      reply.send('ok')\n    }\n  })\n\n  fastify.inject({\n    method: 'GET',\n    url: '/'\n  }, (err, res) => {\n    t.assert.ifError(err)\n    t.assert.strictEqual(res.statusCode, 200)\n    t.assert.ok(!res.headers['cache-control'])\n    t.assert.strictEqual(res.payload, 'ok')\n    done()\n  })\n})\n\ntest('reply.revalidate API', (t, done) => {\n  t.plan(4)\n\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.get('/', (_req, reply) => {\n    reply.revalidate().send('ok')\n  })\n\n  fastify.inject({\n    method: 'GET',\n    url: '/'\n  }, (err, res) => {\n    t.assert.ifError(err)\n    t.assert.strictEqual(res.statusCode, 200)\n    t.assert.strictEqual(res.headers['cache-control'], 'max-age=0, must-revalidate')\n    t.assert.strictEqual(res.payload, 'ok')\n    done()\n  })\n})\n\ntest('reply.staticCache API', (t, done) => {\n  t.plan(4)\n\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.get('/', (_req, reply) => {\n    reply.staticCache(42).send('ok')\n  })\n\n  fastify.inject({\n    method: 'GET',\n    url: '/'\n  }, (err, res) => {\n    t.assert.ifError(err)\n    t.assert.strictEqual(res.statusCode, 200)\n    t.assert.strictEqual(res.headers['cache-control'], 'public, max-age=42, immutable')\n    t.assert.strictEqual(res.payload, 'ok')\n    done()\n  })\n})\n\ntest('reply.staticCache API (as string)', (t, done) => {\n  t.plan(4)\n\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.get('/', (_req, reply) => {\n    reply.staticCache('42s').send('ok')\n  })\n\n  fastify.inject({\n    method: 'GET',\n    url: '/'\n  }, (err, res) => {\n    t.assert.ifError(err)\n    t.assert.strictEqual(res.statusCode, 200)\n    t.assert.strictEqual(res.headers['cache-control'], 'public, max-age=42, immutable')\n    t.assert.strictEqual(res.payload, 'ok')\n    done()\n  })\n})\n\ntest('reply.maxAge and reply.stale API', (t, done) => {\n  t.plan(4)\n\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.get('/', (_req, reply) => {\n    reply\n      .maxAge(42)\n      .stale('while-revalidate', 3)\n      .send('ok')\n  })\n\n  fastify.inject({\n    method: 'GET',\n    url: '/'\n  }, (err, res) => {\n    t.assert.ifError(err)\n    t.assert.strictEqual(res.statusCode, 200)\n    t.assert.strictEqual(res.headers['cache-control'], 'max-age=42, stale-while-revalidate=3')\n    t.assert.strictEqual(res.payload, 'ok')\n    done()\n  })\n})\n\ntest('reply.cacheControl API (string time)', (t, done) => {\n  t.plan(4)\n\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.get('/', (_req, reply) => {\n    reply.cacheControl('max-age', '1d')\n    reply.send('ok')\n  })\n\n  fastify.inject({\n    method: 'GET',\n    url: '/'\n  }, (err, res) => {\n    t.assert.ifError(err)\n    t.assert.strictEqual(res.statusCode, 200)\n    t.assert.strictEqual(res.headers['cache-control'], 'max-age=86400')\n    t.assert.strictEqual(res.payload, 'ok')\n    done()\n  })\n})\n"
  },
  {
    "path": "test/forwarded.test.js",
    "content": "'use strict'\n\nconst { test } = require('node:test')\nconst Fastify = require('fastify')\nconst Sensible = require('../index')\n\ntest('request.forwarded API', (t, done) => {\n  t.plan(3)\n\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.get('/', (req, reply) => {\n    reply.send(req.forwarded())\n  })\n\n  fastify.inject({\n    method: 'GET',\n    url: '/',\n    headers: {\n      'x-forwarded-for': '10.0.0.2, 10.0.0.1'\n    }\n  }, (err, res) => {\n    t.assert.ifError(err)\n    t.assert.strictEqual(res.statusCode, 200)\n    t.assert.deepStrictEqual(\n      JSON.parse(res.payload),\n      ['127.0.0.1', '10.0.0.1', '10.0.0.2']\n    )\n    done()\n  })\n})\n\ntest('request.forwarded API (without header)', (t, done) => {\n  t.plan(3)\n\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.get('/', (req, reply) => {\n    reply.send(req.forwarded())\n  })\n\n  fastify.inject({\n    method: 'GET',\n    url: '/'\n  }, (err, res) => {\n    t.assert.ifError(err)\n    t.assert.strictEqual(res.statusCode, 200)\n    t.assert.deepStrictEqual(\n      JSON.parse(res.payload),\n      ['127.0.0.1']\n    )\n    done()\n  })\n})\n"
  },
  {
    "path": "test/httpErrors.test.js",
    "content": "'use strict'\n\nconst { test } = require('node:test')\nconst createError = require('http-errors')\nconst statusCodes = require('node:http').STATUS_CODES\nconst Fastify = require('fastify')\nconst Sensible = require('../index')\nconst HttpError = require('../lib/httpErrors').HttpError\n\ntest('Should generate the correct http error', (t, done) => {\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.ready(err => {\n    t.assert.ifError(err)\n\n    Object.keys(statusCodes).forEach(code => {\n      if (Number(code) < 400) return\n      const name = normalize(code, statusCodes[code])\n      const err = fastify.httpErrors[name]()\n      t.assert.ok(err instanceof HttpError)\n      // `statusCodes` uses the capital T\n      if (err.message === 'I\\'m a Teapot') {\n        t.assert.strictEqual(err.statusCode, 418)\n      } else {\n        t.assert.strictEqual(err.message, statusCodes[code])\n      }\n      t.assert.strictEqual(typeof err.name, 'string')\n      t.assert.strictEqual(err.statusCode, Number(code))\n    })\n\n    done()\n  })\n})\n\ntest('Should expose the createError method from http-errors', (t, done) => {\n  t.plan(2)\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.ready(err => {\n    t.assert.ifError(err)\n    t.assert.strictEqual(fastify.httpErrors.createError, createError)\n    done()\n  })\n})\n\ntest('Should generate the correct error using the properties given', (t, done) => {\n  t.plan(5)\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.ready(err => {\n    t.assert.ifError(err)\n    const customError = fastify.httpErrors.createError(404, 'This video does not exist!')\n    t.assert.ok(customError instanceof HttpError)\n    t.assert.strictEqual(customError.message, 'This video does not exist!')\n    t.assert.strictEqual(typeof customError.name, 'string')\n    t.assert.strictEqual(customError.statusCode, 404)\n    done()\n  })\n})\n\ntest('Should generate the correct http error (with custom message)', (t, done) => {\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.ready(err => {\n    t.assert.ifError(err)\n\n    Object.keys(statusCodes).forEach(code => {\n      if (Number(code) < 400) return\n      const name = normalize(code, statusCodes[code])\n      const err = fastify.httpErrors[name]('custom')\n      t.assert.ok(err instanceof HttpError)\n      t.assert.strictEqual(err.message, 'custom')\n      t.assert.strictEqual(typeof err.name, 'string')\n      t.assert.strictEqual(err.statusCode, Number(code))\n    })\n\n    done()\n  })\n})\n\ntest('should throw error', (t) => {\n  const err = Sensible.httpErrors.conflict('custom')\n  t.assert.strictEqual(err.message, 'custom')\n})\n\nfunction normalize (code, msg) {\n  if (code === '414') return 'uriTooLong'\n  if (code === '418') return 'imateapot'\n  if (code === '505') return 'httpVersionNotSupported'\n  msg = msg.split(' ').join('').replace(/'/g, '')\n  msg = msg[0].toLowerCase() + msg.slice(1)\n  return msg\n}\n"
  },
  {
    "path": "test/httpErrorsReply.test.js",
    "content": "'use strict'\n\nconst { test } = require('node:test')\nconst statusCodes = require('node:http').STATUS_CODES\nconst Fastify = require('fastify')\nconst Sensible = require('../index')\n\ntest('Should generate the correct http error', (t, rootDone) => {\n  const codes = Object.keys(statusCodes).filter(code => Number(code) >= 400 && code !== '418')\n  let completedTests = 0\n\n  codes.forEach(code => {\n    t.test(code, (t, done) => {\n      t.plan(4)\n      const fastify = Fastify()\n      fastify.register(Sensible)\n\n      fastify.get('/', (_req, reply) => {\n        const name = normalize(code, statusCodes[code])\n        t.assert.strictEqual(reply[name](), reply)\n      })\n\n      fastify.inject({\n        method: 'GET',\n        url: '/'\n      }, (err, res) => {\n        t.assert.ifError(err)\n        t.assert.strictEqual(res.statusCode, Number(code))\n        if (code === '425') {\n          t.assert.deepStrictEqual(JSON.parse(res.payload), {\n            error: 'Too Early',\n            message: 'Too Early',\n            statusCode: 425\n          })\n        } else {\n          t.assert.deepStrictEqual(JSON.parse(res.payload), {\n            error: statusCodes[code],\n            message: statusCodes[code],\n            statusCode: Number(code)\n          })\n        }\n        done()\n        completedTests++\n\n        if (completedTests === codes.length) {\n          rootDone()\n        }\n      })\n    })\n  })\n})\n\ntest('Should generate the correct http error using getter', (t, rootDone) => {\n  const codes = Object.keys(statusCodes).filter(code => Number(code) >= 400 && code !== '418')\n  let completedTests = 0\n\n  codes.forEach(code => {\n    t.test(code, (t, done) => {\n      t.plan(4)\n      const fastify = Fastify()\n      fastify.register(Sensible)\n\n      fastify.get('/', (_req, reply) => {\n        t.assert.strictEqual(reply.getHttpError(code), reply)\n      })\n\n      fastify.inject({\n        method: 'GET',\n        url: '/'\n      }, (err, res) => {\n        t.assert.ifError(err)\n        t.assert.strictEqual(res.statusCode, Number(code))\n        t.assert.deepStrictEqual(JSON.parse(res.payload), {\n          error: statusCodes[code],\n          message: statusCodes[code],\n          statusCode: Number(code)\n        })\n        done()\n        completedTests++\n\n        if (completedTests === codes.length) {\n          rootDone()\n        }\n      })\n    })\n  })\n})\n\ntest('Should generate the correct http error (with custom message)', (t, rootDone) => {\n  const codes = Object.keys(statusCodes).filter(code => Number(code) >= 400 && code !== '418')\n  let completedTests = 0\n\n  codes.forEach(code => {\n    t.test(code, (t, done) => {\n      t.plan(3)\n      const fastify = Fastify()\n      fastify.register(Sensible)\n\n      fastify.get('/', (_req, reply) => {\n        const name = normalize(code, statusCodes[code])\n        reply[name]('custom')\n      })\n\n      fastify.inject({\n        method: 'GET',\n        url: '/'\n      }, (err, res) => {\n        t.assert.ifError(err)\n        t.assert.strictEqual(res.statusCode, Number(code))\n        t.assert.deepStrictEqual(JSON.parse(res.payload), {\n          error: statusCodes[code],\n          message: 'custom',\n          statusCode: Number(code)\n        })\n        done()\n        completedTests++\n\n        if (completedTests === codes.length) {\n          rootDone()\n        }\n      })\n    })\n  })\n})\n\nfunction normalize (code, msg) {\n  if (code === '414') return 'uriTooLong'\n  if (code === '505') return 'httpVersionNotSupported'\n  msg = msg.split(' ').join('').replace(/'/g, '')\n  msg = msg[0].toLowerCase() + msg.slice(1)\n  return msg\n}\n"
  },
  {
    "path": "test/is.test.js",
    "content": "'use strict'\n\nconst { test } = require('node:test')\nconst Fastify = require('fastify')\nconst Sensible = require('../index')\n\ntest('request.is API', (t, done) => {\n  t.plan(3)\n\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.get('/', (req, reply) => {\n    reply.send(req.is('json'))\n  })\n\n  fastify.inject({\n    method: 'GET',\n    url: '/',\n    payload: { foo: 'bar' }\n  }, (err, res) => {\n    t.assert.ifError(err)\n    t.assert.strictEqual(res.statusCode, 200)\n    t.assert.deepStrictEqual(\n      res.payload,\n      'json'\n    )\n    done()\n  })\n})\n\ntest('request.is API (with array)', (t, done) => {\n  t.plan(3)\n\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.get('/', (req, reply) => {\n    reply.send(req.is(['html', 'json']))\n  })\n\n  fastify.inject({\n    method: 'GET',\n    url: '/',\n    payload: { foo: 'bar' }\n  }, (err, res) => {\n    t.assert.ifError(err)\n    t.assert.strictEqual(res.statusCode, 200)\n    t.assert.deepStrictEqual(\n      res.payload,\n      'json'\n    )\n    done()\n  })\n})\n"
  },
  {
    "path": "test/schema.test.js",
    "content": "'use strict'\n\nconst { test } = require('node:test')\nconst statusCodes = require('node:http').STATUS_CODES\nconst Fastify = require('fastify')\nconst Sensible = require('../index')\n\ntest('Should add shared schema', (t, done) => {\n  t.plan(3)\n\n  const fastify = Fastify()\n  fastify.register(Sensible, { sharedSchemaId: 'myError' })\n\n  fastify.get('/', {\n    schema: {\n      response: {\n        400: { $ref: 'myError' }\n      }\n    },\n    handler: (_req, reply) => {\n      reply.badRequest()\n    }\n  })\n\n  fastify.inject({\n    method: 'GET',\n    url: '/'\n  }, (err, res) => {\n    t.assert.ifError(err)\n    t.assert.strictEqual(res.statusCode, 400)\n    t.assert.deepStrictEqual(JSON.parse(res.payload), {\n      error: statusCodes[400],\n      message: statusCodes[400],\n      statusCode: 400\n    })\n    done()\n  })\n})\n"
  },
  {
    "path": "test/to.test.js",
    "content": "'use strict'\n\nconst { test } = require('node:test')\nconst Fastify = require('fastify')\nconst Sensible = require('../index')\n\ntest('Should nicely wrap promises (resolve)', (t, done) => {\n  t.plan(4)\n\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.ready(err => {\n    t.assert.ifError(err)\n\n    fastify.to(promise(true))\n      .then(val => {\n        t.assert.ok(Array.isArray(val))\n        t.assert.ok(!val[0])\n        t.assert.ok(val[1])\n        done()\n      })\n  })\n})\n\ntest('Should nicely wrap promises (reject)', (t, done) => {\n  t.plan(4)\n\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.ready(err => {\n    t.assert.ifError(err)\n\n    fastify.to(promise(false))\n      .then(val => {\n        t.assert.ok(Array.isArray(val))\n        t.assert.ok(val[0])\n        t.assert.ok(!val[1])\n        done()\n      })\n  })\n})\n\nfunction promise (bool) {\n  return new Promise((resolve, reject) => {\n    if (bool) {\n      resolve(true)\n    } else {\n      reject(new Error('kaboom'))\n    }\n  })\n}\n"
  },
  {
    "path": "test/vary.test.js",
    "content": "'use strict'\n\nconst { test, describe } = require('node:test')\nconst Fastify = require('fastify')\nconst Sensible = require('../index')\n\ndescribe('reply.vary API', () => {\n  test('accept string', (t, done) => {\n    t.plan(4)\n\n    const fastify = Fastify()\n    fastify.register(Sensible)\n\n    fastify.get('/', (_req, reply) => {\n      reply.vary('Accept')\n      reply.vary('Origin')\n      reply.vary('User-Agent')\n      reply.send('ok')\n    })\n\n    fastify.inject({\n      method: 'GET',\n      url: '/'\n    }, (err, res) => {\n      t.assert.ifError(err)\n      t.assert.strictEqual(res.statusCode, 200)\n      t.assert.strictEqual(res.headers.vary, 'Accept, Origin, User-Agent')\n      t.assert.strictEqual(res.payload, 'ok')\n      done()\n    })\n  })\n\n  test('accept array of strings', (t, done) => {\n    t.plan(4)\n\n    const fastify = Fastify()\n    fastify.register(Sensible)\n\n    fastify.get('/', (_req, reply) => {\n      reply.header('Vary', ['Accept', 'Origin'])\n      reply.vary('User-Agent')\n      reply.send('ok')\n    })\n\n    fastify.inject({\n      method: 'GET',\n      url: '/'\n    }, (err, res) => {\n      t.assert.ifError(err)\n      t.assert.strictEqual(res.statusCode, 200)\n      t.assert.strictEqual(res.headers.vary, 'Accept, Origin, User-Agent')\n      t.assert.strictEqual(res.payload, 'ok')\n      done()\n    })\n  })\n})\n\ntest('reply.vary.append API', (t, done) => {\n  t.plan(4)\n\n  const fastify = Fastify()\n  fastify.register(Sensible)\n\n  fastify.get('/', (_req, reply) => {\n    t.assert.strictEqual(\n      reply.vary.append('', ['Accept', 'Accept-Language']), 'Accept, Accept-Language'\n    )\n    reply.send('ok')\n  })\n\n  fastify.inject({\n    method: 'GET',\n    url: '/'\n  }, (err, res) => {\n    t.assert.ifError(err)\n    t.assert.strictEqual(res.statusCode, 200)\n    t.assert.strictEqual(res.payload, 'ok')\n    done()\n  })\n})\n"
  },
  {
    "path": "types/index.d.ts",
    "content": "import { FastifyPluginCallback, FastifyReply } from 'fastify'\nimport { HttpErrors, HttpError } from '../lib/httpError'\nimport * as Errors from '../lib/httpError'\n\ntype FastifySensible = FastifyPluginCallback<fastifySensible.FastifySensibleOptions>\n\ntype singleValueTypes =\n  | 'must-revalidate'\n  | 'no-cache'\n  | 'no-store'\n  | 'no-transform'\n  | 'public'\n  | 'private'\n  | 'proxy-revalidate'\n  | 'immutable'\n\ntype multiValueTypes =\n  | 'max-age'\n  | 's-maxage'\n  | 'stale-while-revalidate'\n  | 'stale-if-error'\n\ntype staleTypes = 'while-revalidate' | 'if-error'\n\ndeclare module 'fastify' {\n  namespace SensibleTypes {\n    type ToType<T> = [Error, T]\n  }\n\n  interface Assert {\n    (condition: unknown, code: number, message?: string): asserts condition;\n    ok(condition: unknown, code: number, message?: string): asserts condition;\n    equal(a: unknown, b: unknown, code: number, message?: string): void;\n    notEqual(a: unknown, b: unknown, code: number, message?: string): void;\n    strictEqual<T>(a: unknown, b: T, code: number, message?: string): asserts a is T;\n    notStrictEqual(a: unknown, b: unknown, code: number, message?: string): void;\n    deepEqual(a: unknown, b: unknown, code: number, message?: string): void;\n    notDeepEqual(a: unknown, b: unknown, code: number, message?: string): void;\n  }\n\n  interface FastifyInstance {\n    assert: Assert;\n    to<T>(to: Promise<T>): Promise<SensibleTypes.ToType<T>>;\n    httpErrors: HttpErrors;\n  }\n\n  interface FastifyReply extends fastifySensible.HttpErrorReplys {\n    vary: {\n      (field: string | string[]): void;\n      append: (header: string, field: string | string[]) => string;\n    };\n    cacheControl(type: singleValueTypes): this\n    cacheControl(type: multiValueTypes, time: number | string): this\n    preventCache(): this\n    maxAge(type: number | string): this\n    revalidate(): this\n    staticCache(time: number | string): this\n    stale(type: staleTypes, time: number | string): this\n  }\n\n  interface FastifyRequest {\n    forwarded(): string[];\n    is(types: Array<string>): string | false | null;\n    is(...types: Array<string>): string | false | null;\n  }\n}\n\ndeclare namespace fastifySensible {\n  export interface FastifySensibleOptions {\n    /**\n     * This option registers a shared JSON Schema to be used by all response schemas.\n     *\n     * @example\n     * ```js\n     * fastify.register(require('@fastify/sensible'), {\n     *   sharedSchemaId: 'HttpError'\n     * })\n     *\n     * fastify.get('/async', {\n     *   schema: {\n     *     response: { 404: { $ref: 'HttpError' } }\n     *   }\n     *   handler: async (req, reply) => {\n     *     return reply.notFound()\n     *   }\n     * })\n     * ```\n     */\n    sharedSchemaId?: string | undefined;\n  }\n\n  export { HttpError }\n\n  export type HttpErrors = Errors.HttpErrors\n  export type HttpErrorCodes = Errors.HttpErrorCodes\n  export type HttpErrorCodesLoose = Errors.HttpErrorCodesLoose\n  export type HttpErrorNames = Errors.HttpErrorNames\n  export type HttpErrorTypes = Errors.HttpErrorTypes\n\n  export const httpErrors: typeof Errors.default\n\n  export type HttpErrorReplys = {\n    getHttpError: (code: HttpErrorCodesLoose, message?: string) => FastifyReply;\n  } & {\n    [Property in keyof HttpErrorTypes]: (msg?: string) => FastifyReply\n  }\n\n  export const fastifySensible: FastifySensible\n  export { fastifySensible as default }\n}\n\ndeclare function fastifySensible (...params: Parameters<FastifySensible>): ReturnType<FastifySensible>\nexport = fastifySensible\n"
  },
  {
    "path": "types/index.test-d.ts",
    "content": "import { expectType, expectAssignable, expectError, expectNotAssignable } from 'tsd'\nimport fastify from 'fastify'\nimport fastifySensible, { FastifySensibleOptions, httpErrors, HttpError } from '..'\n\nconst app = fastify()\n\napp.register(fastifySensible)\n\nexpectAssignable<FastifySensibleOptions>({})\nexpectAssignable<FastifySensibleOptions>({ sharedSchemaId: 'HttpError' })\nexpectAssignable<FastifySensibleOptions>({ sharedSchemaId: undefined })\nexpectNotAssignable<FastifySensibleOptions>({ notSharedSchemaId: 'HttpError' })\n\napp.get('/', (_req, reply) => {\n  expectAssignable<typeof reply>(reply.badRequest())\n  expectAssignable<typeof reply>(reply.unauthorized())\n  expectAssignable<typeof reply>(reply.paymentRequired())\n  expectAssignable<typeof reply>(reply.forbidden())\n  expectAssignable<typeof reply>(reply.notFound())\n  expectAssignable<typeof reply>(reply.methodNotAllowed())\n  expectAssignable<typeof reply>(reply.notAcceptable())\n  expectAssignable<typeof reply>(reply.proxyAuthenticationRequired())\n  expectAssignable<typeof reply>(reply.requestTimeout())\n  expectAssignable<typeof reply>(reply.gone())\n  expectAssignable<typeof reply>(reply.lengthRequired())\n  expectAssignable<typeof reply>(reply.preconditionFailed())\n  expectAssignable<typeof reply>(reply.payloadTooLarge())\n  expectAssignable<typeof reply>(reply.uriTooLong())\n  expectAssignable<typeof reply>(reply.unsupportedMediaType())\n  expectAssignable<typeof reply>(reply.rangeNotSatisfiable())\n  expectAssignable<typeof reply>(reply.expectationFailed())\n  expectAssignable<typeof reply>(reply.imateapot())\n  expectAssignable<typeof reply>(reply.unprocessableEntity())\n  expectAssignable<typeof reply>(reply.locked())\n  expectAssignable<typeof reply>(reply.failedDependency())\n  expectAssignable<typeof reply>(reply.tooEarly())\n  expectAssignable<typeof reply>(reply.upgradeRequired())\n  expectAssignable<typeof reply>(reply.preconditionFailed())\n  expectAssignable<typeof reply>(reply.tooManyRequests())\n  expectAssignable<typeof reply>(reply.requestHeaderFieldsTooLarge())\n  expectAssignable<typeof reply>(reply.unavailableForLegalReasons())\n  expectAssignable<typeof reply>(reply.internalServerError())\n  expectAssignable<typeof reply>(reply.notImplemented())\n  expectAssignable<typeof reply>(reply.badGateway())\n  expectAssignable<typeof reply>(reply.serviceUnavailable())\n  expectAssignable<typeof reply>(reply.gatewayTimeout())\n  expectAssignable<typeof reply>(reply.httpVersionNotSupported())\n  expectAssignable<typeof reply>(reply.variantAlsoNegotiates())\n  expectAssignable<typeof reply>(reply.insufficientStorage())\n  expectAssignable<typeof reply>(reply.loopDetected())\n  expectAssignable<typeof reply>(reply.bandwidthLimitExceeded())\n  expectAssignable<typeof reply>(reply.notExtended())\n  expectAssignable<typeof reply>(reply.networkAuthenticationRequired())\n})\n\napp.get('/', (_req, reply) => {\n  expectAssignable<typeof reply>(reply.getHttpError(405, 'Method Not Allowed'))\n  expectAssignable<typeof reply>(reply.getHttpError('405', 'Method Not Allowed'))\n})\n\napp.get('/', () => {\n  expectAssignable<HttpError>(app.httpErrors.createError(405, 'Method Not Allowed'))\n})\n\napp.get('/', () => {\n  expectAssignable<HttpError>(\n    app.httpErrors.createError(405, 'Method Not Allowed')\n  )\n  expectAssignable<HttpError>(\n    app.httpErrors.createError(405, 'Method Not Allowed')\n  )\n  expectAssignable<HttpError<400>>(app.httpErrors.badRequest())\n})\n\napp.get('/', async () => {\n  expectAssignable<HttpError<400>>(app.httpErrors.badRequest())\n  expectAssignable<HttpError<401>>(app.httpErrors.unauthorized())\n  expectAssignable<HttpError<402>>(app.httpErrors.paymentRequired())\n  expectAssignable<HttpError<403>>(app.httpErrors.forbidden())\n  expectAssignable<HttpError<404>>(app.httpErrors.notFound())\n  expectAssignable<HttpError<405>>(app.httpErrors.methodNotAllowed())\n  expectAssignable<HttpError<406>>(app.httpErrors.notAcceptable())\n  expectAssignable<HttpError<407>>(app.httpErrors.proxyAuthenticationRequired())\n  expectAssignable<HttpError<408>>(app.httpErrors.requestTimeout())\n  expectAssignable<HttpError<410>>(app.httpErrors.gone())\n  expectAssignable<HttpError<411>>(app.httpErrors.lengthRequired())\n  expectAssignable<HttpError<412>>(app.httpErrors.preconditionFailed())\n  expectAssignable<HttpError<413>>(app.httpErrors.payloadTooLarge())\n  expectAssignable<HttpError<414>>(app.httpErrors.uriTooLong())\n  expectAssignable<HttpError<415>>(app.httpErrors.unsupportedMediaType())\n  expectAssignable<HttpError<416>>(app.httpErrors.rangeNotSatisfiable())\n  expectAssignable<HttpError<417>>(app.httpErrors.expectationFailed())\n  expectAssignable<HttpError<418>>(app.httpErrors.imateapot())\n  expectAssignable<HttpError<422>>(app.httpErrors.unprocessableEntity())\n  expectAssignable<HttpError<423>>(app.httpErrors.locked())\n  expectAssignable<HttpError<424>>(app.httpErrors.failedDependency())\n  expectAssignable<HttpError<425>>(app.httpErrors.tooEarly())\n  expectAssignable<HttpError<426>>(app.httpErrors.upgradeRequired())\n  expectAssignable<HttpError<429>>(app.httpErrors.tooManyRequests())\n  expectAssignable<HttpError<431>>(app.httpErrors.requestHeaderFieldsTooLarge())\n  expectAssignable<HttpError<451>>(app.httpErrors.unavailableForLegalReasons())\n  expectAssignable<HttpError<500>>(app.httpErrors.internalServerError())\n  expectAssignable<HttpError<501>>(app.httpErrors.notImplemented())\n  expectAssignable<HttpError<502>>(app.httpErrors.badGateway())\n  expectAssignable<HttpError<503>>(app.httpErrors.serviceUnavailable())\n  expectAssignable<HttpError<504>>(app.httpErrors.gatewayTimeout())\n  expectAssignable<HttpError<505>>(app.httpErrors.httpVersionNotSupported())\n  expectAssignable<HttpError<506>>(app.httpErrors.variantAlsoNegotiates())\n  expectAssignable<HttpError<507>>(app.httpErrors.insufficientStorage())\n  expectAssignable<HttpError<508>>(app.httpErrors.loopDetected())\n  expectAssignable<HttpError<509>>(app.httpErrors.bandwidthLimitExceeded())\n  expectAssignable<HttpError<510>>(app.httpErrors.notExtended())\n  expectAssignable<HttpError<511>>(app.httpErrors.networkAuthenticationRequired())\n})\n\napp.get('/', async () => {\n  expectError(app.assert(true))\n  expectType<void>(app.assert(1, 400, 'Bad number'))\n  expectType<void>(app.assert.ok(true, 400))\n  expectType<void>(app.assert.equal(1, 1, 400))\n  expectType<void>(app.assert.notEqual(1, 2, 400))\n  expectType<void>(app.assert.strictEqual(1, 1, 400))\n  expectType<void>(app.assert.notStrictEqual(1, 2, 400))\n  expectType<void>(app.assert.deepEqual({}, {}, 400))\n  expectType<void>(app.assert.notDeepEqual({}, { a: 1 }, 400))\n})\n\napp.get('/', async () => {\n  expectType<Promise<[Error, void]>>(app.to<void>(new Promise(resolve => resolve())))\n})\n\napp.get('/', (_req, reply) => {\n  expectAssignable<typeof reply>(reply.cacheControl('public'))\n})\n\napp.get('/', (_req, reply) => {\n  expectAssignable<typeof reply>(reply.preventCache())\n})\n\napp.get('/', (_req, reply) => {\n  expectAssignable<typeof reply>(reply.cacheControl('max-age', 42))\n})\n\napp.get('/', (_req, reply) => {\n  expectError(reply.cacheControl('foobar'))\n})\n\napp.get('/', (_req, reply) => {\n  expectAssignable<typeof reply>(reply.stale('while-revalidate', 42))\n})\n\napp.get('/', async (_req, reply) => {\n  expectType<void>(reply.vary('test'))\n  expectType<void>(reply.vary(['test']))\n  expectType<string>(reply.vary.append('X-Header', 'field1'))\n  expectType<string>(reply.vary.append('X-Header', ['field1']))\n})\n\napp.get('/', async (req) => {\n  expectType<string[]>(req.forwarded())\n  expectType<string | false | null>(req.is(['foo', 'bar']))\n  expectType<string | false | null>(req.is('foo', 'bar'))\n})\n\nhttpErrors.forbidden('This type should be also available')\nhttpErrors.createError('MyError')\n"
  }
]