Auto-commit 2026-04-29 16:31
This commit is contained in:
8
node_modules/@fastify/cors/.editorconfig
generated
vendored
Normal file
8
node_modules/@fastify/cors/.editorconfig
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = false
|
||||
insert_final_newline = false
|
||||
5
node_modules/@fastify/cors/.gitattributes
generated
vendored
Normal file
5
node_modules/@fastify/cors/.gitattributes
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# Set the default behavior, in case people don't have core.autocrlf set
|
||||
* text=auto
|
||||
|
||||
# Require Unix line endings
|
||||
* text eol=lf
|
||||
13
node_modules/@fastify/cors/.github/dependabot.yml
generated
vendored
Normal file
13
node_modules/@fastify/cors/.github/dependabot.yml
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
open-pull-requests-limit: 10
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
open-pull-requests-limit: 10
|
||||
21
node_modules/@fastify/cors/.github/stale.yml
generated
vendored
Normal file
21
node_modules/@fastify/cors/.github/stale.yml
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 15
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- "discussion"
|
||||
- "feature request"
|
||||
- "bug"
|
||||
- "help wanted"
|
||||
- "plugin suggestion"
|
||||
- "good first issue"
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
||||
33
node_modules/@fastify/cors/.github/workflows/ci.yml
generated
vendored
Normal file
33
node_modules/@fastify/cors/.github/workflows/ci.yml
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- next
|
||||
- 'v*'
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
|
||||
# This allows a subsequently queued workflow run to interrupt previous runs
|
||||
concurrency:
|
||||
group: "${{ github.workflow }}-${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
uses: fastify/workflows/.github/workflows/plugins-ci.yml@v5
|
||||
with:
|
||||
license-check: true
|
||||
lint: true
|
||||
23
node_modules/@fastify/cors/LICENSE
generated
vendored
Normal file
23
node_modules/@fastify/cors/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018-present The Fastify team
|
||||
|
||||
The Fastify team members are listed at https://github.com/fastify/fastify#team.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
212
node_modules/@fastify/cors/README.md
generated
vendored
Normal file
212
node_modules/@fastify/cors/README.md
generated
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
# @fastify/cors
|
||||
|
||||
[](https://github.com/fastify/fastify-cors/actions/workflows/ci.yml)
|
||||
[](https://www.npmjs.com/package/@fastify/cors)
|
||||
[](https://github.com/neostandard/neostandard)
|
||||
|
||||
`@fastify/cors` enables the use of [CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) in a Fastify application.
|
||||
|
||||
## Install
|
||||
```
|
||||
npm i @fastify/cors
|
||||
```
|
||||
|
||||
### Compatibility
|
||||
|
||||
| Plugin version | Fastify version |
|
||||
| ---------------|-----------------|
|
||||
| `^11.x` | `^5.x` |
|
||||
| `^10.x` | `^5.x` |
|
||||
| `^8.x` | `^4.x` |
|
||||
| `^7.x` | `^3.x` |
|
||||
| `>=3.x <7.x` | `^2.x` |
|
||||
| `>=1.x <3.x` | `^1.x` |
|
||||
|
||||
Please note that if a Fastify version is out of support, then so are the corresponding versions of this plugin
|
||||
in the table above.
|
||||
See [Fastify's LTS policy](https://github.com/fastify/fastify/blob/main/docs/Reference/LTS.md) for more details.
|
||||
|
||||
## Usage
|
||||
Require `@fastify/cors` and register it as any other plugin. It adds an `onRequest` hook and a [wildcard options route](https://github.com/fastify/fastify/issues/326#issuecomment-411360862).
|
||||
```js
|
||||
import Fastify from 'fastify'
|
||||
import cors from '@fastify/cors'
|
||||
|
||||
const fastify = Fastify()
|
||||
await fastify.register(cors, {
|
||||
// put your options here
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
await fastify.listen({ port: 3000 })
|
||||
```
|
||||
You can use it as is without passing any option or you can configure it as explained below.
|
||||
### Options
|
||||
* `origin`: Configures the **Access-Control-Allow-Origin** CORS header. The value of origin can be:
|
||||
- `Boolean`: Set to `true` to reflect the [request origin](http://tools.ietf.org/html/draft-abarth-origin-09), or `false` to disable CORS.
|
||||
- `String`: Set to a specific origin (e.g., `"http://example.com"`). The special `*` value (default) allows any origin.
|
||||
- `RegExp`: Set to a regular expression pattern to test the request origin. If it matches, the request origin is reflected (e.g., `/example\.com$/` returns the origin only if it ends with `example.com`).
|
||||
- `Array`: Set to an array of valid origins, each being a `String` or `RegExp` (e.g., `["http://example1.com", /\.example2\.com$/]`).
|
||||
- `Function`: Set to a function with custom logic. The function takes the request origin as the first parameter and a callback as the second (signature `err [Error | null], origin`). *Async-await* and promises are supported. The Fastify instance is bound to the function call and can be accessed via `this`. For example:
|
||||
```js
|
||||
origin: (origin, cb) => {
|
||||
const hostname = new URL(origin).hostname
|
||||
if(hostname === "localhost"){
|
||||
// Request from localhost will pass
|
||||
cb(null, true)
|
||||
return
|
||||
}
|
||||
// Generate an error on other origins, disabling access
|
||||
cb(new Error("Not allowed"), false)
|
||||
}
|
||||
```
|
||||
* `methods`: Configures the **Access-Control-Allow-Methods** CORS header. Expects a comma-delimited string (e.g., 'GET,HEAD,POST') or an array (e.g., `['GET', 'HEAD', 'POST']`). Default: [CORS-safelisted methods](https://fetch.spec.whatwg.org/#methods) `GET,HEAD,POST`.
|
||||
* `hook`: See [Custom Fastify hook name](#custom-fastify-hook-name). Default: `onRequest`.
|
||||
* `allowedHeaders`: Configures the **Access-Control-Allow-Headers** CORS header. Expects a comma-delimited string (e.g., `'Content-Type,Authorization'`) or an array (e.g., `['Content-Type', 'Authorization']`). Defaults to reflecting the headers specified in the request's **Access-Control-Request-Headers** header if not specified.
|
||||
* `exposedHeaders`: Configures the **Access-Control-Expose-Headers** CORS header. Expects a comma-delimited string (e.g., `'Content-Range,X-Content-Range'`) or an array (e.g., `['Content-Range', 'X-Content-Range']`). No custom headers are exposed if not specified.
|
||||
* `credentials`: Configures the **Access-Control-Allow-Credentials** CORS header. Set to `true` to pass the header; otherwise, it is omitted.
|
||||
* `maxAge`: Configures the **Access-Control-Max-Age** CORS header in seconds. Set to an integer to pass the header; otherwise, it is omitted.
|
||||
* `cacheControl`: Configures the **Cache-Control** header for CORS preflight responses. Set to an integer to pass the header as `Cache-Control: max-age=${cacheControl}`, or set to a string to pass the header as `Cache-Control: ${cacheControl}`. Otherwise, the header is omitted.
|
||||
* `preflightContinue`: Passes the CORS preflight response to the route handler. Default: `false`.
|
||||
* `optionsSuccessStatus`: Provides a status code for successful `OPTIONS` requests, as some legacy browsers (IE11, various SmartTVs) choke on `204`.
|
||||
* `preflight`: Disables preflight by passing `false`. Default: `true`.
|
||||
* `strictPreflight`: Enforces strict requirements for the CORS preflight request headers (**Access-Control-Request-Method** and **Origin**) as defined by the [W3C CORS specification](https://www.w3.org/TR/2020/SPSD-cors-20200602/#resource-preflight-requests). Preflight requests without the required headers result in 400 errors when set to `true`. Default: `true`.
|
||||
* `hideOptionsRoute`: Hides the options route from documentation built using [@fastify/swagger](https://github.com/fastify/fastify-swagger). Default: `true`.
|
||||
* `logLevel`: Sets the Fastify log level **only** for the internal CORS pre-flight `OPTIONS *` route.
|
||||
Pass `'silent'` to suppress these requests in your logs, or any valid Fastify
|
||||
log level (`'trace'`, `'debug'`, `'info'`, `'warn'`, `'error'`, `'fatal'`).
|
||||
Default: inherits Fastify’s global log level.
|
||||
|
||||
#### :warning: DoS attacks
|
||||
|
||||
Using `RegExp` or a `function` for the `origin` parameter may enable Denial of Service attacks.
|
||||
Craft with extreme care.
|
||||
|
||||
### Configuring CORS Asynchronously
|
||||
|
||||
```js
|
||||
const fastify = require('fastify')()
|
||||
|
||||
fastify.register(require('@fastify/cors'), (instance) => {
|
||||
return (req, callback) => {
|
||||
const corsOptions = {
|
||||
// This is NOT recommended for production as it enables reflection exploits
|
||||
origin: true
|
||||
};
|
||||
|
||||
// do not include CORS headers for requests from localhost
|
||||
if (/^localhost$/m.test(req.headers.origin)) {
|
||||
corsOptions.origin = false
|
||||
}
|
||||
|
||||
// callback expects two parameters: error and options
|
||||
callback(null, corsOptions)
|
||||
}
|
||||
})
|
||||
|
||||
fastify.register(async function (fastify) {
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
})
|
||||
|
||||
fastify.listen({ port: 3000 })
|
||||
```
|
||||
|
||||
### Route-Level CORS Overrides
|
||||
|
||||
It is possible to override the CORS plugin options provided during registration on a per-route basis using the `config.cors` option.
|
||||
|
||||
```js
|
||||
const fastify = require('fastify')()
|
||||
|
||||
fastify.register(require('@fastify/cors'), { origin: 'https://example.com' })
|
||||
|
||||
fastify.get('/cors-enabled', (_req, reply) => {
|
||||
reply.send('CORS headers applied')
|
||||
})
|
||||
|
||||
fastify.get('/cors-allow-all', {
|
||||
config: {
|
||||
cors: {
|
||||
origin: '*', // Allow all origins for this route
|
||||
},
|
||||
},
|
||||
}, (_req, reply) => {
|
||||
reply.send('Custom CORS headers applied')
|
||||
})
|
||||
|
||||
fastify.get('/cors-disabled', {
|
||||
config: {
|
||||
cors: false, // Disable CORS for this route
|
||||
},
|
||||
}, (_req, reply) => {
|
||||
reply.send('No CORS headers')
|
||||
})
|
||||
|
||||
fastify.listen({ port: 3000 })
|
||||
```
|
||||
|
||||
### Custom Fastify hook name
|
||||
|
||||
By default, `@fastify/cors` adds an `onRequest` hook for validation and header injection. This can be customized by passing `hook` in the options. Valid values are `onRequest`, `preParsing`, `preValidation`, `preHandler`, `preSerialization`, and `onSend`.
|
||||
|
||||
```js
|
||||
import Fastify from 'fastify'
|
||||
import cors from '@fastify/cors'
|
||||
|
||||
const fastify = Fastify()
|
||||
await fastify.register(cors, {
|
||||
hook: 'preHandler',
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
await fastify.listen({ port: 3000 })
|
||||
```
|
||||
|
||||
To configure CORS asynchronously, provide an object with the `delegator` key:
|
||||
|
||||
```js
|
||||
const fastify = require('fastify')()
|
||||
|
||||
fastify.register(require('@fastify/cors'), {
|
||||
hook: 'preHandler',
|
||||
delegator: (req, callback) => {
|
||||
const corsOptions = {
|
||||
// This is NOT recommended for production as it enables reflection exploits
|
||||
origin: true
|
||||
};
|
||||
|
||||
// do not include CORS headers for requests from localhost
|
||||
if (/^localhost$/m.test(req.headers.origin)) {
|
||||
corsOptions.origin = false
|
||||
}
|
||||
|
||||
// callback expects two parameters: error and options
|
||||
callback(null, corsOptions)
|
||||
},
|
||||
})
|
||||
|
||||
fastify.register(async function (fastify) {
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
})
|
||||
|
||||
fastify.listen({ port: 3000 })
|
||||
```
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
The code is a port for Fastify of [`expressjs/cors`](https://github.com/expressjs/cors).
|
||||
|
||||
## License
|
||||
|
||||
Licensed under [MIT](./LICENSE).<br/>
|
||||
[`expressjs/cors` license](https://github.com/expressjs/cors/blob/master/LICENSE)
|
||||
17
node_modules/@fastify/cors/bench.js
generated
vendored
Normal file
17
node_modules/@fastify/cors/bench.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
'use strict'
|
||||
|
||||
const fastify = require('fastify')()
|
||||
|
||||
fastify.register((instance, _opts, next) => {
|
||||
instance.register(require('./index'))
|
||||
instance.get('/fastify', (_req, reply) => reply.send('ok'))
|
||||
next()
|
||||
})
|
||||
|
||||
fastify.register((instance, _opts, next) => {
|
||||
instance.use(require('cors')())
|
||||
instance.get('/express', (_req, reply) => reply.send('ok'))
|
||||
next()
|
||||
})
|
||||
|
||||
fastify.listen({ port: 3000 })
|
||||
15
node_modules/@fastify/cors/benchmark/package.json
generated
vendored
Normal file
15
node_modules/@fastify/cors/benchmark/package.json
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "benchmark",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "vary.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"benchmark": "^2.1.4",
|
||||
"vary": "^1.1.2"
|
||||
}
|
||||
}
|
||||
34
node_modules/@fastify/cors/benchmark/vary.js
generated
vendored
Normal file
34
node_modules/@fastify/cors/benchmark/vary.js
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
'use strict'
|
||||
|
||||
const benchmark = require('benchmark')
|
||||
const vary = require('vary')
|
||||
const createAddFieldnameToVary = require('../vary').createAddFieldnameToVary
|
||||
|
||||
const replyMock = (header) => ({
|
||||
getHeader () { return header },
|
||||
setHeader () { },
|
||||
header () { }
|
||||
})
|
||||
|
||||
const addAcceptToVary = createAddFieldnameToVary('Accept')
|
||||
const addWildcardToVary = createAddFieldnameToVary('*')
|
||||
const addAcceptEncodingToVary = createAddFieldnameToVary('Accept-Encoding')
|
||||
const addXFooToVary = createAddFieldnameToVary('X-Foo')
|
||||
|
||||
new benchmark.Suite()
|
||||
.add('vary - field to undefined', function () { vary(replyMock(undefined), 'Accept-Encoding') }, { minSamples: 100 })
|
||||
.add('vary - field to *', function () { vary(replyMock('*'), 'Accept-Encoding') }, { minSamples: 100 })
|
||||
.add('vary - * to field', function () { vary(replyMock('Accept-Encoding'), '*') }, { minSamples: 100 })
|
||||
.add('vary - field to empty', function () { vary(replyMock(''), 'Accept-Encoding') }, { minSamples: 100 })
|
||||
.add('vary - fields string to empty', function () { vary(replyMock(''), 'Accept') }, { minSamples: 100 })
|
||||
.add('vary - field to fields', function () { vary(replyMock('Accept, Accept-Encoding, Accept-Language'), 'X-Foo') }, { minSamples: 100 })
|
||||
|
||||
.add('cors - field to undefined', function () { addAcceptEncodingToVary(replyMock(undefined)) }, { minSamples: 100 })
|
||||
.add('cors - field to *', function () { addAcceptEncodingToVary(replyMock('*')) }, { minSamples: 100 })
|
||||
.add('cors - * to field', function () { addWildcardToVary(replyMock('Accept-Encoding')) }, { minSamples: 100 })
|
||||
.add('cors - field to empty', function () { addAcceptEncodingToVary(replyMock('')) }, { minSamples: 100 })
|
||||
.add('cors - fields string to empty', function () { addAcceptToVary(replyMock('')) }, { minSamples: 100 })
|
||||
.add('cors - field to fields', function () { addXFooToVary(replyMock('Accept, Accept-Encoding, Accept-Language')) }, { minSamples: 100 })
|
||||
|
||||
.on('cycle', function onCycle (event) { console.log(String(event.target)) })
|
||||
.run({ async: false })
|
||||
6
node_modules/@fastify/cors/eslint.config.js
generated
vendored
Normal file
6
node_modules/@fastify/cors/eslint.config.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = require('neostandard')({
|
||||
ignores: require('neostandard').resolveIgnoresFromGitignore(),
|
||||
ts: true
|
||||
})
|
||||
318
node_modules/@fastify/cors/index.js
generated
vendored
Normal file
318
node_modules/@fastify/cors/index.js
generated
vendored
Normal file
@@ -0,0 +1,318 @@
|
||||
'use strict'
|
||||
|
||||
const fp = require('fastify-plugin')
|
||||
const {
|
||||
addAccessControlRequestHeadersToVaryHeader,
|
||||
addOriginToVaryHeader
|
||||
} = require('./vary')
|
||||
|
||||
const defaultOptions = {
|
||||
origin: '*',
|
||||
methods: 'GET,HEAD,POST',
|
||||
hook: 'onRequest',
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 204,
|
||||
credentials: false,
|
||||
exposedHeaders: null,
|
||||
allowedHeaders: null,
|
||||
maxAge: null,
|
||||
preflight: true,
|
||||
strictPreflight: true
|
||||
}
|
||||
|
||||
const validHooks = [
|
||||
'onRequest',
|
||||
'preParsing',
|
||||
'preValidation',
|
||||
'preHandler',
|
||||
'preSerialization',
|
||||
'onSend'
|
||||
]
|
||||
|
||||
const hookWithPayload = [
|
||||
'preSerialization',
|
||||
'preParsing',
|
||||
'onSend'
|
||||
]
|
||||
|
||||
function validateHook (value, next) {
|
||||
if (validHooks.indexOf(value) !== -1) {
|
||||
return
|
||||
}
|
||||
next(new TypeError('@fastify/cors: Invalid hook option provided.'))
|
||||
}
|
||||
|
||||
function fastifyCors (fastify, opts, next) {
|
||||
fastify.decorateRequest('corsPreflightEnabled', false)
|
||||
|
||||
let hideOptionsRoute = true
|
||||
let logLevel
|
||||
|
||||
if (typeof opts === 'function') {
|
||||
handleCorsOptionsDelegator(opts, fastify, { hook: defaultOptions.hook }, next)
|
||||
} else if (opts.delegator) {
|
||||
const { delegator, ...options } = opts
|
||||
handleCorsOptionsDelegator(delegator, fastify, options, next)
|
||||
} else {
|
||||
const corsOptions = normalizeCorsOptions(opts)
|
||||
validateHook(corsOptions.hook, next)
|
||||
if (hookWithPayload.indexOf(corsOptions.hook) !== -1) {
|
||||
fastify.addHook(corsOptions.hook, function handleCors (req, reply, _payload, next) {
|
||||
addCorsHeadersHandler(fastify, corsOptions, req, reply, next)
|
||||
})
|
||||
} else {
|
||||
fastify.addHook(corsOptions.hook, function handleCors (req, reply, next) {
|
||||
addCorsHeadersHandler(fastify, corsOptions, req, reply, next)
|
||||
})
|
||||
}
|
||||
}
|
||||
if (opts.logLevel !== undefined) logLevel = opts.logLevel
|
||||
if (opts.hideOptionsRoute !== undefined) hideOptionsRoute = opts.hideOptionsRoute
|
||||
|
||||
// The preflight reply must occur in the hook. This allows fastify-cors to reply to
|
||||
// preflight requests BEFORE possible authentication plugins. If the preflight reply
|
||||
// occurred in this handler, other plugins may deny the request since the browser will
|
||||
// remove most headers (such as the Authentication header).
|
||||
//
|
||||
// This route simply enables fastify to accept preflight requests.
|
||||
|
||||
fastify.options('*', { schema: { hide: hideOptionsRoute }, logLevel }, (req, reply) => {
|
||||
if (!req.corsPreflightEnabled) {
|
||||
// Do not handle preflight requests if the origin option disabled CORS
|
||||
reply.callNotFound()
|
||||
return
|
||||
}
|
||||
|
||||
reply.send()
|
||||
})
|
||||
|
||||
next()
|
||||
}
|
||||
|
||||
function handleCorsOptionsDelegator (optionsResolver, fastify, opts, next) {
|
||||
const hook = opts?.hook || defaultOptions.hook
|
||||
validateHook(hook, next)
|
||||
if (optionsResolver.length === 2) {
|
||||
if (hookWithPayload.indexOf(hook) !== -1) {
|
||||
fastify.addHook(hook, function handleCors (req, reply, _payload, next) {
|
||||
handleCorsOptionsCallbackDelegator(optionsResolver, fastify, req, reply, next)
|
||||
})
|
||||
} else {
|
||||
fastify.addHook(hook, function handleCors (req, reply, next) {
|
||||
handleCorsOptionsCallbackDelegator(optionsResolver, fastify, req, reply, next)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if (hookWithPayload.indexOf(hook) !== -1) {
|
||||
// handle delegator based on Promise
|
||||
fastify.addHook(hook, function handleCors (req, reply, _payload, next) {
|
||||
const ret = optionsResolver(req)
|
||||
if (ret && typeof ret.then === 'function') {
|
||||
ret.then(options => addCorsHeadersHandler(fastify, normalizeCorsOptions(options, true), req, reply, next)).catch(next)
|
||||
return
|
||||
}
|
||||
next(new Error('Invalid CORS origin option'))
|
||||
})
|
||||
} else {
|
||||
// handle delegator based on Promise
|
||||
fastify.addHook(hook, function handleCors (req, reply, next) {
|
||||
const ret = optionsResolver(req)
|
||||
if (ret && typeof ret.then === 'function') {
|
||||
ret.then(options => addCorsHeadersHandler(fastify, normalizeCorsOptions(options, true), req, reply, next)).catch(next)
|
||||
return
|
||||
}
|
||||
next(new Error('Invalid CORS origin option'))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleCorsOptionsCallbackDelegator (optionsResolver, fastify, req, reply, next) {
|
||||
optionsResolver(req, (err, options) => {
|
||||
if (err) {
|
||||
next(err)
|
||||
} else {
|
||||
addCorsHeadersHandler(fastify, normalizeCorsOptions(options, true), req, reply, next)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('./types').FastifyCorsOptions} opts
|
||||
*/
|
||||
function normalizeCorsOptions (opts, dynamic) {
|
||||
const corsOptions = { ...defaultOptions, ...opts }
|
||||
if (Array.isArray(opts.origin) && opts.origin.indexOf('*') !== -1) {
|
||||
corsOptions.origin = '*'
|
||||
}
|
||||
if (Number.isInteger(corsOptions.cacheControl)) {
|
||||
// integer numbers are formatted this way
|
||||
corsOptions.cacheControl = `max-age=${corsOptions.cacheControl}`
|
||||
} else if (typeof corsOptions.cacheControl !== 'string') {
|
||||
// strings are applied directly and any other value is ignored
|
||||
corsOptions.cacheControl = null
|
||||
}
|
||||
corsOptions.dynamic = dynamic || false
|
||||
return corsOptions
|
||||
}
|
||||
|
||||
function addCorsHeadersHandler (fastify, globalOptions, req, reply, next) {
|
||||
const options = { ...globalOptions, ...req.routeOptions.config?.cors }
|
||||
|
||||
if ((typeof options.origin !== 'string' && options.origin !== false) || options.dynamic) {
|
||||
// Always set Vary header for non-static origin option
|
||||
// https://fetch.spec.whatwg.org/#cors-protocol-and-http-caches
|
||||
addOriginToVaryHeader(reply)
|
||||
}
|
||||
|
||||
const resolveOriginOption = typeof options.origin === 'function' ? resolveOriginWrapper(fastify, options.origin) : (_, cb) => cb(null, options.origin)
|
||||
|
||||
resolveOriginOption(req, (error, resolvedOriginOption) => {
|
||||
if (error !== null) {
|
||||
return next(error)
|
||||
}
|
||||
|
||||
// Disable CORS and preflight if false
|
||||
if (resolvedOriginOption === false) {
|
||||
return next()
|
||||
}
|
||||
|
||||
// Allow routes to disable CORS individually
|
||||
if (req.routeOptions.config?.cors === false) {
|
||||
return next()
|
||||
}
|
||||
|
||||
// Falsy values are invalid
|
||||
if (!resolvedOriginOption) {
|
||||
return next(new Error('Invalid CORS origin option'))
|
||||
}
|
||||
|
||||
addCorsHeaders(req, reply, resolvedOriginOption, options)
|
||||
|
||||
if (req.raw.method === 'OPTIONS' && options.preflight === true) {
|
||||
// Strict mode enforces the required headers for preflight
|
||||
if (options.strictPreflight === true && (!req.headers.origin || !req.headers['access-control-request-method'])) {
|
||||
reply.status(400).type('text/plain').send('Invalid Preflight Request')
|
||||
return
|
||||
}
|
||||
|
||||
req.corsPreflightEnabled = true
|
||||
|
||||
addPreflightHeaders(req, reply, options)
|
||||
|
||||
if (!options.preflightContinue) {
|
||||
// Do not call the hook callback and terminate the request
|
||||
// Safari (and potentially other browsers) need content-length 0,
|
||||
// for 204 or they just hang waiting for a body
|
||||
reply
|
||||
.code(options.optionsSuccessStatus)
|
||||
.header('Content-Length', '0')
|
||||
.send()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return next()
|
||||
})
|
||||
}
|
||||
|
||||
function addCorsHeaders (req, reply, originOption, corsOptions) {
|
||||
const origin = getAccessControlAllowOriginHeader(req.headers.origin, originOption)
|
||||
// In the case of origin not allowed the header is not
|
||||
// written in the response.
|
||||
// https://github.com/fastify/fastify-cors/issues/127
|
||||
if (origin) {
|
||||
reply.header('Access-Control-Allow-Origin', origin)
|
||||
}
|
||||
|
||||
if (corsOptions.credentials) {
|
||||
reply.header('Access-Control-Allow-Credentials', 'true')
|
||||
}
|
||||
|
||||
if (corsOptions.exposedHeaders !== null) {
|
||||
reply.header(
|
||||
'Access-Control-Expose-Headers',
|
||||
Array.isArray(corsOptions.exposedHeaders) ? corsOptions.exposedHeaders.join(', ') : corsOptions.exposedHeaders
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function addPreflightHeaders (req, reply, corsOptions) {
|
||||
reply.header(
|
||||
'Access-Control-Allow-Methods',
|
||||
Array.isArray(corsOptions.methods) ? corsOptions.methods.join(', ') : corsOptions.methods
|
||||
)
|
||||
|
||||
if (corsOptions.allowedHeaders === null) {
|
||||
addAccessControlRequestHeadersToVaryHeader(reply)
|
||||
const reqAllowedHeaders = req.headers['access-control-request-headers']
|
||||
if (reqAllowedHeaders !== undefined) {
|
||||
reply.header('Access-Control-Allow-Headers', reqAllowedHeaders)
|
||||
}
|
||||
} else {
|
||||
reply.header(
|
||||
'Access-Control-Allow-Headers',
|
||||
Array.isArray(corsOptions.allowedHeaders) ? corsOptions.allowedHeaders.join(', ') : corsOptions.allowedHeaders
|
||||
)
|
||||
}
|
||||
|
||||
if (corsOptions.maxAge !== null) {
|
||||
reply.header('Access-Control-Max-Age', String(corsOptions.maxAge))
|
||||
}
|
||||
|
||||
if (corsOptions.cacheControl) {
|
||||
reply.header('Cache-Control', corsOptions.cacheControl)
|
||||
}
|
||||
}
|
||||
|
||||
function resolveOriginWrapper (fastify, origin) {
|
||||
return function (req, cb) {
|
||||
const result = origin.call(fastify, req.headers.origin, cb)
|
||||
|
||||
// Allow for promises
|
||||
if (result && typeof result.then === 'function') {
|
||||
result.then(res => cb(null, res), cb)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getAccessControlAllowOriginHeader (reqOrigin, originOption) {
|
||||
if (typeof originOption === 'string') {
|
||||
// fixed or any origin ('*')
|
||||
return originOption
|
||||
}
|
||||
|
||||
// reflect origin
|
||||
return isRequestOriginAllowed(reqOrigin, originOption) ? reqOrigin : false
|
||||
}
|
||||
|
||||
function isRequestOriginAllowed (reqOrigin, allowedOrigin) {
|
||||
if (Array.isArray(allowedOrigin)) {
|
||||
for (let i = 0; i < allowedOrigin.length; ++i) {
|
||||
if (isRequestOriginAllowed(reqOrigin, allowedOrigin[i])) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
} else if (typeof allowedOrigin === 'string') {
|
||||
return reqOrigin === allowedOrigin
|
||||
} else if (allowedOrigin instanceof RegExp) {
|
||||
allowedOrigin.lastIndex = 0
|
||||
return allowedOrigin.test(reqOrigin)
|
||||
} else {
|
||||
return !!allowedOrigin
|
||||
}
|
||||
}
|
||||
|
||||
const _fastifyCors = fp(fastifyCors, {
|
||||
fastify: '5.x',
|
||||
name: '@fastify/cors'
|
||||
})
|
||||
|
||||
/**
|
||||
* These export configurations enable JS and TS developers
|
||||
* to consumer fastify in whatever way best suits their needs.
|
||||
*/
|
||||
module.exports = _fastifyCors
|
||||
module.exports.fastifyCors = _fastifyCors
|
||||
module.exports.default = _fastifyCors
|
||||
2
node_modules/@fastify/cors/node_modules/fastify-plugin/.gitattributes
generated
vendored
Normal file
2
node_modules/@fastify/cors/node_modules/fastify-plugin/.gitattributes
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Set default behavior to automatically convert line endings
|
||||
* text=auto eol=lf
|
||||
13
node_modules/@fastify/cors/node_modules/fastify-plugin/.github/dependabot.yml
generated
vendored
Normal file
13
node_modules/@fastify/cors/node_modules/fastify-plugin/.github/dependabot.yml
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
open-pull-requests-limit: 10
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
open-pull-requests-limit: 10
|
||||
21
node_modules/@fastify/cors/node_modules/fastify-plugin/.github/stale.yml
generated
vendored
Normal file
21
node_modules/@fastify/cors/node_modules/fastify-plugin/.github/stale.yml
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 15
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- "discussion"
|
||||
- "feature request"
|
||||
- "bug"
|
||||
- "help wanted"
|
||||
- "plugin suggestion"
|
||||
- "good first issue"
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
||||
28
node_modules/@fastify/cors/node_modules/fastify-plugin/.github/workflows/ci.yml
generated
vendored
Normal file
28
node_modules/@fastify/cors/node_modules/fastify-plugin/.github/workflows/ci.yml
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- next
|
||||
- 'v*'
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
uses: fastify/workflows/.github/workflows/plugins-ci.yml@v5
|
||||
with:
|
||||
license-check: true
|
||||
lint: true
|
||||
23
node_modules/@fastify/cors/node_modules/fastify-plugin/LICENSE
generated
vendored
Normal file
23
node_modules/@fastify/cors/node_modules/fastify-plugin/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-present The Fastify team
|
||||
|
||||
The Fastify team members are listed at https://github.com/fastify/fastify#team.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
188
node_modules/@fastify/cors/node_modules/fastify-plugin/README.md
generated
vendored
Normal file
188
node_modules/@fastify/cors/node_modules/fastify-plugin/README.md
generated
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
# fastify-plugin
|
||||
|
||||
[](https://github.com/fastify/fastify-plugin/actions/workflows/ci.yml)
|
||||
[](https://www.npmjs.com/package/fastify-plugin)
|
||||
[](https://github.com/neostandard/neostandard)
|
||||
|
||||
`fastify-plugin` is a plugin helper for [Fastify](https://github.com/fastify/fastify).
|
||||
|
||||
When you build plugins for Fastify and you want them to be accessible in the same context where you require them, you have two ways:
|
||||
1. Use the `skip-override` hidden property
|
||||
2. Use this module
|
||||
|
||||
__Note: the v4.x series of this module covers Fastify v4__
|
||||
__Note: the v2.x & v3.x series of this module covers Fastify v3. For Fastify v2 support, refer to the v1.x series.__
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
npm i fastify-plugin
|
||||
```
|
||||
|
||||
## Usage
|
||||
`fastify-plugin` can do three things for you:
|
||||
- Add the `skip-override` hidden property
|
||||
- Check the bare-minimum version of Fastify
|
||||
- Pass some custom metadata of the plugin to Fastify
|
||||
|
||||
Example using a callback:
|
||||
```js
|
||||
const fp = require('fastify-plugin')
|
||||
|
||||
module.exports = fp(function (fastify, opts, done) {
|
||||
// your plugin code
|
||||
done()
|
||||
})
|
||||
```
|
||||
|
||||
Example using an [async](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) function:
|
||||
```js
|
||||
const fp = require('fastify-plugin')
|
||||
|
||||
// A callback function param is not required for async functions
|
||||
module.exports = fp(async function (fastify, opts) {
|
||||
// Wait for an async function to fulfill promise before proceeding
|
||||
await exampleAsyncFunction()
|
||||
})
|
||||
```
|
||||
|
||||
## Metadata
|
||||
In addition, if you use this module when creating new plugins, you can declare the dependencies, the name, and the expected Fastify version that your plugin needs.
|
||||
|
||||
#### Fastify version
|
||||
If you need to set a bare-minimum version of Fastify for your plugin, just add the [semver](https://semver.org/) range that you need:
|
||||
```js
|
||||
const fp = require('fastify-plugin')
|
||||
|
||||
module.exports = fp(function (fastify, opts, done) {
|
||||
// your plugin code
|
||||
done()
|
||||
}, { fastify: '5.x' })
|
||||
```
|
||||
|
||||
If you need to check the Fastify version only, you can pass just the version string.
|
||||
|
||||
You can check [here](https://github.com/npm/node-semver#ranges) how to define a `semver` range.
|
||||
|
||||
#### Name
|
||||
Fastify uses this option to validate the dependency graph, allowing it to ensure that no name collisions occur and making it possible to perform [dependency checks](https://github.com/fastify/fastify-plugin#dependencies).
|
||||
|
||||
```js
|
||||
const fp = require('fastify-plugin')
|
||||
|
||||
function plugin (fastify, opts, done) {
|
||||
// your plugin code
|
||||
done()
|
||||
}
|
||||
|
||||
module.exports = fp(plugin, {
|
||||
fastify: '5.x',
|
||||
name: 'your-plugin-name'
|
||||
})
|
||||
```
|
||||
|
||||
#### Dependencies
|
||||
You can also check if the `plugins` and `decorators` that your plugin intend to use are present in the dependency graph.
|
||||
> *Note:* This is the point where registering `name` of the plugins become important, because you can reference `plugin` dependencies by their [name](https://github.com/fastify/fastify-plugin#name).
|
||||
```js
|
||||
const fp = require('fastify-plugin')
|
||||
|
||||
function plugin (fastify, opts, done) {
|
||||
// your plugin code
|
||||
done()
|
||||
}
|
||||
|
||||
module.exports = fp(plugin, {
|
||||
fastify: '5.x',
|
||||
decorators: {
|
||||
fastify: ['plugin1', 'plugin2'],
|
||||
reply: ['compress']
|
||||
},
|
||||
dependencies: ['plugin1-name', 'plugin2-name']
|
||||
})
|
||||
```
|
||||
|
||||
#### Encapsulate
|
||||
|
||||
By default, `fastify-plugin` breaks the [encapsulation](https://github.com/fastify/fastify/blob/HEAD/docs/Reference/Encapsulation.md) but you can optionally keep the plugin encapsulated.
|
||||
This allows you to set the plugin's name and validate its dependencies without making the plugin accessible.
|
||||
```js
|
||||
const fp = require('fastify-plugin')
|
||||
|
||||
function plugin (fastify, opts, done) {
|
||||
// the decorator is not accessible outside this plugin
|
||||
fastify.decorate('util', function() {})
|
||||
done()
|
||||
}
|
||||
|
||||
module.exports = fp(plugin, {
|
||||
name: 'my-encapsulated-plugin',
|
||||
fastify: '5.x',
|
||||
decorators: {
|
||||
fastify: ['plugin1', 'plugin2'],
|
||||
reply: ['compress']
|
||||
},
|
||||
dependencies: ['plugin1-name', 'plugin2-name'],
|
||||
encapsulate: true
|
||||
})
|
||||
```
|
||||
|
||||
#### Bundlers and Typescript
|
||||
`fastify-plugin` adds a `.default` and `[name]` property to the passed in function.
|
||||
The type definition would have to be updated to leverage this.
|
||||
|
||||
## Known Issue: TypeScript Contextual Inference
|
||||
|
||||
[Documentation Reference](https://www.typescriptlang.org/docs/handbook/functions.html#inferring-the-types)
|
||||
|
||||
It is common for developers to inline their plugin with fastify-plugin such as:
|
||||
|
||||
```js
|
||||
fp((fastify, opts, done) => { done() })
|
||||
fp(async (fastify, opts) => { return })
|
||||
```
|
||||
|
||||
TypeScript can sometimes infer the types of the arguments for these functions. Plugins in Fastify are recommended to be typed using either `FastifyPluginCallback` or `FastifyPluginAsync`. These two definitions only differ in two ways:
|
||||
|
||||
1. The third argument `done` (the callback part)
|
||||
2. The return type `FastifyPluginCallback` or `FastifyPluginAsync`
|
||||
|
||||
At this time, TypeScript inference is not smart enough to differentiate by definition argument length alone.
|
||||
|
||||
Thus, if you are a TypeScript developer please use on the following patterns instead:
|
||||
|
||||
```ts
|
||||
// Callback
|
||||
|
||||
// Assign type directly
|
||||
const pluginCallback: FastifyPluginCallback = (fastify, options, done) => { }
|
||||
fp(pluginCallback)
|
||||
|
||||
// or define your own function declaration that satisfies the existing definitions
|
||||
const pluginCallbackWithTypes = (fastify: FastifyInstance, options: FastifyPluginOptions, done: (error?: FastifyError) => void): void => { }
|
||||
fp(pluginCallbackWithTypes)
|
||||
// or inline
|
||||
fp((fastify: FastifyInstance, options: FastifyPluginOptions, done: (error?: FastifyError) => void): void => { })
|
||||
|
||||
// Async
|
||||
|
||||
// Assign type directly
|
||||
const pluginAsync: FastifyPluginAsync = async (fastify, options) => { }
|
||||
fp(pluginAsync)
|
||||
|
||||
// or define your own function declaration that satisfies the existing definitions
|
||||
const pluginAsyncWithTypes = async (fastify: FastifyInstance, options: FastifyPluginOptions): Promise<void> => { }
|
||||
fp(pluginAsyncWithTypes)
|
||||
// or inline
|
||||
fp(async (fastify: FastifyInstance, options: FastifyPluginOptions): Promise<void> => { })
|
||||
```
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
This project is kindly sponsored by:
|
||||
- [nearForm](https://nearform.com)
|
||||
- [LetzDoIt](https://www.letzdoitapp.com/)
|
||||
|
||||
## License
|
||||
|
||||
Licensed under [MIT](./LICENSE).
|
||||
6
node_modules/@fastify/cors/node_modules/fastify-plugin/eslint.config.js
generated
vendored
Normal file
6
node_modules/@fastify/cors/node_modules/fastify-plugin/eslint.config.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = require('neostandard')({
|
||||
ignores: require('neostandard').resolveIgnoresFromGitignore(),
|
||||
ts: true
|
||||
})
|
||||
25
node_modules/@fastify/cors/node_modules/fastify-plugin/lib/getPluginName.js
generated
vendored
Normal file
25
node_modules/@fastify/cors/node_modules/fastify-plugin/lib/getPluginName.js
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
'use strict'
|
||||
|
||||
const fpStackTracePattern = /at\s(?:.*\.)?plugin\s.*\n\s*(.*)/
|
||||
const fileNamePattern = /(\w*(\.\w*)*)\..*/
|
||||
|
||||
module.exports = function getPluginName (fn) {
|
||||
if (fn.name.length > 0) return fn.name
|
||||
|
||||
const stackTraceLimit = Error.stackTraceLimit
|
||||
Error.stackTraceLimit = 10
|
||||
try {
|
||||
throw new Error('anonymous function')
|
||||
} catch (e) {
|
||||
Error.stackTraceLimit = stackTraceLimit
|
||||
return extractPluginName(e.stack)
|
||||
}
|
||||
}
|
||||
|
||||
function extractPluginName (stack) {
|
||||
const m = stack.match(fpStackTracePattern)
|
||||
|
||||
// get last section of path and match for filename
|
||||
return m ? m[1].split(/[/\\]/).slice(-1)[0].match(fileNamePattern)[1] : 'anonymous'
|
||||
}
|
||||
module.exports.extractPluginName = extractPluginName
|
||||
10
node_modules/@fastify/cors/node_modules/fastify-plugin/lib/toCamelCase.js
generated
vendored
Normal file
10
node_modules/@fastify/cors/node_modules/fastify-plugin/lib/toCamelCase.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = function toCamelCase (name) {
|
||||
if (name[0] === '@') {
|
||||
name = name.slice(1).replace('/', '-')
|
||||
}
|
||||
return name.replace(/-(.)/g, function (match, g1) {
|
||||
return g1.toUpperCase()
|
||||
})
|
||||
}
|
||||
70
node_modules/@fastify/cors/node_modules/fastify-plugin/package.json
generated
vendored
Normal file
70
node_modules/@fastify/cors/node_modules/fastify-plugin/package.json
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"name": "fastify-plugin",
|
||||
"version": "5.1.0",
|
||||
"description": "Plugin helper for Fastify",
|
||||
"main": "plugin.js",
|
||||
"type": "commonjs",
|
||||
"types": "types/plugin.d.ts",
|
||||
"scripts": {
|
||||
"lint": "eslint",
|
||||
"lint:fix": "eslint --fix",
|
||||
"test": "npm run test:unit && npm run test:typescript",
|
||||
"test:unit": "c8 --100 node --test",
|
||||
"test:coverage": "c8 node --test && c8 report --reporter=html",
|
||||
"test:typescript": "tsd"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/fastify/fastify-plugin.git"
|
||||
},
|
||||
"keywords": [
|
||||
"plugin",
|
||||
"helper",
|
||||
"fastify"
|
||||
],
|
||||
"author": "Tomas Della Vedova - @delvedor (http://delved.org)",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Matteo Collina",
|
||||
"email": "hello@matteocollina.com"
|
||||
},
|
||||
{
|
||||
"name": "Manuel Spigolon",
|
||||
"email": "behemoth89@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Aras Abbasi",
|
||||
"email": "aras.abbasi@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Frazer Smith",
|
||||
"email": "frazer.dev@icloud.com",
|
||||
"url": "https://github.com/fdawgs"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/fastify/fastify-plugin/issues"
|
||||
},
|
||||
"homepage": "https://github.com/fastify/fastify-plugin#readme",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fastify"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/fastify"
|
||||
}
|
||||
],
|
||||
"devDependencies": {
|
||||
"@fastify/type-provider-typebox": "^5.1.0",
|
||||
"@types/node": "^24.0.8",
|
||||
"c8": "^10.1.2",
|
||||
"eslint": "^9.17.0",
|
||||
"fastify": "^5.0.0",
|
||||
"neostandard": "^0.12.0",
|
||||
"proxyquire": "^2.1.3",
|
||||
"tsd": "^0.33.0"
|
||||
}
|
||||
}
|
||||
67
node_modules/@fastify/cors/node_modules/fastify-plugin/plugin.js
generated
vendored
Normal file
67
node_modules/@fastify/cors/node_modules/fastify-plugin/plugin.js
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
'use strict'
|
||||
|
||||
const getPluginName = require('./lib/getPluginName')
|
||||
const toCamelCase = require('./lib/toCamelCase')
|
||||
|
||||
let count = 0
|
||||
|
||||
function plugin (fn, options = {}) {
|
||||
let autoName = false
|
||||
|
||||
if (fn.default !== undefined) {
|
||||
// Support for 'export default' behaviour in transpiled ECMAScript module
|
||||
fn = fn.default
|
||||
}
|
||||
|
||||
if (typeof fn !== 'function') {
|
||||
throw new TypeError(
|
||||
`fastify-plugin expects a function, instead got a '${typeof fn}'`
|
||||
)
|
||||
}
|
||||
|
||||
if (typeof options === 'string') {
|
||||
options = {
|
||||
fastify: options
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
typeof options !== 'object' ||
|
||||
Array.isArray(options) ||
|
||||
options === null
|
||||
) {
|
||||
throw new TypeError('The options object should be an object')
|
||||
}
|
||||
|
||||
if (options.fastify !== undefined && typeof options.fastify !== 'string') {
|
||||
throw new TypeError(`fastify-plugin expects a version string, instead got '${typeof options.fastify}'`)
|
||||
}
|
||||
|
||||
if (!options.name) {
|
||||
autoName = true
|
||||
options.name = getPluginName(fn) + '-auto-' + count++
|
||||
}
|
||||
|
||||
fn[Symbol.for('skip-override')] = options.encapsulate !== true
|
||||
fn[Symbol.for('fastify.display-name')] = options.name
|
||||
fn[Symbol.for('plugin-meta')] = options
|
||||
|
||||
// Faux modules support
|
||||
if (!fn.default) {
|
||||
fn.default = fn
|
||||
}
|
||||
|
||||
// TypeScript support for named imports
|
||||
// See https://github.com/fastify/fastify/issues/2404 for more details
|
||||
// The type definitions would have to be update to match this.
|
||||
const camelCase = toCamelCase(options.name)
|
||||
if (!autoName && !fn[camelCase]) {
|
||||
fn[camelCase] = fn
|
||||
}
|
||||
|
||||
return fn
|
||||
}
|
||||
|
||||
module.exports = plugin
|
||||
module.exports.default = plugin
|
||||
module.exports.fastifyPlugin = plugin
|
||||
110
node_modules/@fastify/cors/node_modules/fastify-plugin/test/bundlers.test.js
generated
vendored
Normal file
110
node_modules/@fastify/cors/node_modules/fastify-plugin/test/bundlers.test.js
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const fp = require('../plugin')
|
||||
|
||||
test('webpack removes require.main.filename', t => {
|
||||
const filename = require.main.filename
|
||||
const info = console.info
|
||||
t.after(() => {
|
||||
require.main.filename = filename
|
||||
console.info = info
|
||||
})
|
||||
|
||||
require.main.filename = null
|
||||
|
||||
console.info = function (msg) {
|
||||
t.assert.fail('logged: ' + msg)
|
||||
}
|
||||
|
||||
fp((_fastify, _opts, next) => {
|
||||
next()
|
||||
}, {
|
||||
fastify: '^5.0.0'
|
||||
})
|
||||
})
|
||||
|
||||
test('support faux modules', (t) => {
|
||||
const plugin = fp((_fastify, _opts, next) => {
|
||||
next()
|
||||
})
|
||||
|
||||
t.assert.strictEqual(plugin.default, plugin)
|
||||
})
|
||||
|
||||
test('support faux modules does not override existing default field in babel module', (t) => {
|
||||
const module = {
|
||||
default: (_fastify, _opts, next) => next()
|
||||
}
|
||||
|
||||
module.default.default = 'Existing default field'
|
||||
|
||||
const plugin = fp(module)
|
||||
|
||||
t.assert.strictEqual(plugin.default, 'Existing default field')
|
||||
})
|
||||
|
||||
test('support ts named imports', (t) => {
|
||||
const plugin = fp((_fastify, _opts, next) => {
|
||||
next()
|
||||
}, {
|
||||
name: 'hello'
|
||||
})
|
||||
|
||||
t.assert.strictEqual(plugin.hello, plugin)
|
||||
})
|
||||
|
||||
test('from kebab-case to camelCase', (t) => {
|
||||
const plugin = fp((_fastify, _opts, next) => {
|
||||
next()
|
||||
}, {
|
||||
name: 'hello-world'
|
||||
})
|
||||
|
||||
t.assert.strictEqual(plugin.helloWorld, plugin)
|
||||
})
|
||||
|
||||
test('from @-prefixed named imports', (t) => {
|
||||
const plugin = fp((_fastify, _opts, next) => {
|
||||
next()
|
||||
}, {
|
||||
name: '@hello/world'
|
||||
})
|
||||
|
||||
t.assert.strictEqual(plugin.helloWorld, plugin)
|
||||
})
|
||||
|
||||
test('from @-prefixed named kebab-case to camelCase', (t) => {
|
||||
const plugin = fp((_fastify, _opts, next) => {
|
||||
next()
|
||||
}, {
|
||||
name: '@hello/my-world'
|
||||
})
|
||||
|
||||
t.assert.strictEqual(plugin.helloMyWorld, plugin)
|
||||
})
|
||||
|
||||
test('from kebab-case to camelCase multiple words', (t) => {
|
||||
const plugin = fp((_fastify, _opts, next) => {
|
||||
next()
|
||||
}, {
|
||||
name: 'hello-long-world'
|
||||
})
|
||||
|
||||
t.assert.strictEqual(plugin.helloLongWorld, plugin)
|
||||
})
|
||||
|
||||
test('from kebab-case to camelCase multiple words does not override', (t) => {
|
||||
const fn = (_fastify, _opts, next) => {
|
||||
next()
|
||||
}
|
||||
|
||||
const foobar = {}
|
||||
fn.helloLongWorld = foobar
|
||||
|
||||
const plugin = fp(fn, {
|
||||
name: 'hello-long-world'
|
||||
})
|
||||
|
||||
t.assert.strictEqual(plugin.helloLongWorld, foobar)
|
||||
})
|
||||
67
node_modules/@fastify/cors/node_modules/fastify-plugin/test/checkVersion.test.js
generated
vendored
Normal file
67
node_modules/@fastify/cors/node_modules/fastify-plugin/test/checkVersion.test.js
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const fp = require('../plugin')
|
||||
|
||||
test('checkVersion having require.main.filename', (t) => {
|
||||
const info = console.info
|
||||
t.assert.ok(require.main.filename)
|
||||
t.after(() => {
|
||||
console.info = info
|
||||
})
|
||||
|
||||
console.info = function (msg) {
|
||||
t.assert.fail('logged: ' + msg)
|
||||
}
|
||||
|
||||
fp((_fastify, _opts, next) => {
|
||||
next()
|
||||
}, {
|
||||
fastify: '^5.0.0'
|
||||
})
|
||||
})
|
||||
|
||||
test('checkVersion having no require.main.filename but process.argv[1]', (t) => {
|
||||
const filename = require.main.filename
|
||||
const info = console.info
|
||||
t.after(() => {
|
||||
require.main.filename = filename
|
||||
console.info = info
|
||||
})
|
||||
|
||||
require.main.filename = null
|
||||
|
||||
console.info = function (msg) {
|
||||
t.assert.fail('logged: ' + msg)
|
||||
}
|
||||
|
||||
fp((_fastify, _opts, next) => {
|
||||
next()
|
||||
}, {
|
||||
fastify: '^5.0.0'
|
||||
})
|
||||
})
|
||||
|
||||
test('checkVersion having no require.main.filename and no process.argv[1]', (t) => {
|
||||
const filename = require.main.filename
|
||||
const argv = process.argv
|
||||
const info = console.info
|
||||
t.after(() => {
|
||||
require.main.filename = filename
|
||||
process.argv = argv
|
||||
console.info = info
|
||||
})
|
||||
|
||||
require.main.filename = null
|
||||
process.argv[1] = null
|
||||
|
||||
console.info = function (msg) {
|
||||
t.assert.fail('logged: ' + msg)
|
||||
}
|
||||
|
||||
fp((_fastify, _opts, next) => {
|
||||
next()
|
||||
}, {
|
||||
fastify: '^5.0.0'
|
||||
})
|
||||
})
|
||||
14
node_modules/@fastify/cors/node_modules/fastify-plugin/test/composite.test.js
generated
vendored
Normal file
14
node_modules/@fastify/cors/node_modules/fastify-plugin/test/composite.test.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const fp = require('../plugin')
|
||||
|
||||
test('anonymous function should be named composite.test0', (t) => {
|
||||
t.plan(2)
|
||||
const fn = fp((_fastify, _opts, next) => {
|
||||
next()
|
||||
})
|
||||
|
||||
t.assert.strictEqual(fn[Symbol.for('plugin-meta')].name, 'composite.test-auto-0')
|
||||
t.assert.strictEqual(fn[Symbol.for('fastify.display-name')], 'composite.test-auto-0')
|
||||
})
|
||||
11
node_modules/@fastify/cors/node_modules/fastify-plugin/test/esm/esm.mjs
generated
vendored
Normal file
11
node_modules/@fastify/cors/node_modules/fastify-plugin/test/esm/esm.mjs
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import { test } from 'node:test'
|
||||
import fp from '../../plugin.js'
|
||||
|
||||
test('esm base support', (t) => {
|
||||
fp((_fastify, _opts, next) => {
|
||||
next()
|
||||
}, {
|
||||
fastify: '^5.0.0'
|
||||
})
|
||||
t.assert.ok(true, 'fp function called without throwing an error')
|
||||
})
|
||||
11
node_modules/@fastify/cors/node_modules/fastify-plugin/test/esm/index.test.js
generated
vendored
Normal file
11
node_modules/@fastify/cors/node_modules/fastify-plugin/test/esm/index.test.js
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
'use strict'
|
||||
|
||||
// Node v8 throw a `SyntaxError: Unexpected token import`
|
||||
// even if this branch is never touch in the code,
|
||||
// by using `eval` we can avoid this issue.
|
||||
// eslint-disable-next-line
|
||||
new Function('module', 'return import(module)')('./esm.mjs').catch((err) => {
|
||||
process.nextTick(() => {
|
||||
throw err
|
||||
})
|
||||
})
|
||||
49
node_modules/@fastify/cors/node_modules/fastify-plugin/test/extractPluginName.test.js
generated
vendored
Normal file
49
node_modules/@fastify/cors/node_modules/fastify-plugin/test/extractPluginName.test.js
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const extractPluginName = require('../lib/getPluginName').extractPluginName
|
||||
|
||||
const winStack = `Error: anonymous function
|
||||
at checkName (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\index.js:43:11)
|
||||
at plugin (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\index.js:24:20)
|
||||
at Test.test (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\test\\hello.test.js:9:14)
|
||||
at bound (domain.js:396:14)
|
||||
at Test.runBound (domain.js:409:12)
|
||||
at ret (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\node_modules\\tap\\lib\\test.js:278:21)
|
||||
at Test.main (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\node_modules\\tap\\lib\\test.js:282:7)
|
||||
at writeSubComment (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\node_modules\\tap\\lib\\test.js:371:13)
|
||||
at TAP.writeSubComment (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\node_modules\\tap\\lib\\test.js:403:5)
|
||||
at Test.runBeforeEach (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\node_modules\\tap\\lib\\test.js:370:14)
|
||||
at loop (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\node_modules\\function-loop\\index.js:35:15)
|
||||
at TAP.runBeforeEach (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\node_modules\\tap\\lib\\test.js:683:7)
|
||||
at TAP.processSubtest (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\node_modules\\tap\\lib\\test.js:369:12)
|
||||
at TAP.process (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\node_modules\\tap\\lib\\test.js:306:14)
|
||||
at TAP.sub (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\node_modules\\tap\\lib\\test.js:185:10)
|
||||
at TAP.test (C:\\Users\\leonardo.davinci\\Desktop\\fastify-plugin\\node_modules\\tap\\lib\\test.js:209:17)`
|
||||
|
||||
const nixStack = `Error: anonymous function
|
||||
at checkName (/home/leonardo/desktop/fastify-plugin/index.js:43:11)
|
||||
at plugin (/home/leonardo/desktop/fastify-plugin/index.js:24:20)
|
||||
at Test.test (/home/leonardo/desktop/fastify-plugin/test/this.is.a.test.js:9:14)
|
||||
at bound (domain.js:396:14)
|
||||
at Test.runBound (domain.js:409:12)
|
||||
at ret (/home/leonardo/desktop/fastify-plugin/node_modules/tap/lib/test.js:278:21)
|
||||
at Test.main (/home/leonardo/desktop/fastify-plugin/node_modules/tap/lib/test.js:282:7)
|
||||
at writeSubComment (/home/leonardo/desktop/fastify-plugin/node_modules/tap/lib/test.js:371:13)
|
||||
at TAP.writeSubComment (/home/leonardo/desktop/fastify-plugin/node_modules/tap/lib/test.js:403:5)
|
||||
at Test.runBeforeEach (/home/leonardo/desktop/fastify-plugin/node_modules/tap/lib/test.js:370:14)
|
||||
at loop (/home/leonardo/desktop/fastify-plugin/node_modules/function-loop/index.js:35:15)
|
||||
at TAP.runBeforeEach (/home/leonardo/desktop/fastify-plugin/node_modules/tap/lib/test.js:683:7)
|
||||
at TAP.processSubtest (/home/leonardo/desktop/fastify-plugin/node_modules/tap/lib/test.js:369:12)
|
||||
at TAP.process (/home/leonardo/desktop/fastify-plugin/node_modules/tap/lib/test.js:306:14)
|
||||
at TAP.sub (/home/leonardo/desktop/fastify-plugin/node_modules/tap/lib/test.js:185:10)
|
||||
at TAP.test (/home/leonardo/desktop/fastify-plugin/node_modules/tap/lib/test.js:209:17)`
|
||||
|
||||
const anonymousStack = 'Unable to parse this'
|
||||
|
||||
test('extractPluginName tests', (t) => {
|
||||
t.plan(3)
|
||||
t.assert.strictEqual(extractPluginName(winStack), 'hello.test')
|
||||
t.assert.strictEqual(extractPluginName(nixStack), 'this.is.a.test')
|
||||
t.assert.strictEqual(extractPluginName(anonymousStack), 'anonymous')
|
||||
})
|
||||
15
node_modules/@fastify/cors/node_modules/fastify-plugin/test/mu1tip1e.composite.test.js
generated
vendored
Normal file
15
node_modules/@fastify/cors/node_modules/fastify-plugin/test/mu1tip1e.composite.test.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const fp = require('../plugin')
|
||||
|
||||
test('anonymous function should be named mu1tip1e.composite.test', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const fn = fp((_fastify, _opts, next) => {
|
||||
next()
|
||||
})
|
||||
|
||||
t.assert.strictEqual(fn[Symbol.for('plugin-meta')].name, 'mu1tip1e.composite.test-auto-0')
|
||||
t.assert.strictEqual(fn[Symbol.for('fastify.display-name')], 'mu1tip1e.composite.test-auto-0')
|
||||
})
|
||||
396
node_modules/@fastify/cors/node_modules/fastify-plugin/test/test.js
generated
vendored
Normal file
396
node_modules/@fastify/cors/node_modules/fastify-plugin/test/test.js
generated
vendored
Normal file
@@ -0,0 +1,396 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const proxyquire = require('proxyquire')
|
||||
const fp = require('../plugin')
|
||||
const Fastify = require('fastify')
|
||||
|
||||
const pkg = require('../package.json')
|
||||
|
||||
test('fastify-plugin is a function', (t) => {
|
||||
t.plan(1)
|
||||
t.assert.ok(typeof fp === 'function')
|
||||
})
|
||||
|
||||
test('should return the function with the skip-override Symbol', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
function plugin (_fastify, _opts, next) {
|
||||
next()
|
||||
}
|
||||
|
||||
fp(plugin)
|
||||
t.assert.ok(plugin[Symbol.for('skip-override')])
|
||||
})
|
||||
|
||||
test('should support "default" function from babel module', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const plugin = {
|
||||
default: () => { }
|
||||
}
|
||||
|
||||
try {
|
||||
fp(plugin)
|
||||
t.assert.ok(true)
|
||||
} catch (e) {
|
||||
t.assert.strictEqual(e.message, 'fastify-plugin expects a function, instead got a \'object\'')
|
||||
}
|
||||
})
|
||||
|
||||
test('should throw if the plugin is not a function', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
try {
|
||||
fp('plugin')
|
||||
t.assert.fail()
|
||||
} catch (e) {
|
||||
t.assert.strictEqual(e.message, 'fastify-plugin expects a function, instead got a \'string\'')
|
||||
}
|
||||
})
|
||||
|
||||
test('should check the fastify version', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
function plugin (_fastify, _opts, next) {
|
||||
next()
|
||||
}
|
||||
|
||||
try {
|
||||
fp(plugin, { fastify: '>=0.10.0' })
|
||||
t.assert.ok(true)
|
||||
} catch {
|
||||
t.assert.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('should check the fastify version', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
function plugin (_fastify, _opts, next) {
|
||||
next()
|
||||
}
|
||||
|
||||
try {
|
||||
fp(plugin, '>=0.10.0')
|
||||
t.assert.ok(true)
|
||||
} catch {
|
||||
t.assert.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('the options object should be an object', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
try {
|
||||
fp(() => { }, null)
|
||||
t.assert.fail()
|
||||
} catch (e) {
|
||||
t.assert.strictEqual(e.message, 'The options object should be an object')
|
||||
}
|
||||
|
||||
try {
|
||||
fp(() => { }, [])
|
||||
t.assert.fail()
|
||||
} catch (e) {
|
||||
t.assert.strictEqual(e.message, 'The options object should be an object')
|
||||
}
|
||||
})
|
||||
|
||||
test('should throw if the version number is not a string', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
try {
|
||||
fp(() => { }, { fastify: 12 })
|
||||
t.assert.fail()
|
||||
} catch (e) {
|
||||
t.assert.strictEqual(e.message, 'fastify-plugin expects a version string, instead got \'number\'')
|
||||
}
|
||||
})
|
||||
|
||||
test('Should accept an option object', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const opts = { hello: 'world' }
|
||||
|
||||
function plugin (_fastify, _opts, next) {
|
||||
next()
|
||||
}
|
||||
|
||||
fp(plugin, opts)
|
||||
|
||||
t.assert.ok(plugin[Symbol.for('skip-override')], 'skip-override symbol should be present')
|
||||
t.assert.deepStrictEqual(plugin[Symbol.for('plugin-meta')], opts, 'plugin-meta should match opts')
|
||||
})
|
||||
|
||||
test('Should accept an option object and checks the version', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const opts = { hello: 'world', fastify: '>=0.10.0' }
|
||||
|
||||
function plugin (_fastify, _opts, next) {
|
||||
next()
|
||||
}
|
||||
|
||||
fp(plugin, opts)
|
||||
t.assert.ok(plugin[Symbol.for('skip-override')])
|
||||
t.assert.deepStrictEqual(plugin[Symbol.for('plugin-meta')], opts)
|
||||
})
|
||||
|
||||
test('should set anonymous function name to file it was called from with a counter', (t) => {
|
||||
const fp = proxyquire('../plugin.js', { stubs: {} })
|
||||
|
||||
const fn = fp((_fastify, _opts, next) => {
|
||||
next()
|
||||
})
|
||||
|
||||
t.assert.strictEqual(fn[Symbol.for('plugin-meta')].name, 'test-auto-0')
|
||||
t.assert.strictEqual(fn[Symbol.for('fastify.display-name')], 'test-auto-0')
|
||||
|
||||
const fn2 = fp((_fastify, _opts, next) => {
|
||||
next()
|
||||
})
|
||||
|
||||
t.assert.strictEqual(fn2[Symbol.for('plugin-meta')].name, 'test-auto-1')
|
||||
t.assert.strictEqual(fn2[Symbol.for('fastify.display-name')], 'test-auto-1')
|
||||
})
|
||||
|
||||
test('should set function name if Error.stackTraceLimit is set to 0', (t) => {
|
||||
const stackTraceLimit = Error.stackTraceLimit = 0
|
||||
|
||||
const fp = proxyquire('../plugin.js', { stubs: {} })
|
||||
|
||||
const fn = fp((_fastify, _opts, next) => {
|
||||
next()
|
||||
})
|
||||
|
||||
t.assert.strictEqual(fn[Symbol.for('plugin-meta')].name, 'test-auto-0')
|
||||
t.assert.strictEqual(fn[Symbol.for('fastify.display-name')], 'test-auto-0')
|
||||
|
||||
const fn2 = fp((_fastify, _opts, next) => {
|
||||
next()
|
||||
})
|
||||
|
||||
t.assert.strictEqual(fn2[Symbol.for('plugin-meta')].name, 'test-auto-1')
|
||||
t.assert.strictEqual(fn2[Symbol.for('fastify.display-name')], 'test-auto-1')
|
||||
|
||||
Error.stackTraceLimit = stackTraceLimit
|
||||
})
|
||||
|
||||
test('should set display-name to meta name', (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const functionName = 'superDuperSpecialFunction'
|
||||
|
||||
const fn = fp((_fastify, _opts, next) => next(), {
|
||||
name: functionName
|
||||
})
|
||||
|
||||
t.assert.strictEqual(fn[Symbol.for('plugin-meta')].name, functionName)
|
||||
t.assert.strictEqual(fn[Symbol.for('fastify.display-name')], functionName)
|
||||
})
|
||||
|
||||
test('should preserve fastify version in meta', (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const opts = { hello: 'world', fastify: '>=0.10.0' }
|
||||
|
||||
const fn = fp((_fastify, _opts, next) => next(), opts)
|
||||
|
||||
t.assert.strictEqual(fn[Symbol.for('plugin-meta')].fastify, '>=0.10.0')
|
||||
})
|
||||
|
||||
test('should check fastify dependency graph - plugin', async (t) => {
|
||||
t.plan(1)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(fp((_fastify, _opts, next) => next(), {
|
||||
fastify: '5.x',
|
||||
name: 'plugin1-name'
|
||||
}))
|
||||
|
||||
fastify.register(fp((_fastify, _opts, next) => next(), {
|
||||
fastify: '5.x',
|
||||
name: 'test',
|
||||
dependencies: ['plugin1-name', 'plugin2-name']
|
||||
}))
|
||||
|
||||
await t.assert.rejects(fastify.ready(), { message: "The dependency 'plugin2-name' of plugin 'test' is not registered" })
|
||||
})
|
||||
|
||||
test('should check fastify dependency graph - decorate', async (t) => {
|
||||
t.plan(1)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.decorate('plugin1', fp((_fastify, _opts, next) => next(), {
|
||||
fastify: '5.x',
|
||||
name: 'plugin1-name'
|
||||
}))
|
||||
|
||||
fastify.register(fp((_fastify, _opts, next) => next(), {
|
||||
fastify: '5.x',
|
||||
name: 'test',
|
||||
decorators: { fastify: ['plugin1', 'plugin2'] }
|
||||
}))
|
||||
|
||||
await t.assert.rejects(fastify.ready(), { message: "The decorator 'plugin2' required by 'test' is not present in Fastify" })
|
||||
})
|
||||
|
||||
test('should check fastify dependency graph - decorateReply', async (t) => {
|
||||
t.plan(1)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.decorateReply('plugin1', fp((_fastify, _opts, next) => next(), {
|
||||
fastify: '5.x',
|
||||
name: 'plugin1-name'
|
||||
}))
|
||||
|
||||
fastify.register(fp((_fastify, _opts, next) => next(), {
|
||||
fastify: '5.x',
|
||||
name: 'test',
|
||||
decorators: { reply: ['plugin1', 'plugin2'] }
|
||||
}))
|
||||
|
||||
await t.assert.rejects(fastify.ready(), { message: "The decorator 'plugin2' required by 'test' is not present in Reply" })
|
||||
})
|
||||
|
||||
test('should accept an option to encapsulate', async (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(fp((fastify, _opts, next) => {
|
||||
fastify.decorate('accessible', true)
|
||||
next()
|
||||
}, {
|
||||
name: 'accessible-plugin'
|
||||
}))
|
||||
|
||||
fastify.register(fp((fastify, _opts, next) => {
|
||||
fastify.decorate('alsoAccessible', true)
|
||||
next()
|
||||
}, {
|
||||
name: 'accessible-plugin2',
|
||||
encapsulate: false
|
||||
}))
|
||||
|
||||
fastify.register(fp((fastify, _opts, next) => {
|
||||
fastify.decorate('encapsulated', true)
|
||||
next()
|
||||
}, {
|
||||
name: 'encapsulated-plugin',
|
||||
encapsulate: true
|
||||
}))
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
t.assert.ok(fastify.hasDecorator('accessible'))
|
||||
t.assert.ok(fastify.hasDecorator('alsoAccessible'))
|
||||
t.assert.ok(!fastify.hasDecorator('encapsulated'))
|
||||
})
|
||||
|
||||
test('should check dependencies when encapsulated', async (t) => {
|
||||
t.plan(1)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(fp((_fastify, _opts, next) => next(), {
|
||||
name: 'test',
|
||||
dependencies: ['missing-dependency-name'],
|
||||
encapsulate: true
|
||||
}))
|
||||
|
||||
await t.assert.rejects(fastify.ready(), { message: "The dependency 'missing-dependency-name' of plugin 'test' is not registered" })
|
||||
})
|
||||
|
||||
test(
|
||||
'should check version when encapsulated',
|
||||
{ skip: /\d-.+/.test(pkg.devDependencies.fastify) },
|
||||
async (t) => {
|
||||
t.plan(1)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(fp((_fastify, _opts, next) => next(), {
|
||||
name: 'test',
|
||||
fastify: '<=2.10.0',
|
||||
encapsulate: true
|
||||
}))
|
||||
|
||||
await t.assert.rejects(fastify.ready(), { message: /fastify-plugin: test - expected '<=2.10.0' fastify version, '\d.\d+.\d+' is installed/ })
|
||||
}
|
||||
)
|
||||
|
||||
test('should check decorators when encapsulated', async (t) => {
|
||||
t.plan(1)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.decorate('plugin1', 'foo')
|
||||
|
||||
fastify.register(fp((_fastify, _opts, next) => next(), {
|
||||
fastify: '5.x',
|
||||
name: 'test',
|
||||
encapsulate: true,
|
||||
decorators: { fastify: ['plugin1', 'plugin2'] }
|
||||
}))
|
||||
|
||||
await t.assert.rejects(fastify.ready(), { message: "The decorator 'plugin2' required by 'test' is not present in Fastify" })
|
||||
})
|
||||
|
||||
test('plugin name when encapsulated', async (t) => {
|
||||
t.plan(6)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(function plugin (_instance, _opts, next) {
|
||||
next()
|
||||
})
|
||||
|
||||
fastify.register(fp(getFn('hello'), {
|
||||
fastify: '5.x',
|
||||
name: 'hello',
|
||||
encapsulate: true
|
||||
}))
|
||||
|
||||
fastify.register(function plugin (fastify, _opts, next) {
|
||||
fastify.register(fp(getFn('deep'), {
|
||||
fastify: '5.x',
|
||||
name: 'deep',
|
||||
encapsulate: true
|
||||
}))
|
||||
|
||||
fastify.register(fp(function genericPlugin (fastify, _opts, next) {
|
||||
t.assert.strictEqual(fastify.pluginName, 'deep-deep', 'should be deep-deep')
|
||||
|
||||
fastify.register(fp(getFn('deep-deep-deep'), {
|
||||
fastify: '5.x',
|
||||
name: 'deep-deep-deep',
|
||||
encapsulate: true
|
||||
}))
|
||||
|
||||
fastify.register(fp(getFn('deep-deep -> not-encapsulated-2'), {
|
||||
fastify: '5.x',
|
||||
name: 'not-encapsulated-2'
|
||||
}))
|
||||
|
||||
next()
|
||||
}, {
|
||||
fastify: '5.x',
|
||||
name: 'deep-deep',
|
||||
encapsulate: true
|
||||
}))
|
||||
|
||||
fastify.register(fp(getFn('plugin -> not-encapsulated'), {
|
||||
fastify: '5.x',
|
||||
name: 'not-encapsulated'
|
||||
}))
|
||||
|
||||
next()
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
function getFn (expectedName) {
|
||||
return function genericPlugin (fastify, _opts, next) {
|
||||
t.assert.strictEqual(fastify.pluginName, expectedName, `should be ${expectedName}`)
|
||||
next()
|
||||
}
|
||||
}
|
||||
})
|
||||
24
node_modules/@fastify/cors/node_modules/fastify-plugin/test/toCamelCase.test.js
generated
vendored
Normal file
24
node_modules/@fastify/cors/node_modules/fastify-plugin/test/toCamelCase.test.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const toCamelCase = require('../lib/toCamelCase')
|
||||
|
||||
test('from kebab-case to camelCase', (t) => {
|
||||
t.plan(1)
|
||||
t.assert.strictEqual(toCamelCase('hello-world'), 'helloWorld')
|
||||
})
|
||||
|
||||
test('from @-prefixed named imports', (t) => {
|
||||
t.plan(1)
|
||||
t.assert.strictEqual(toCamelCase('@hello/world'), 'helloWorld')
|
||||
})
|
||||
|
||||
test('from @-prefixed named kebab-case to camelCase', (t) => {
|
||||
t.plan(1)
|
||||
t.assert.strictEqual(toCamelCase('@hello/my-world'), 'helloMyWorld')
|
||||
})
|
||||
|
||||
test('from kebab-case to camelCase multiple words', (t) => {
|
||||
t.plan(1)
|
||||
t.assert.strictEqual(toCamelCase('hello-long-world'), 'helloLongWorld')
|
||||
})
|
||||
19
node_modules/@fastify/cors/node_modules/fastify-plugin/types/example-async.test-d.ts
generated
vendored
Normal file
19
node_modules/@fastify/cors/node_modules/fastify-plugin/types/example-async.test-d.ts
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
import { FastifyPluginAsync } from 'fastify'
|
||||
|
||||
type FastifyExampleAsync = FastifyPluginAsync<fastifyExampleAsync.FastifyExampleAsyncOptions>
|
||||
|
||||
declare namespace fastifyExampleAsync {
|
||||
|
||||
export interface FastifyExampleAsyncOptions {
|
||||
foo?: 'bar'
|
||||
}
|
||||
|
||||
export interface FastifyExampleAsyncPluginOptions extends FastifyExampleAsyncOptions {
|
||||
}
|
||||
export const fastifyExampleAsync: FastifyExampleAsync
|
||||
export { fastifyExampleAsync as default }
|
||||
}
|
||||
|
||||
declare function fastifyExampleAsync (...params: Parameters<FastifyExampleAsync>): ReturnType<FastifyExampleAsync>
|
||||
|
||||
export default fastifyExampleAsync
|
||||
19
node_modules/@fastify/cors/node_modules/fastify-plugin/types/example-callback.test-d.ts
generated
vendored
Normal file
19
node_modules/@fastify/cors/node_modules/fastify-plugin/types/example-callback.test-d.ts
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
import { FastifyPluginCallback } from 'fastify'
|
||||
|
||||
type FastifyExampleCallback = FastifyPluginCallback<fastifyExampleCallback.FastifyExampleCallbackOptions>
|
||||
|
||||
declare namespace fastifyExampleCallback {
|
||||
|
||||
export interface FastifyExampleCallbackOptions {
|
||||
foo?: 'bar'
|
||||
}
|
||||
|
||||
export interface FastifyExampleCallbackPluginOptions extends FastifyExampleCallbackOptions {
|
||||
}
|
||||
export const fastifyExampleCallback: FastifyExampleCallback
|
||||
export { fastifyExampleCallback as default }
|
||||
}
|
||||
|
||||
declare function fastifyExampleCallback (...params: Parameters<FastifyExampleCallback>): ReturnType<FastifyExampleCallback>
|
||||
|
||||
export default fastifyExampleCallback
|
||||
61
node_modules/@fastify/cors/node_modules/fastify-plugin/types/plugin.d.ts
generated
vendored
Normal file
61
node_modules/@fastify/cors/node_modules/fastify-plugin/types/plugin.d.ts
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
/// <reference types="fastify" />
|
||||
|
||||
import {
|
||||
FastifyPluginCallback,
|
||||
FastifyPluginAsync,
|
||||
FastifyPluginOptions,
|
||||
RawServerBase,
|
||||
RawServerDefault,
|
||||
FastifyTypeProvider,
|
||||
FastifyTypeProviderDefault,
|
||||
FastifyBaseLogger,
|
||||
} from 'fastify'
|
||||
|
||||
type FastifyPlugin = typeof fastifyPlugin
|
||||
|
||||
declare namespace fastifyPlugin {
|
||||
export interface PluginMetadata {
|
||||
/** Bare-minimum version of Fastify for your plugin, just add the semver range that you need. */
|
||||
fastify?: string,
|
||||
name?: string,
|
||||
/** Decorator dependencies for this plugin */
|
||||
decorators?: {
|
||||
fastify?: (string | symbol)[],
|
||||
reply?: (string | symbol)[],
|
||||
request?: (string | symbol)[]
|
||||
},
|
||||
/** The plugin dependencies */
|
||||
dependencies?: string[],
|
||||
encapsulate?: boolean
|
||||
}
|
||||
// Exporting PluginOptions for backward compatibility after renaming it to PluginMetadata
|
||||
/**
|
||||
* @deprecated Use PluginMetadata instead
|
||||
*/
|
||||
export interface PluginOptions extends PluginMetadata {}
|
||||
|
||||
export const fastifyPlugin: FastifyPlugin
|
||||
export { fastifyPlugin as default }
|
||||
}
|
||||
|
||||
/**
|
||||
* This function does three things for you:
|
||||
* 1. Add the `skip-override` hidden property
|
||||
* 2. Check bare-minimum version of Fastify
|
||||
* 3. Pass some custom metadata of the plugin to Fastify
|
||||
* @param fn Fastify plugin function
|
||||
* @param options Optional plugin options
|
||||
*/
|
||||
|
||||
declare function fastifyPlugin<
|
||||
Options extends FastifyPluginOptions = Record<never, never>,
|
||||
RawServer extends RawServerBase = RawServerDefault,
|
||||
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
|
||||
Logger extends FastifyBaseLogger = FastifyBaseLogger,
|
||||
Fn extends FastifyPluginCallback<Options, RawServer, TypeProvider, Logger> | FastifyPluginAsync<Options, RawServer, TypeProvider, Logger> = FastifyPluginCallback<Options, RawServer, TypeProvider, Logger>
|
||||
> (
|
||||
fn: Fn extends unknown ? Fn extends (...args: any) => Promise<any> ? FastifyPluginAsync<Options, RawServer, TypeProvider, Logger> : FastifyPluginCallback<Options, RawServer, TypeProvider, Logger> : Fn,
|
||||
options?: fastifyPlugin.PluginMetadata | string
|
||||
): Fn
|
||||
|
||||
export = fastifyPlugin
|
||||
166
node_modules/@fastify/cors/node_modules/fastify-plugin/types/plugin.test-d.ts
generated
vendored
Normal file
166
node_modules/@fastify/cors/node_modules/fastify-plugin/types/plugin.test-d.ts
generated
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
import fastifyPlugin from '..'
|
||||
import fastify, { FastifyPluginCallback, FastifyPluginAsync, FastifyError, FastifyInstance, FastifyPluginOptions, RawServerDefault, FastifyTypeProviderDefault, FastifyBaseLogger } from 'fastify'
|
||||
import { expectAssignable, expectError, expectNotType, expectType } from 'tsd'
|
||||
import { Server } from 'node:https'
|
||||
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
|
||||
import fastifyExampleCallback from './example-callback.test-d'
|
||||
import fastifyExampleAsync from './example-async.test-d'
|
||||
|
||||
interface Options {
|
||||
foo: string
|
||||
}
|
||||
|
||||
const testSymbol = Symbol('foobar')
|
||||
|
||||
// Callback
|
||||
|
||||
const pluginCallback: FastifyPluginCallback = (_fastify, _options, _next) => { }
|
||||
expectType<FastifyPluginCallback>(fastifyPlugin(pluginCallback))
|
||||
|
||||
const pluginCallbackWithTypes = (_fastify: FastifyInstance, _options: FastifyPluginOptions, _next: (error?: FastifyError) => void): void => { }
|
||||
expectAssignable<FastifyPluginCallback>(fastifyPlugin(pluginCallbackWithTypes))
|
||||
expectNotType<any>(fastifyPlugin(pluginCallbackWithTypes))
|
||||
|
||||
expectAssignable<FastifyPluginCallback>(fastifyPlugin((_fastify: FastifyInstance, _options: FastifyPluginOptions, _next: (error?: FastifyError) => void): void => { }))
|
||||
expectNotType<any>(fastifyPlugin((_fastify: FastifyInstance, _options: FastifyPluginOptions, _next: (error?: FastifyError) => void): void => { }))
|
||||
|
||||
expectType<FastifyPluginCallback>(fastifyPlugin(pluginCallback, ''))
|
||||
expectType<FastifyPluginCallback>(fastifyPlugin(pluginCallback, {
|
||||
fastify: '',
|
||||
name: '',
|
||||
decorators: {
|
||||
fastify: ['', testSymbol],
|
||||
reply: ['', testSymbol],
|
||||
request: ['', testSymbol]
|
||||
},
|
||||
dependencies: [''],
|
||||
encapsulate: true
|
||||
}))
|
||||
|
||||
const pluginCallbackWithOptions: FastifyPluginCallback<Options> = (_fastify, options, _next) => {
|
||||
expectType<string>(options.foo)
|
||||
}
|
||||
|
||||
expectType<FastifyPluginCallback<Options>>(fastifyPlugin(pluginCallbackWithOptions))
|
||||
|
||||
const pluginCallbackWithServer: FastifyPluginCallback<Options, Server> = (fastify, _options, _next) => {
|
||||
expectType<Server>(fastify.server)
|
||||
}
|
||||
|
||||
expectType<FastifyPluginCallback<Options, Server>>(fastifyPlugin(pluginCallbackWithServer))
|
||||
|
||||
const pluginCallbackWithTypeProvider: FastifyPluginCallback<Options, Server, TypeBoxTypeProvider> = (_fastify, _options, _next) => { }
|
||||
|
||||
expectType<FastifyPluginCallback<Options, Server, TypeBoxTypeProvider>>(fastifyPlugin(pluginCallbackWithTypeProvider))
|
||||
|
||||
// Async
|
||||
|
||||
const pluginAsync: FastifyPluginAsync = async (_fastify, _options) => { }
|
||||
expectType<FastifyPluginAsync>(fastifyPlugin(pluginAsync))
|
||||
|
||||
const pluginAsyncWithTypes = async (_fastify: FastifyInstance, _options: FastifyPluginOptions): Promise<void> => { }
|
||||
expectType<FastifyPluginAsync<FastifyPluginOptions, RawServerDefault, FastifyTypeProviderDefault>>(fastifyPlugin(pluginAsyncWithTypes))
|
||||
|
||||
expectType<FastifyPluginAsync<FastifyPluginOptions, RawServerDefault, FastifyTypeProviderDefault>>(fastifyPlugin(async (_fastify: FastifyInstance, _options: FastifyPluginOptions): Promise<void> => { }))
|
||||
expectType<FastifyPluginAsync>(fastifyPlugin(pluginAsync, ''))
|
||||
expectType<FastifyPluginAsync>(fastifyPlugin(pluginAsync, {
|
||||
fastify: '',
|
||||
name: '',
|
||||
decorators: {
|
||||
fastify: ['', testSymbol],
|
||||
reply: ['', testSymbol],
|
||||
request: ['', testSymbol]
|
||||
},
|
||||
dependencies: [''],
|
||||
encapsulate: true
|
||||
}))
|
||||
|
||||
const pluginAsyncWithOptions: FastifyPluginAsync<Options> = async (_fastify, options) => {
|
||||
expectType<string>(options.foo)
|
||||
}
|
||||
|
||||
expectType<FastifyPluginAsync<Options>>(fastifyPlugin(pluginAsyncWithOptions))
|
||||
|
||||
const pluginAsyncWithServer: FastifyPluginAsync<Options, Server> = async (fastify, _options) => {
|
||||
expectType<Server>(fastify.server)
|
||||
}
|
||||
|
||||
expectType<FastifyPluginAsync<Options, Server>>(fastifyPlugin(pluginAsyncWithServer))
|
||||
|
||||
const pluginAsyncWithTypeProvider: FastifyPluginAsync<Options, Server, TypeBoxTypeProvider> = async (_fastify, _options) => { }
|
||||
|
||||
expectType<FastifyPluginAsync<Options, Server, TypeBoxTypeProvider>>(fastifyPlugin(pluginAsyncWithTypeProvider))
|
||||
|
||||
// Fastify register
|
||||
|
||||
const server = fastify()
|
||||
server.register(fastifyPlugin(pluginCallback))
|
||||
server.register(fastifyPlugin(pluginCallbackWithTypes), { foo: 'bar' })
|
||||
server.register(fastifyPlugin(pluginCallbackWithOptions), { foo: 'bar' })
|
||||
server.register(fastifyPlugin(pluginCallbackWithServer), { foo: 'bar' })
|
||||
server.register(fastifyPlugin(pluginCallbackWithTypeProvider), { foo: 'bar' })
|
||||
server.register(fastifyPlugin(pluginAsync))
|
||||
server.register(fastifyPlugin(pluginAsyncWithTypes), { foo: 'bar' })
|
||||
server.register(fastifyPlugin(pluginAsyncWithOptions), { foo: 'bar' })
|
||||
server.register(fastifyPlugin(pluginAsyncWithServer), { foo: 'bar' })
|
||||
server.register(fastifyPlugin(pluginAsyncWithTypeProvider), { foo: 'bar' })
|
||||
|
||||
// properly handling callback and async
|
||||
fastifyPlugin(function (fastify, options, next) {
|
||||
expectType<FastifyInstance>(fastify)
|
||||
expectType<Record<never, never>>(options)
|
||||
expectType<(err?: Error) => void>(next)
|
||||
})
|
||||
|
||||
fastifyPlugin<Options>(function (fastify, options, next) {
|
||||
expectType<FastifyInstance>(fastify)
|
||||
expectType<Options>(options)
|
||||
expectType<(err?: Error) => void>(next)
|
||||
})
|
||||
|
||||
fastifyPlugin<Options>(async function (fastify, options) {
|
||||
expectType<FastifyInstance>(fastify)
|
||||
expectType<Options>(options)
|
||||
})
|
||||
|
||||
expectAssignable<FastifyPluginAsync<Options, RawServerDefault, FastifyTypeProviderDefault, FastifyBaseLogger>>(fastifyPlugin(async function (_fastify: FastifyInstance, _options: Options) { }))
|
||||
expectNotType<any>(fastifyPlugin(async function (_fastify: FastifyInstance, _options: Options) { }))
|
||||
|
||||
fastifyPlugin(async function (fastify, options: Options) {
|
||||
expectType<FastifyInstance>(fastify)
|
||||
expectType<Options>(options)
|
||||
})
|
||||
|
||||
fastifyPlugin(async function (fastify, options) {
|
||||
expectType<FastifyInstance>(fastify)
|
||||
expectType<Record<never, never>>(options)
|
||||
})
|
||||
|
||||
expectError(
|
||||
fastifyPlugin(async function (fastify, options: Options, _next) {
|
||||
expectType<FastifyInstance>(fastify)
|
||||
expectType<Options>(options)
|
||||
})
|
||||
)
|
||||
expectAssignable<FastifyPluginCallback<Options>>(fastifyPlugin(function (_fastify, _options, _next) { }))
|
||||
expectNotType<any>(fastifyPlugin(function (_fastify, _options, _next) { }))
|
||||
|
||||
fastifyPlugin(function (fastify, options: Options, next) {
|
||||
expectType<FastifyInstance>(fastify)
|
||||
expectType<Options>(options)
|
||||
expectType<(err?: Error) => void>(next)
|
||||
})
|
||||
|
||||
expectError(
|
||||
fastifyPlugin(function (fastify, options: Options, _next) {
|
||||
expectType<FastifyInstance>(fastify)
|
||||
expectType<Options>(options)
|
||||
return Promise.resolve()
|
||||
})
|
||||
)
|
||||
|
||||
server.register(fastifyExampleCallback, { foo: 'bar' })
|
||||
expectError(server.register(fastifyExampleCallback, { foo: 'baz' }))
|
||||
|
||||
server.register(fastifyExampleAsync, { foo: 'bar' })
|
||||
expectError(server.register(fastifyExampleAsync, { foo: 'baz' }))
|
||||
81
node_modules/@fastify/cors/package.json
generated
vendored
Normal file
81
node_modules/@fastify/cors/package.json
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"name": "@fastify/cors",
|
||||
"version": "11.2.0",
|
||||
"description": "Fastify CORS",
|
||||
"main": "index.js",
|
||||
"type": "commonjs",
|
||||
"types": "types/index.d.ts",
|
||||
"scripts": {
|
||||
"lint": "eslint",
|
||||
"lint:fix": "eslint --fix",
|
||||
"test": "npm run test:unit && npm run test:typescript",
|
||||
"test:typescript": "tsd",
|
||||
"test:unit": "c8 --100 node --test"
|
||||
},
|
||||
"keywords": [
|
||||
"fastify",
|
||||
"cors",
|
||||
"headers",
|
||||
"access",
|
||||
"control"
|
||||
],
|
||||
"author": "Tomas Della Vedova - @delvedor (http://delved.org)",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Matteo Collina",
|
||||
"email": "hello@matteocollina.com"
|
||||
},
|
||||
{
|
||||
"name": "Manuel Spigolon",
|
||||
"email": "behemoth89@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Cemre Mengu",
|
||||
"email": "cemremengu@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Frazer Smith",
|
||||
"email": "frazer.dev@icloud.com",
|
||||
"url": "https://github.com/fdawgs"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/fastify/fastify-cors.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/fastify/fastify-cors/issues"
|
||||
},
|
||||
"homepage": "https://github.com/fastify/fastify-cors#readme",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fastify"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/fastify"
|
||||
}
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.0.8",
|
||||
"c8": "^10.1.2",
|
||||
"cors": "^2.8.5",
|
||||
"eslint": "^9.17.0",
|
||||
"fastify": "^5.0.0",
|
||||
"neostandard": "^0.12.0",
|
||||
"tsd": "^0.33.0",
|
||||
"typescript": "~5.9.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"fastify-plugin": "^5.0.0",
|
||||
"toad-cache": "^3.7.0"
|
||||
},
|
||||
"tsd": {
|
||||
"directory": "test"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
1124
node_modules/@fastify/cors/test/cors.test.js
generated
vendored
Normal file
1124
node_modules/@fastify/cors/test/cors.test.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
787
node_modules/@fastify/cors/test/hooks.test.js
generated
vendored
Normal file
787
node_modules/@fastify/cors/test/hooks.test.js
generated
vendored
Normal file
@@ -0,0 +1,787 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const Fastify = require('fastify')
|
||||
const kFastifyContext = require('fastify/lib/symbols').kRouteContext
|
||||
const cors = require('..')
|
||||
const { setTimeout: sleep } = require('node:timers/promises')
|
||||
|
||||
test('Should error on invalid hook option', async (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
await t.assert.rejects(
|
||||
async () => fastify.register(cors, { hook: 'invalid' }),
|
||||
(err) => {
|
||||
t.assert.strictEqual(err.name, 'TypeError')
|
||||
t.assert.strictEqual(err.message, '@fastify/cors: Invalid hook option provided.')
|
||||
return true
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
test('Should set hook onRequest if hook option is not set', async (t) => {
|
||||
t.plan(10)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(cors)
|
||||
|
||||
fastify.addHook('onResponse', (request, _reply, done) => {
|
||||
t.assert.strictEqual(request[kFastifyContext].onError, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].onRequest.length, 1)
|
||||
t.assert.strictEqual(request[kFastifyContext].onSend, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preHandler, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preParsing, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preSerialization, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preValidation, null)
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.get('/', (_req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
})
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 200)
|
||||
t.assert.strictEqual(res.payload, 'ok')
|
||||
const actualHeader = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin']
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeader, {
|
||||
'access-control-allow-origin': '*'
|
||||
})
|
||||
})
|
||||
|
||||
test('Should set hook onRequest if hook option is set to onRequest', async (t) => {
|
||||
t.plan(10)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(cors, {
|
||||
hook: 'onRequest'
|
||||
})
|
||||
|
||||
fastify.addHook('onResponse', (request, _reply, done) => {
|
||||
t.assert.strictEqual(request[kFastifyContext].onError, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].onRequest.length, 1)
|
||||
t.assert.strictEqual(request[kFastifyContext].onSend, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preHandler, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preParsing, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preSerialization, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preValidation, null)
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.get('/', (_req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
})
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 200)
|
||||
t.assert.strictEqual(res.payload, 'ok')
|
||||
const actualHeader = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin']
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeader, {
|
||||
'access-control-allow-origin': '*'
|
||||
})
|
||||
})
|
||||
|
||||
test('Should set hook preParsing if hook option is set to preParsing', async (t) => {
|
||||
t.plan(11)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(cors, {
|
||||
hook: 'preParsing'
|
||||
})
|
||||
|
||||
fastify.addHook('onResponse', (request, _reply, done) => {
|
||||
t.assert.strictEqual(request[kFastifyContext].onError, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].onRequest, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].onSend, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preHandler, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preParsing.length, 1)
|
||||
t.assert.strictEqual(request[kFastifyContext].preSerialization, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preValidation, null)
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.get('/', (_req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
})
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 200)
|
||||
t.assert.strictEqual(res.payload, 'ok')
|
||||
const actualHeader = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin']
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeader, {
|
||||
'access-control-allow-origin': '*'
|
||||
})
|
||||
t.assert.notStrictEqual(res.headers.vary, 'Origin')
|
||||
})
|
||||
|
||||
test('Should set hook preValidation if hook option is set to preValidation', async (t) => {
|
||||
t.plan(11)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(cors, {
|
||||
hook: 'preValidation'
|
||||
})
|
||||
|
||||
fastify.addHook('onResponse', (request, _reply, done) => {
|
||||
t.assert.strictEqual(request[kFastifyContext].onError, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].onRequest, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].onSend, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preHandler, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preParsing, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preSerialization, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preValidation.length, 1)
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.get('/', (_req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
})
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 200)
|
||||
t.assert.strictEqual(res.payload, 'ok')
|
||||
const actualHeader = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin']
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeader, {
|
||||
'access-control-allow-origin': '*'
|
||||
})
|
||||
t.assert.notStrictEqual(res.headers.vary, 'Origin')
|
||||
})
|
||||
|
||||
test('Should set hook preParsing if hook option is set to preParsing', async (t) => {
|
||||
t.plan(11)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(cors, {
|
||||
hook: 'preParsing'
|
||||
})
|
||||
|
||||
fastify.addHook('onResponse', (request, _reply, done) => {
|
||||
t.assert.strictEqual(request[kFastifyContext].onError, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].onRequest, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].onSend, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preHandler, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preParsing.length, 1)
|
||||
t.assert.strictEqual(request[kFastifyContext].preSerialization, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preValidation, null)
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.get('/', (_req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
})
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 200)
|
||||
t.assert.strictEqual(res.payload, 'ok')
|
||||
const actualHeader = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin']
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeader, {
|
||||
'access-control-allow-origin': '*'
|
||||
})
|
||||
t.assert.notStrictEqual(res.headers.vary, 'Origin')
|
||||
})
|
||||
|
||||
test('Should set hook preHandler if hook option is set to preHandler', async (t) => {
|
||||
t.plan(11)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(cors, {
|
||||
hook: 'preHandler'
|
||||
})
|
||||
|
||||
fastify.addHook('onResponse', (request, _reply, done) => {
|
||||
t.assert.strictEqual(request[kFastifyContext].onError, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].onRequest, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].onSend, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preHandler.length, 1)
|
||||
t.assert.strictEqual(request[kFastifyContext].preParsing, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preSerialization, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preValidation, null)
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.get('/', (_req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
})
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 200)
|
||||
t.assert.strictEqual(res.payload, 'ok')
|
||||
const actualHeader = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin']
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeader, {
|
||||
'access-control-allow-origin': '*'
|
||||
})
|
||||
t.assert.notStrictEqual(res.headers.vary, 'Origin')
|
||||
})
|
||||
|
||||
test('Should set hook onSend if hook option is set to onSend', async (t) => {
|
||||
t.plan(11)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(cors, {
|
||||
hook: 'onSend'
|
||||
})
|
||||
|
||||
fastify.addHook('onResponse', (request, _reply, done) => {
|
||||
t.assert.strictEqual(request[kFastifyContext].onError, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].onRequest, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].onSend.length, 1)
|
||||
t.assert.strictEqual(request[kFastifyContext].preHandler, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preParsing, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preSerialization, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preValidation, null)
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.get('/', (_req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
})
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 200)
|
||||
t.assert.strictEqual(res.payload, 'ok')
|
||||
const actualHeader = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin']
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeader, {
|
||||
'access-control-allow-origin': '*'
|
||||
})
|
||||
t.assert.notStrictEqual(res.headers.vary, 'Origin')
|
||||
})
|
||||
|
||||
test('Should set hook preSerialization if hook option is set to preSerialization', async (t) => {
|
||||
t.plan(11)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(cors, {
|
||||
hook: 'preSerialization'
|
||||
})
|
||||
|
||||
fastify.addHook('onResponse', (request, _reply, done) => {
|
||||
t.assert.strictEqual(request[kFastifyContext].onError, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].onRequest, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].onSend, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preHandler, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preParsing, null)
|
||||
t.assert.strictEqual(request[kFastifyContext].preSerialization.length, 1)
|
||||
t.assert.strictEqual(request[kFastifyContext].preValidation, null)
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.get('/', (_req, reply) => {
|
||||
reply.send({ nonString: true })
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
})
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 200)
|
||||
t.assert.strictEqual(res.payload, '{"nonString":true}')
|
||||
const actualHeader = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin']
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeader, {
|
||||
'access-control-allow-origin': '*'
|
||||
})
|
||||
t.assert.notStrictEqual(res.headers.vary, 'Origin')
|
||||
})
|
||||
|
||||
test('Should support custom hook with dynamic config', async t => {
|
||||
t.plan(16)
|
||||
|
||||
const configs = [{
|
||||
origin: 'example.com',
|
||||
methods: 'GET',
|
||||
credentials: true,
|
||||
exposedHeaders: ['foo', 'bar'],
|
||||
allowedHeaders: ['baz', 'woo'],
|
||||
maxAge: 123
|
||||
}, {
|
||||
origin: 'sample.com',
|
||||
methods: 'GET',
|
||||
credentials: true,
|
||||
exposedHeaders: ['zoo', 'bar'],
|
||||
allowedHeaders: ['baz', 'foo'],
|
||||
maxAge: 321
|
||||
}]
|
||||
|
||||
const fastify = Fastify()
|
||||
let requestId = 0
|
||||
const configDelegation = async function (req) {
|
||||
// request should have id
|
||||
t.assert.ok(req.id)
|
||||
// request should not have send
|
||||
t.assert.ifError(req.send)
|
||||
const config = configs[requestId]
|
||||
requestId++
|
||||
if (config) {
|
||||
return Promise.resolve(config)
|
||||
} else {
|
||||
return Promise.reject(new Error('ouch'))
|
||||
}
|
||||
}
|
||||
await fastify.register(cors, {
|
||||
hook: 'preHandler',
|
||||
delegator: configDelegation
|
||||
})
|
||||
|
||||
fastify.get('/', (_req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
let res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
})
|
||||
t.assert.ok(res)
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 200)
|
||||
t.assert.strictEqual(res.payload, 'ok')
|
||||
let actualHeaders = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin'],
|
||||
'access-control-allow-credentials': res.headers['access-control-allow-credentials'],
|
||||
'access-control-expose-headers': res.headers['access-control-expose-headers'],
|
||||
'content-length': res.headers['content-length'],
|
||||
vary: res.headers.vary
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeaders, {
|
||||
'access-control-allow-origin': 'example.com',
|
||||
'access-control-allow-credentials': 'true',
|
||||
'access-control-expose-headers': 'foo, bar',
|
||||
'content-length': '2',
|
||||
vary: 'Origin'
|
||||
})
|
||||
|
||||
res = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
})
|
||||
t.assert.ok(res)
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 204)
|
||||
t.assert.strictEqual(res.payload, '')
|
||||
actualHeaders = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin'],
|
||||
'access-control-allow-credentials': res.headers['access-control-allow-credentials'],
|
||||
'access-control-expose-headers': res.headers['access-control-expose-headers'],
|
||||
'access-control-allow-methods': res.headers['access-control-allow-methods'],
|
||||
'access-control-allow-headers': res.headers['access-control-allow-headers'],
|
||||
'access-control-max-age': res.headers['access-control-max-age'],
|
||||
'content-length': res.headers['content-length'],
|
||||
vary: res.headers.vary
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeaders, {
|
||||
'access-control-allow-origin': 'sample.com',
|
||||
'access-control-allow-credentials': 'true',
|
||||
'access-control-expose-headers': 'zoo, bar',
|
||||
'access-control-allow-methods': 'GET',
|
||||
'access-control-allow-headers': 'baz, foo',
|
||||
'access-control-max-age': '321',
|
||||
'content-length': '0',
|
||||
vary: 'Origin'
|
||||
})
|
||||
|
||||
res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
})
|
||||
t.assert.ok(res)
|
||||
t.assert.strictEqual(res.statusCode, 500)
|
||||
})
|
||||
|
||||
test('Should support custom hook with dynamic config (callback)', async t => {
|
||||
t.plan(16)
|
||||
|
||||
const configs = [{
|
||||
origin: 'example.com',
|
||||
methods: 'GET',
|
||||
credentials: true,
|
||||
exposedHeaders: ['foo', 'bar'],
|
||||
allowedHeaders: ['baz', 'woo'],
|
||||
maxAge: 123
|
||||
}, {
|
||||
origin: 'sample.com',
|
||||
methods: 'GET',
|
||||
credentials: true,
|
||||
exposedHeaders: ['zoo', 'bar'],
|
||||
allowedHeaders: ['baz', 'foo'],
|
||||
maxAge: 321
|
||||
}]
|
||||
|
||||
const fastify = Fastify()
|
||||
let requestId = 0
|
||||
const configDelegation = function (req, cb) {
|
||||
// request should have id
|
||||
t.assert.ok(req.id)
|
||||
// request should not have send
|
||||
t.assert.ifError(req.send)
|
||||
const config = configs[requestId]
|
||||
requestId++
|
||||
if (config) {
|
||||
cb(null, config)
|
||||
} else {
|
||||
cb(new Error('ouch'))
|
||||
}
|
||||
}
|
||||
fastify.register(cors, {
|
||||
hook: 'preParsing',
|
||||
delegator: configDelegation
|
||||
})
|
||||
|
||||
fastify.get('/', (_req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.assert.ifError(err)
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 200)
|
||||
t.assert.strictEqual(res.payload, 'ok')
|
||||
const actualHeaders = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin'],
|
||||
'access-control-allow-credentials': res.headers['access-control-allow-credentials'],
|
||||
'access-control-expose-headers': res.headers['access-control-expose-headers'],
|
||||
'content-length': res.headers['content-length'],
|
||||
vary: res.headers.vary
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeaders, {
|
||||
'access-control-allow-origin': 'example.com',
|
||||
'access-control-allow-credentials': 'true',
|
||||
'access-control-expose-headers': 'foo, bar',
|
||||
'content-length': '2',
|
||||
vary: 'Origin'
|
||||
})
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.assert.ifError(err)
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 204)
|
||||
t.assert.strictEqual(res.payload, '')
|
||||
const actualHeaders = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin'],
|
||||
'access-control-allow-credentials': res.headers['access-control-allow-credentials'],
|
||||
'access-control-expose-headers': res.headers['access-control-expose-headers'],
|
||||
'access-control-allow-methods': res.headers['access-control-allow-methods'],
|
||||
'access-control-allow-headers': res.headers['access-control-allow-headers'],
|
||||
'access-control-max-age': res.headers['access-control-max-age'],
|
||||
'content-length': res.headers['content-length'],
|
||||
vary: res.headers.vary
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeaders, {
|
||||
'access-control-allow-origin': 'sample.com',
|
||||
'access-control-allow-credentials': 'true',
|
||||
'access-control-expose-headers': 'zoo, bar',
|
||||
'access-control-allow-methods': 'GET',
|
||||
'access-control-allow-headers': 'baz, foo',
|
||||
'access-control-max-age': '321',
|
||||
'content-length': '0',
|
||||
vary: 'Origin'
|
||||
})
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.assert.ifError(err)
|
||||
t.assert.strictEqual(res.statusCode, 500)
|
||||
})
|
||||
await sleep()
|
||||
})
|
||||
|
||||
test('Should support custom hook with dynamic config (Promise)', async t => {
|
||||
t.plan(16)
|
||||
|
||||
const configs = [{
|
||||
origin: 'example.com',
|
||||
methods: 'GET',
|
||||
credentials: true,
|
||||
exposedHeaders: ['foo', 'bar'],
|
||||
allowedHeaders: ['baz', 'woo'],
|
||||
maxAge: 123
|
||||
}, {
|
||||
origin: 'sample.com',
|
||||
methods: 'GET',
|
||||
credentials: true,
|
||||
exposedHeaders: ['zoo', 'bar'],
|
||||
allowedHeaders: ['baz', 'foo'],
|
||||
maxAge: 321
|
||||
}]
|
||||
|
||||
const fastify = Fastify()
|
||||
let requestId = 0
|
||||
const configDelegation = async function (req) {
|
||||
// request should have id
|
||||
t.assert.ok(req.id)
|
||||
// request should not have send
|
||||
t.assert.ifError(req.send)
|
||||
const config = configs[requestId]
|
||||
requestId++
|
||||
if (config) {
|
||||
return Promise.resolve(config)
|
||||
} else {
|
||||
return Promise.reject(new Error('ouch'))
|
||||
}
|
||||
}
|
||||
|
||||
await fastify.register(cors, {
|
||||
hook: 'preParsing',
|
||||
delegator: configDelegation
|
||||
})
|
||||
|
||||
fastify.get('/', (_req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
let res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
})
|
||||
t.assert.ok(res)
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 200)
|
||||
t.assert.strictEqual(res.payload, 'ok')
|
||||
let actualHeaders = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin'],
|
||||
'access-control-allow-credentials': res.headers['access-control-allow-credentials'],
|
||||
'access-control-expose-headers': res.headers['access-control-expose-headers'],
|
||||
'content-length': res.headers['content-length'],
|
||||
vary: res.headers.vary
|
||||
}
|
||||
|
||||
t.assert.deepStrictEqual(actualHeaders, {
|
||||
'access-control-allow-origin': 'example.com',
|
||||
'access-control-allow-credentials': 'true',
|
||||
'access-control-expose-headers': 'foo, bar',
|
||||
'content-length': '2',
|
||||
vary: 'Origin'
|
||||
})
|
||||
|
||||
res = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
})
|
||||
t.assert.ok(res)
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 204)
|
||||
t.assert.strictEqual(res.payload, '')
|
||||
actualHeaders = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin'],
|
||||
'access-control-allow-credentials': res.headers['access-control-allow-credentials'],
|
||||
'access-control-expose-headers': res.headers['access-control-expose-headers'],
|
||||
'access-control-allow-methods': res.headers['access-control-allow-methods'],
|
||||
'access-control-allow-headers': res.headers['access-control-allow-headers'],
|
||||
'access-control-max-age': res.headers['access-control-max-age'],
|
||||
'content-length': res.headers['content-length'],
|
||||
vary: res.headers.vary
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeaders, {
|
||||
'access-control-allow-origin': 'sample.com',
|
||||
'access-control-allow-credentials': 'true',
|
||||
'access-control-expose-headers': 'zoo, bar',
|
||||
'access-control-allow-methods': 'GET',
|
||||
'access-control-allow-headers': 'baz, foo',
|
||||
'access-control-max-age': '321',
|
||||
'content-length': '0',
|
||||
vary: 'Origin'
|
||||
})
|
||||
|
||||
res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
})
|
||||
t.assert.ok(res)
|
||||
t.assert.strictEqual(res.statusCode, 500)
|
||||
})
|
||||
|
||||
test('Should support custom hook with dynamic config (Promise), but should error /1', async t => {
|
||||
t.plan(6)
|
||||
|
||||
const fastify = Fastify()
|
||||
const configDelegation = function () {
|
||||
return false
|
||||
}
|
||||
|
||||
await fastify.register(cors, {
|
||||
hook: 'preParsing',
|
||||
delegator: configDelegation
|
||||
})
|
||||
|
||||
fastify.get('/', (_req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
let res = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
})
|
||||
t.assert.ok(res)
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 500)
|
||||
t.assert.strictEqual(res.payload, '{"statusCode":500,"error":"Internal Server Error","message":"Invalid CORS origin option"}')
|
||||
const actualHeaders = {
|
||||
'content-length': res.headers['content-length']
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeaders, {
|
||||
'content-length': '89'
|
||||
})
|
||||
|
||||
res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
})
|
||||
t.assert.ok(res)
|
||||
t.assert.strictEqual(res.statusCode, 500)
|
||||
})
|
||||
|
||||
test('Should support custom hook with dynamic config (Promise), but should error /2', async t => {
|
||||
t.plan(6)
|
||||
|
||||
const fastify = Fastify()
|
||||
const configDelegation = function () {
|
||||
return false
|
||||
}
|
||||
|
||||
await fastify.register(cors, {
|
||||
delegator: configDelegation
|
||||
})
|
||||
|
||||
fastify.get('/', (_req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
let res = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
})
|
||||
t.assert.ok(res)
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 500)
|
||||
t.assert.strictEqual(res.payload, '{"statusCode":500,"error":"Internal Server Error","message":"Invalid CORS origin option"}')
|
||||
const actualHeaders = {
|
||||
'content-length': res.headers['content-length']
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeaders, {
|
||||
'content-length': '89'
|
||||
})
|
||||
|
||||
res = await fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
})
|
||||
t.assert.ok(res)
|
||||
t.assert.strictEqual(res.statusCode, 500)
|
||||
})
|
||||
590
node_modules/@fastify/cors/test/preflight.test.js
generated
vendored
Normal file
590
node_modules/@fastify/cors/test/preflight.test.js
generated
vendored
Normal file
@@ -0,0 +1,590 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const Fastify = require('fastify')
|
||||
const cors = require('../')
|
||||
|
||||
test('Should reply to preflight requests', async t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
await fastify.register(cors)
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
})
|
||||
t.assert.ok(res)
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 204)
|
||||
t.assert.strictEqual(res.payload, '')
|
||||
const actualHeaders = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin'],
|
||||
'access-control-allow-methods': res.headers['access-control-allow-methods'],
|
||||
vary: res.headers.vary,
|
||||
'content-length': res.headers['content-length']
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeaders, {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET,HEAD,POST',
|
||||
vary: 'Access-Control-Request-Headers',
|
||||
'content-length': '0'
|
||||
})
|
||||
})
|
||||
|
||||
test('Should add access-control-allow-headers to response if preflight req has access-control-request-headers', async t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
await fastify.register(cors)
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-headers': 'x-requested-with',
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
|
||||
})
|
||||
t.assert.ok(res)
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 204)
|
||||
t.assert.strictEqual(res.payload, '')
|
||||
const actualHeaders = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin'],
|
||||
'access-control-allow-methods': res.headers['access-control-allow-methods'],
|
||||
'access-control-allow-headers': res.headers['access-control-allow-headers'],
|
||||
vary: res.headers.vary,
|
||||
'content-length': res.headers['content-length']
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeaders, {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET,HEAD,POST',
|
||||
'access-control-allow-headers': 'x-requested-with',
|
||||
vary: 'Access-Control-Request-Headers',
|
||||
'content-length': '0'
|
||||
})
|
||||
})
|
||||
|
||||
test('Should reply to preflight requests with custom status code', async t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
await fastify.register(cors, { optionsSuccessStatus: 200 })
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
})
|
||||
t.assert.ok(res)
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 200)
|
||||
t.assert.strictEqual(res.payload, '')
|
||||
const actualHeaders = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin'],
|
||||
'access-control-allow-methods': res.headers['access-control-allow-methods'],
|
||||
vary: res.headers.vary,
|
||||
'content-length': res.headers['content-length']
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeaders, {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET,HEAD,POST',
|
||||
vary: 'Access-Control-Request-Headers',
|
||||
'content-length': '0'
|
||||
})
|
||||
})
|
||||
|
||||
test('Should be able to override preflight response with a route', async t => {
|
||||
t.plan(5)
|
||||
|
||||
const fastify = Fastify()
|
||||
await fastify.register(cors, { preflightContinue: true })
|
||||
|
||||
fastify.options('/', (_req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
})
|
||||
t.assert.ok(res)
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 200)
|
||||
t.assert.strictEqual(res.payload, 'ok')
|
||||
const actualHeaders = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin']
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeaders, {
|
||||
// Only the base cors headers and no preflight headers
|
||||
'access-control-allow-origin': '*'
|
||||
})
|
||||
t.assert.notStrictEqual(res.headers.vary, 'Origin')
|
||||
})
|
||||
|
||||
test('Should reply to all options requests', async t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
await fastify.register(cors)
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/hello',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
})
|
||||
t.assert.ok(res)
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 204)
|
||||
t.assert.strictEqual(res.payload, '')
|
||||
const actualHeaders = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin'],
|
||||
'access-control-allow-methods': res.headers['access-control-allow-methods'],
|
||||
vary: res.headers.vary,
|
||||
'content-length': res.headers['content-length']
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeaders, {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET,HEAD,POST',
|
||||
vary: 'Access-Control-Request-Headers',
|
||||
'content-length': '0'
|
||||
})
|
||||
})
|
||||
|
||||
test('Should support a prefix for preflight requests', async t => {
|
||||
t.plan(6)
|
||||
|
||||
const fastify = Fastify()
|
||||
await fastify.register((instance, _opts, next) => {
|
||||
instance.register(cors)
|
||||
next()
|
||||
}, { prefix: '/subsystem' })
|
||||
|
||||
let res = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/hello'
|
||||
})
|
||||
t.assert.ok(res)
|
||||
t.assert.strictEqual(res.statusCode, 404)
|
||||
|
||||
res = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/subsystem/hello',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
})
|
||||
t.assert.ok(res)
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 204)
|
||||
t.assert.strictEqual(res.payload, '')
|
||||
const actualHeaders = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin'],
|
||||
'access-control-allow-methods': res.headers['access-control-allow-methods'],
|
||||
vary: res.headers.vary,
|
||||
'content-length': res.headers['content-length']
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeaders, {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET,HEAD,POST',
|
||||
vary: 'Access-Control-Request-Headers',
|
||||
'content-length': '0'
|
||||
})
|
||||
})
|
||||
|
||||
test('hide options route by default', async t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addHook('onRoute', (route) => {
|
||||
if (route.method === 'OPTIONS' && route.url === '*') {
|
||||
t.assert.strictEqual(route.schema.hide, true)
|
||||
}
|
||||
})
|
||||
await fastify.register(cors)
|
||||
|
||||
const ready = await fastify.ready()
|
||||
t.assert.ok(ready)
|
||||
})
|
||||
|
||||
test('show options route', async t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addHook('onRoute', (route) => {
|
||||
if (route.method === 'OPTIONS' && route.url === '*') {
|
||||
t.assert.strictEqual(route.schema.hide, false)
|
||||
}
|
||||
})
|
||||
await fastify.register(cors, { hideOptionsRoute: false })
|
||||
|
||||
const ready = await fastify.ready()
|
||||
t.assert.ok(ready)
|
||||
})
|
||||
|
||||
test('Allow only request from with specific methods', async t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
await fastify.register(cors, { methods: ['GET', 'POST'] })
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
})
|
||||
t.assert.ok(res)
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 204)
|
||||
const actualHeaders = {
|
||||
'access-control-allow-methods': res.headers['access-control-allow-methods']
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeaders, {
|
||||
'access-control-allow-methods': 'GET, POST'
|
||||
})
|
||||
t.assert.notStrictEqual(res.headers.vary, 'Origin')
|
||||
})
|
||||
|
||||
test('Should reply with 400 error to OPTIONS requests missing origin header when default strictPreflight', async t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
await fastify.register(cors)
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET'
|
||||
}
|
||||
})
|
||||
t.assert.ok(res)
|
||||
t.assert.strictEqual(res.statusCode, 400)
|
||||
t.assert.strictEqual(res.payload, 'Invalid Preflight Request')
|
||||
})
|
||||
|
||||
test('Should reply with 400 to OPTIONS requests when missing Access-Control-Request-Method header when default strictPreflight', async t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
await fastify.register(cors, {
|
||||
strictPreflight: true
|
||||
})
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
origin: 'example.com'
|
||||
}
|
||||
})
|
||||
t.assert.ok(res)
|
||||
t.assert.strictEqual(res.statusCode, 400)
|
||||
t.assert.strictEqual(res.payload, 'Invalid Preflight Request')
|
||||
})
|
||||
|
||||
test('Should reply to all preflight requests when strictPreflight is disabled', async t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
await fastify.register(cors, { strictPreflight: false })
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/'
|
||||
// No access-control-request-method or origin headers
|
||||
})
|
||||
t.assert.ok(res)
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 204)
|
||||
t.assert.strictEqual(res.payload, '')
|
||||
const actualHeaders = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin'],
|
||||
'access-control-allow-methods': res.headers['access-control-allow-methods'],
|
||||
vary: res.headers.vary,
|
||||
'content-length': res.headers['content-length']
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeaders, {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET,HEAD,POST',
|
||||
vary: 'Access-Control-Request-Headers',
|
||||
'content-length': '0'
|
||||
})
|
||||
})
|
||||
|
||||
test('Default empty 200 response with preflightContinue on OPTIONS routes', async t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
await fastify.register(cors, { preflightContinue: true })
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/doesnotexist',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
})
|
||||
t.assert.ok(res)
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 200)
|
||||
t.assert.strictEqual(res.payload, '')
|
||||
const actualHeaders = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin'],
|
||||
'access-control-allow-methods': res.headers['access-control-allow-methods'],
|
||||
vary: res.headers.vary
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeaders, {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET,HEAD,POST',
|
||||
vary: 'Access-Control-Request-Headers'
|
||||
})
|
||||
})
|
||||
|
||||
test('Can override preflight response with preflightContinue', async t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
await fastify.register(cors, { preflightContinue: true })
|
||||
|
||||
fastify.options('/', (_req, reply) => {
|
||||
reply.send('ok')
|
||||
})
|
||||
|
||||
const res = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
})
|
||||
t.assert.ok(res)
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 200)
|
||||
t.assert.strictEqual(res.payload, 'ok')
|
||||
const actualHeaders = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin'],
|
||||
'access-control-allow-methods': res.headers['access-control-allow-methods'],
|
||||
vary: res.headers.vary
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeaders, {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET,HEAD,POST',
|
||||
vary: 'Access-Control-Request-Headers'
|
||||
})
|
||||
})
|
||||
|
||||
test('Should support ongoing prefix ', async t => {
|
||||
t.plan(12)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
await fastify.register(async (instance) => {
|
||||
instance.register(cors)
|
||||
}, { prefix: '/prefix' })
|
||||
|
||||
// support prefixed route
|
||||
let res = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/prefix',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
})
|
||||
t.assert.ok(res)
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 204)
|
||||
t.assert.strictEqual(res.payload, '')
|
||||
let actualHeaders = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin'],
|
||||
'access-control-allow-methods': res.headers['access-control-allow-methods'],
|
||||
vary: res.headers.vary,
|
||||
'content-length': res.headers['content-length']
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeaders, {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET,HEAD,POST',
|
||||
vary: 'Access-Control-Request-Headers',
|
||||
'content-length': '0'
|
||||
})
|
||||
|
||||
// support prefixed route without / continue
|
||||
res = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/prefixfoo',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
})
|
||||
t.assert.ok(res)
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 204)
|
||||
t.assert.strictEqual(res.payload, '')
|
||||
actualHeaders = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin'],
|
||||
'access-control-allow-methods': res.headers['access-control-allow-methods'],
|
||||
vary: res.headers.vary,
|
||||
'content-length': res.headers['content-length']
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeaders, {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET,HEAD,POST',
|
||||
vary: 'Access-Control-Request-Headers',
|
||||
'content-length': '0'
|
||||
})
|
||||
|
||||
// support prefixed route with / continue
|
||||
res = await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/prefix/foo',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'example.com'
|
||||
}
|
||||
})
|
||||
t.assert.ok(res)
|
||||
delete res.headers.date
|
||||
t.assert.strictEqual(res.statusCode, 204)
|
||||
t.assert.strictEqual(res.payload, '')
|
||||
actualHeaders = {
|
||||
'access-control-allow-origin': res.headers['access-control-allow-origin'],
|
||||
'access-control-allow-methods': res.headers['access-control-allow-methods'],
|
||||
vary: res.headers.vary,
|
||||
'content-length': res.headers['content-length']
|
||||
}
|
||||
t.assert.deepStrictEqual(actualHeaders, {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET,HEAD,POST',
|
||||
vary: 'Access-Control-Request-Headers',
|
||||
'content-length': '0'
|
||||
})
|
||||
})
|
||||
|
||||
test('Silences preflight logs when logLevel is "silent"', async t => {
|
||||
const logs = []
|
||||
const fastify = Fastify({
|
||||
logger: {
|
||||
level: 'info',
|
||||
stream: {
|
||||
write (line) {
|
||||
try {
|
||||
logs.push(JSON.parse(line))
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await fastify.register(cors, { logLevel: 'silent' })
|
||||
|
||||
fastify.get('/', async () => ({ ok: true }))
|
||||
|
||||
await fastify.ready()
|
||||
t.assert.ok(fastify)
|
||||
|
||||
await fastify.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'https://example.com'
|
||||
}
|
||||
})
|
||||
|
||||
await fastify.inject({ method: 'GET', url: '/' })
|
||||
|
||||
const hasOptionsLog = logs.some(l => l.req && l.req.method === 'OPTIONS')
|
||||
const hasGetLog = logs.some(l => l.req && l.req.method === 'GET')
|
||||
|
||||
t.assert.strictEqual(hasOptionsLog, false)
|
||||
t.assert.strictEqual(hasGetLog, true)
|
||||
|
||||
await fastify.close()
|
||||
})
|
||||
test('delegator + logLevel:"silent" → OPTIONS logs are suppressed', async t => {
|
||||
t.plan(3)
|
||||
|
||||
const logs = []
|
||||
const app = Fastify({
|
||||
logger: {
|
||||
level: 'info',
|
||||
stream: { write: l => { try { logs.push(JSON.parse(l)) } catch {} } }
|
||||
}
|
||||
})
|
||||
|
||||
await app.register(cors, {
|
||||
delegator: () => ({ origin: '*' }),
|
||||
logLevel: 'silent'
|
||||
})
|
||||
|
||||
app.get('/', () => ({ ok: true }))
|
||||
await app.ready()
|
||||
t.assert.ok(app)
|
||||
|
||||
await app.inject({
|
||||
method: 'OPTIONS',
|
||||
url: '/',
|
||||
headers: {
|
||||
'access-control-request-method': 'GET',
|
||||
origin: 'https://example.com'
|
||||
}
|
||||
})
|
||||
|
||||
await app.inject({ method: 'GET', url: '/' })
|
||||
|
||||
const hasOptionsLog = logs.some(l => l.req?.method === 'OPTIONS')
|
||||
const hasGetLog = logs.some(l => l.req?.method === 'GET')
|
||||
|
||||
t.assert.strictEqual(hasOptionsLog, false)
|
||||
t.assert.strictEqual(hasGetLog, true)
|
||||
|
||||
await app.close()
|
||||
})
|
||||
test('delegator + hideOptionsRoute:false → OPTIONS route is visible', async t => {
|
||||
t.plan(2)
|
||||
|
||||
const app = Fastify()
|
||||
|
||||
app.addHook('onRoute', route => {
|
||||
if (route.method === 'OPTIONS' && route.url === '*') {
|
||||
t.assert.strictEqual(route.schema.hide, false)
|
||||
}
|
||||
})
|
||||
|
||||
await app.register(cors, {
|
||||
delegator: () => ({ origin: '*' }),
|
||||
hideOptionsRoute: false
|
||||
})
|
||||
|
||||
await app.ready()
|
||||
t.assert.ok(app)
|
||||
await app.close()
|
||||
})
|
||||
237
node_modules/@fastify/cors/test/vary.test.js
generated
vendored
Normal file
237
node_modules/@fastify/cors/test/vary.test.js
generated
vendored
Normal file
@@ -0,0 +1,237 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const { createAddFieldnameToVary } = require('../vary')
|
||||
const { parse } = require('../vary')
|
||||
|
||||
test('Should set * even if we set a specific field', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const addOriginToVary = createAddFieldnameToVary('Origin')
|
||||
const replyMock = {
|
||||
getHeader () {
|
||||
return '*'
|
||||
},
|
||||
header () {
|
||||
t.fail('Should not be here')
|
||||
}
|
||||
}
|
||||
|
||||
addOriginToVary(replyMock)
|
||||
t.assert.ok(true) // equalivant to tap t.pass()
|
||||
})
|
||||
|
||||
test('Should set * even if we set a specific field', t => {
|
||||
t.plan(2)
|
||||
|
||||
const addWildcardToVary = createAddFieldnameToVary('*')
|
||||
const replyMock = {
|
||||
getHeader () {
|
||||
return 'Origin'
|
||||
},
|
||||
header (name, value) {
|
||||
t.assert.deepStrictEqual(name, 'Vary')
|
||||
t.assert.deepStrictEqual(value, '*')
|
||||
}
|
||||
}
|
||||
|
||||
addWildcardToVary(replyMock)
|
||||
})
|
||||
|
||||
test('Should set * when field contains a *', t => {
|
||||
t.plan(3)
|
||||
|
||||
const addOriginToVary = createAddFieldnameToVary('Origin')
|
||||
const replyMock = {
|
||||
getHeader () {
|
||||
return ['Origin', '*', 'Access-Control-Request-Headers']
|
||||
},
|
||||
header (name, value) {
|
||||
t.assert.deepStrictEqual(name, 'Vary')
|
||||
t.assert.deepStrictEqual(value, '*')
|
||||
}
|
||||
}
|
||||
|
||||
addOriginToVary(replyMock)
|
||||
t.assert.ok(true) // equalivant to tap t.pass()
|
||||
})
|
||||
|
||||
test('Should concat vary values', t => {
|
||||
t.plan(3)
|
||||
|
||||
const addOriginToVary = createAddFieldnameToVary('Origin')
|
||||
const replyMock = {
|
||||
getHeader () {
|
||||
return 'Access-Control-Request-Headers'
|
||||
},
|
||||
header (name, value) {
|
||||
t.assert.deepStrictEqual(name, 'Vary')
|
||||
t.assert.deepStrictEqual(value, 'Access-Control-Request-Headers, Origin')
|
||||
}
|
||||
}
|
||||
|
||||
addOriginToVary(replyMock)
|
||||
t.assert.ok(true) // equalivant to tap t.pass()
|
||||
})
|
||||
|
||||
test('Should concat vary values ignoring consecutive commas', t => {
|
||||
t.plan(3)
|
||||
|
||||
const addOriginToVary = createAddFieldnameToVary('Origin')
|
||||
const replyMock = {
|
||||
getHeader () {
|
||||
return ' Access-Control-Request-Headers,Access-Control-Request-Method'
|
||||
},
|
||||
header (name, value) {
|
||||
t.assert.deepStrictEqual(name, 'Vary')
|
||||
t.assert.deepStrictEqual(value, ' Access-Control-Request-Headers,Access-Control-Request-Method, Origin')
|
||||
}
|
||||
}
|
||||
|
||||
addOriginToVary(replyMock)
|
||||
t.assert.ok(true) // equalivant to tap t.pass()
|
||||
})
|
||||
|
||||
test('Should concat vary values ignoring whitespace', t => {
|
||||
t.plan(3)
|
||||
|
||||
const addOriginToVary = createAddFieldnameToVary('Origin')
|
||||
const replyMock = {
|
||||
getHeader () {
|
||||
return ' Access-Control-Request-Headers ,Access-Control-Request-Method'
|
||||
},
|
||||
header (name, value) {
|
||||
t.assert.deepStrictEqual(name, 'Vary')
|
||||
t.assert.deepStrictEqual(value, ' Access-Control-Request-Headers ,Access-Control-Request-Method, Origin')
|
||||
}
|
||||
}
|
||||
|
||||
addOriginToVary(replyMock)
|
||||
t.assert.ok(true) // equalivant to tap t.pass()
|
||||
})
|
||||
|
||||
test('Should set the field as value for vary if no vary is defined', t => {
|
||||
t.plan(2)
|
||||
|
||||
const addOriginToVary = createAddFieldnameToVary('Origin')
|
||||
const replyMock = {
|
||||
getHeader () {
|
||||
return undefined
|
||||
},
|
||||
header (name, value) {
|
||||
t.assert.deepStrictEqual(name, 'Vary')
|
||||
t.assert.deepStrictEqual(value, 'Origin')
|
||||
}
|
||||
}
|
||||
|
||||
addOriginToVary(replyMock)
|
||||
})
|
||||
|
||||
test('Should set * as value for vary if vary contains *', t => {
|
||||
t.plan(2)
|
||||
|
||||
const addOriginToVary = createAddFieldnameToVary('Origin')
|
||||
const replyMock = {
|
||||
getHeader () {
|
||||
return 'Accept,*'
|
||||
},
|
||||
header (name, value) {
|
||||
t.assert.deepStrictEqual(name, 'Vary')
|
||||
t.assert.deepStrictEqual(value, '*')
|
||||
}
|
||||
}
|
||||
|
||||
addOriginToVary(replyMock)
|
||||
})
|
||||
|
||||
test('Should set Accept-Encoding as value for vary if vary is empty string', t => {
|
||||
t.plan(2)
|
||||
|
||||
const addAcceptEncodingToVary = createAddFieldnameToVary('Accept-Encoding')
|
||||
const replyMock = {
|
||||
getHeader () {
|
||||
return ''
|
||||
},
|
||||
header (name, value) {
|
||||
t.assert.deepStrictEqual(name, 'Vary')
|
||||
t.assert.deepStrictEqual(value, 'Accept-Encoding')
|
||||
}
|
||||
}
|
||||
|
||||
addAcceptEncodingToVary(replyMock)
|
||||
})
|
||||
|
||||
test('Should have no issues with values containing dashes', t => {
|
||||
t.plan(2)
|
||||
|
||||
const addXFooToVary = createAddFieldnameToVary('X-Foo')
|
||||
const replyMock = {
|
||||
value: 'Accept-Encoding',
|
||||
getHeader () {
|
||||
return this.value
|
||||
},
|
||||
header (name, value) {
|
||||
t.assert.deepStrictEqual(name, 'Vary')
|
||||
t.assert.deepStrictEqual(value, 'Accept-Encoding, X-Foo')
|
||||
this.value = value
|
||||
}
|
||||
}
|
||||
|
||||
addXFooToVary(replyMock)
|
||||
addXFooToVary(replyMock)
|
||||
})
|
||||
|
||||
test('Should ignore the header as value for vary if it is already in vary', t => {
|
||||
t.plan(1)
|
||||
|
||||
const addOriginToVary = createAddFieldnameToVary('Origin')
|
||||
const replyMock = {
|
||||
getHeader () {
|
||||
return 'Origin'
|
||||
},
|
||||
header () {
|
||||
t.fail('Should not be here')
|
||||
}
|
||||
}
|
||||
addOriginToVary(replyMock)
|
||||
addOriginToVary(replyMock)
|
||||
|
||||
t.assert.ok(true) // equalivant to tap t.pass()
|
||||
})
|
||||
|
||||
test('parse', t => {
|
||||
t.plan(18)
|
||||
t.assert.deepStrictEqual(parse(''), [])
|
||||
t.assert.deepStrictEqual(parse('a'), ['a'])
|
||||
t.assert.deepStrictEqual(parse('a,b'), ['a', 'b'])
|
||||
t.assert.deepStrictEqual(parse(' a,b'), ['a', 'b'])
|
||||
t.assert.deepStrictEqual(parse('a,b '), ['a', 'b'])
|
||||
t.assert.deepStrictEqual(parse('a,b,c'), ['a', 'b', 'c'])
|
||||
t.assert.deepStrictEqual(parse('A,b,c'), ['a', 'b', 'c'])
|
||||
t.assert.deepStrictEqual(parse('a,b,c,'), ['a', 'b', 'c'])
|
||||
t.assert.deepStrictEqual(parse('a,b,c, '), ['a', 'b', 'c'])
|
||||
t.assert.deepStrictEqual(parse(',a,b,c'), ['a', 'b', 'c'])
|
||||
t.assert.deepStrictEqual(parse(' ,a,b,c'), ['a', 'b', 'c'])
|
||||
t.assert.deepStrictEqual(parse('a,,b,c'), ['a', 'b', 'c'])
|
||||
t.assert.deepStrictEqual(parse('a,,,b,,c'), ['a', 'b', 'c'])
|
||||
t.assert.deepStrictEqual(parse('a, b,c'), ['a', 'b', 'c'])
|
||||
t.assert.deepStrictEqual(parse('a, b,c'), ['a', 'b', 'c'])
|
||||
t.assert.deepStrictEqual(parse('a, , b,c'), ['a', 'b', 'c'])
|
||||
t.assert.deepStrictEqual(parse('a, , b,c'), ['a', 'b', 'c'])
|
||||
|
||||
// one for the cache
|
||||
t.assert.deepStrictEqual(parse('A,b,c'), ['a', 'b', 'c'])
|
||||
})
|
||||
|
||||
test('createAddFieldnameToVary', async t => {
|
||||
t.plan(4)
|
||||
t.assert.strictEqual(typeof createAddFieldnameToVary('valid-header'), 'function')
|
||||
await t.assert.rejects(
|
||||
async () => createAddFieldnameToVary('invalid:header'),
|
||||
(err) => {
|
||||
t.assert.strictEqual(err.name, 'TypeError')
|
||||
t.assert.strictEqual(err.message, 'Fieldname contains invalid characters.')
|
||||
return true
|
||||
}
|
||||
)
|
||||
})
|
||||
126
node_modules/@fastify/cors/types/index.d.ts
generated
vendored
Normal file
126
node_modules/@fastify/cors/types/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
/// <reference types="node" />
|
||||
|
||||
import { FastifyInstance, FastifyPluginCallback, FastifyRequest, LogLevel } from 'fastify'
|
||||
|
||||
type OriginCallback = (err: Error | null, origin: ValueOrArray<OriginType>) => void
|
||||
type OriginType = string | boolean | RegExp
|
||||
type ValueOrArray<T> = T | ArrayOfValueOrArray<T>
|
||||
|
||||
interface ArrayOfValueOrArray<T> extends Array<ValueOrArray<T>> {
|
||||
}
|
||||
|
||||
type FastifyCorsPlugin = FastifyPluginCallback<
|
||||
NonNullable<fastifyCors.FastifyCorsOptions> | fastifyCors.FastifyCorsOptionsDelegate
|
||||
>
|
||||
|
||||
type FastifyCorsHook =
|
||||
| 'onRequest'
|
||||
| 'preParsing'
|
||||
| 'preValidation'
|
||||
| 'preHandler'
|
||||
| 'preSerialization'
|
||||
| 'onSend'
|
||||
|
||||
declare namespace fastifyCors {
|
||||
export type OriginFunction = (origin: string | undefined, callback: OriginCallback) => void
|
||||
export type AsyncOriginFunction = (origin: string | undefined) => Promise<ValueOrArray<OriginType>>
|
||||
|
||||
export interface FastifyCorsOptions {
|
||||
/**
|
||||
* Configures the Lifecycle Hook.
|
||||
*/
|
||||
hook?: FastifyCorsHook;
|
||||
|
||||
/**
|
||||
* Configures the delegate function.
|
||||
*/
|
||||
delegator?: FastifyCorsOptionsDelegate;
|
||||
|
||||
/**
|
||||
* Configures the Access-Control-Allow-Origin CORS header.
|
||||
*/
|
||||
origin?: ValueOrArray<OriginType> | fastifyCors.AsyncOriginFunction | fastifyCors.OriginFunction;
|
||||
/**
|
||||
* Configures the Access-Control-Allow-Credentials CORS header.
|
||||
* Set to true to pass the header, otherwise it is omitted.
|
||||
*/
|
||||
credentials?: boolean;
|
||||
/**
|
||||
* Configures the Access-Control-Expose-Headers CORS header.
|
||||
* Expects a comma-delimited string (ex: 'Content-Range,X-Content-Range')
|
||||
* or an array (ex: ['Content-Range', 'X-Content-Range']).
|
||||
* If not specified, no custom headers are exposed.
|
||||
*/
|
||||
exposedHeaders?: string | string[];
|
||||
/**
|
||||
* Configures the Access-Control-Allow-Headers CORS header.
|
||||
* Expects a comma-delimited string (ex: 'Content-Type,Authorization')
|
||||
* or an array (ex: ['Content-Type', 'Authorization']). If not
|
||||
* specified, defaults to reflecting the headers specified in the
|
||||
* request's Access-Control-Request-Headers header.
|
||||
*/
|
||||
allowedHeaders?: string | string[];
|
||||
/**
|
||||
* Configures the Access-Control-Allow-Methods CORS header.
|
||||
* Expects a comma-delimited string (ex: 'GET,PUT,POST') or an array (ex: ['GET', 'PUT', 'POST']).
|
||||
*/
|
||||
methods?: string | string[];
|
||||
/**
|
||||
* Configures the Access-Control-Max-Age CORS header.
|
||||
* Set to an integer to pass the header, otherwise it is omitted.
|
||||
*/
|
||||
maxAge?: number;
|
||||
/**
|
||||
* Configures the Cache-Control header for CORS preflight responses.
|
||||
* Set to an integer to pass the header as `Cache-Control: max-age=${cacheControl}`,
|
||||
* or set to a string to pass the header as `Cache-Control: ${cacheControl}` (fully define
|
||||
* the header value), otherwise the header is omitted.
|
||||
*/
|
||||
cacheControl?: number | string;
|
||||
/**
|
||||
* Pass the CORS preflight response to the route handler (default: false).
|
||||
*/
|
||||
preflightContinue?: boolean;
|
||||
/**
|
||||
* Provides a status code to use for successful OPTIONS requests,
|
||||
* since some legacy browsers (IE11, various SmartTVs) choke on 204.
|
||||
*/
|
||||
optionsSuccessStatus?: number;
|
||||
/**
|
||||
* Pass the CORS preflight response to the route handler (default: true).
|
||||
*/
|
||||
preflight?: boolean;
|
||||
/**
|
||||
* Enforces strict requirement of the CORS preflight request headers (Access-Control-Request-Method and Origin).
|
||||
* Preflight requests without the required headers will result in 400 errors when set to `true` (default: `true`).
|
||||
*/
|
||||
strictPreflight?: boolean;
|
||||
/**
|
||||
* Hide options route from the documentation built using fastify-swagger (default: true).
|
||||
*/
|
||||
hideOptionsRoute?: boolean;
|
||||
|
||||
/**
|
||||
* Sets the Fastify log level specifically for the internal OPTIONS route
|
||||
* used to handle CORS preflight requests. For example, setting this to `'silent'`
|
||||
* will prevent these requests from being logged.
|
||||
* Useful for reducing noise in application logs.
|
||||
* Default: inherits Fastify's global log level.
|
||||
*/
|
||||
logLevel?: LogLevel;
|
||||
}
|
||||
|
||||
export interface FastifyCorsOptionsDelegateCallback { (req: FastifyRequest, cb: (error: Error | null, corsOptions?: FastifyCorsOptions) => void): void }
|
||||
export interface FastifyCorsOptionsDelegatePromise { (req: FastifyRequest): Promise<FastifyCorsOptions> }
|
||||
export type FastifyCorsOptionsDelegate = FastifyCorsOptionsDelegateCallback | FastifyCorsOptionsDelegatePromise
|
||||
export type FastifyPluginOptionsDelegate<T = FastifyCorsOptionsDelegate> = (instance: FastifyInstance) => T
|
||||
|
||||
export const fastifyCors: FastifyCorsPlugin
|
||||
export { fastifyCors as default }
|
||||
}
|
||||
|
||||
declare function fastifyCors (
|
||||
...params: Parameters<FastifyCorsPlugin>
|
||||
): ReturnType<FastifyCorsPlugin>
|
||||
|
||||
export = fastifyCors
|
||||
388
node_modules/@fastify/cors/types/index.test-d.ts
generated
vendored
Normal file
388
node_modules/@fastify/cors/types/index.test-d.ts
generated
vendored
Normal file
@@ -0,0 +1,388 @@
|
||||
import fastify, { FastifyRequest } from 'fastify'
|
||||
import { expectType } from 'tsd'
|
||||
import fastifyCors, {
|
||||
AsyncOriginFunction,
|
||||
FastifyCorsOptions,
|
||||
FastifyCorsOptionsDelegate,
|
||||
FastifyCorsOptionsDelegatePromise,
|
||||
FastifyPluginOptionsDelegate,
|
||||
OriginFunction
|
||||
} from '..'
|
||||
|
||||
const app = fastify()
|
||||
|
||||
app.register(fastifyCors)
|
||||
|
||||
app.register(fastifyCors, {
|
||||
origin: true,
|
||||
allowedHeaders: 'authorization,content-type',
|
||||
methods: 'GET,POST,PUT,PATCH,DELETE,OPTIONS',
|
||||
credentials: true,
|
||||
exposedHeaders: 'authorization',
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
app.register(fastifyCors, {
|
||||
origin: true,
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 'public, max-age=3500',
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
app.register(fastifyCors, {
|
||||
origin: '*',
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
app.register(fastifyCors, {
|
||||
origin: /\*/,
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
app.register(fastifyCors, {
|
||||
origin: ['*', 'something'],
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
app.register(fastifyCors, {
|
||||
origin: [/\*/, /something/],
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
const corsDelegate: OriginFunction = (origin, cb) => {
|
||||
if (origin === undefined || /localhost/.test(origin)) {
|
||||
cb(null, true)
|
||||
return
|
||||
}
|
||||
cb(new Error(), false)
|
||||
}
|
||||
|
||||
app.register(fastifyCors, {
|
||||
origin: corsDelegate,
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
const asyncCorsDelegate: OriginFunction = async (origin) => {
|
||||
if (origin === undefined || /localhost/.test(origin)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
app.register(fastifyCors, {
|
||||
origin: asyncCorsDelegate,
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
app.register(fastifyCors, {
|
||||
origin: (_origin, cb) => cb(null, true)
|
||||
})
|
||||
|
||||
app.register(fastifyCors, {
|
||||
origin: (_origin, cb) => cb(null, '*')
|
||||
})
|
||||
|
||||
app.register(fastifyCors, {
|
||||
origin: (_origin, cb) => cb(null, /\*/)
|
||||
})
|
||||
|
||||
const appHttp2 = fastify({ http2: true })
|
||||
|
||||
appHttp2.register(fastifyCors)
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
origin: true,
|
||||
allowedHeaders: 'authorization,content-type',
|
||||
methods: 'GET,POST,PUT,PATCH,DELETE,OPTIONS',
|
||||
credentials: true,
|
||||
exposedHeaders: 'authorization',
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false,
|
||||
logLevel: 'silent'
|
||||
})
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
origin: true,
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
origin: '*',
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
origin: /\*/,
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
origin: ['*', 'something'],
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
origin: [/\*/, /something/],
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
origin: (origin: string | undefined, cb: (err: Error | null, allow: boolean) => void) => {
|
||||
if (origin === undefined || /localhost/.test(origin)) {
|
||||
cb(null, true)
|
||||
return
|
||||
}
|
||||
cb(new Error(), false)
|
||||
},
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
|
||||
appHttp2.register(fastifyCors, (): FastifyCorsOptionsDelegate => (_req, cb) => {
|
||||
cb(null, {
|
||||
origin: [/\*/, /something/],
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
})
|
||||
|
||||
appHttp2.register(fastifyCors, (): FastifyCorsOptionsDelegatePromise => () => {
|
||||
return Promise.resolve({
|
||||
origin: [/\*/, /something/],
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
})
|
||||
|
||||
const delegate: FastifyPluginOptionsDelegate<FastifyCorsOptionsDelegatePromise> = () => async () => {
|
||||
return {
|
||||
origin: [/\*/, /something/],
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 13000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
}
|
||||
}
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
hook: 'onRequest'
|
||||
})
|
||||
appHttp2.register(fastifyCors, {
|
||||
hook: 'preParsing'
|
||||
})
|
||||
appHttp2.register(fastifyCors, {
|
||||
hook: 'preValidation'
|
||||
})
|
||||
appHttp2.register(fastifyCors, {
|
||||
hook: 'preHandler'
|
||||
})
|
||||
appHttp2.register(fastifyCors, {
|
||||
hook: 'preSerialization'
|
||||
})
|
||||
appHttp2.register(fastifyCors, {
|
||||
hook: 'onSend'
|
||||
})
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
hook: 'preParsing',
|
||||
delegator: (req, cb) => {
|
||||
if (req.url.startsWith('/some-value')) {
|
||||
cb(new Error())
|
||||
}
|
||||
cb(null, {
|
||||
origin: [/\*/, /something/],
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 12000,
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
hook: 'preParsing',
|
||||
delegator: async (_req: FastifyRequest): Promise<FastifyCorsOptions> => {
|
||||
return {
|
||||
origin: [/\*/, /something/],
|
||||
allowedHeaders: ['authorization', 'content-type'],
|
||||
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||
credentials: true,
|
||||
exposedHeaders: ['authorization'],
|
||||
maxAge: 13000,
|
||||
cacheControl: 'public, max-age=3500',
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 200,
|
||||
preflight: false,
|
||||
strictPreflight: false
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
appHttp2.register(fastifyCors, delegate)
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
hook: 'preParsing',
|
||||
origin: function (origin, cb) {
|
||||
expectType<string | undefined>(origin)
|
||||
cb(null, false)
|
||||
},
|
||||
})
|
||||
|
||||
const asyncOriginFn: AsyncOriginFunction = async function (origin): Promise<boolean> {
|
||||
expectType<string | undefined>(origin)
|
||||
return false
|
||||
}
|
||||
|
||||
appHttp2.register(fastifyCors, {
|
||||
hook: 'preParsing',
|
||||
origin: asyncOriginFn,
|
||||
})
|
||||
116
node_modules/@fastify/cors/vary.js
generated
vendored
Normal file
116
node_modules/@fastify/cors/vary.js
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
'use strict'
|
||||
|
||||
const { FifoMap: FifoCache } = require('toad-cache')
|
||||
|
||||
/**
|
||||
* Field Value Components
|
||||
* Most HTTP header field values are defined using common syntax
|
||||
* components (token, quoted-string, and comment) separated by
|
||||
* whitespace or specific delimiting characters. Delimiters are chosen
|
||||
* from the set of US-ASCII visual characters not allowed in a token
|
||||
* (DQUOTE and "(),/:;<=>?@[\]{}").
|
||||
*
|
||||
* field-name = token
|
||||
* token = 1*tchar
|
||||
* tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
|
||||
* / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
|
||||
* / DIGIT / ALPHA
|
||||
* ; any VCHAR, except delimiters
|
||||
*
|
||||
* @see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6
|
||||
*/
|
||||
|
||||
const validFieldnameRE = /^[!#$%&'*+\-.^\w`|~]+$/u
|
||||
function validateFieldname (fieldname) {
|
||||
if (validFieldnameRE.test(fieldname) === false) {
|
||||
throw new TypeError('Fieldname contains invalid characters.')
|
||||
}
|
||||
}
|
||||
|
||||
function parse (header) {
|
||||
header = header.trim().toLowerCase()
|
||||
const result = []
|
||||
|
||||
if (header.length === 0) {
|
||||
// pass through
|
||||
} else if (header.indexOf(',') === -1) {
|
||||
result.push(header)
|
||||
} else {
|
||||
const il = header.length
|
||||
let i = 0
|
||||
let pos = 0
|
||||
let char
|
||||
|
||||
// tokenize the header
|
||||
for (i; i < il; ++i) {
|
||||
char = header[i]
|
||||
// when we have whitespace set the pos to the next position
|
||||
if (char === ' ') {
|
||||
pos = i + 1
|
||||
// `,` is the separator of vary-values
|
||||
} else if (char === ',') {
|
||||
// if pos and current position are not the same we have a valid token
|
||||
if (pos !== i) {
|
||||
result.push(header.slice(pos, i))
|
||||
}
|
||||
// reset the positions
|
||||
pos = i + 1
|
||||
}
|
||||
}
|
||||
|
||||
if (pos !== i) {
|
||||
result.push(header.slice(pos, i))
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function createAddFieldnameToVary (fieldname) {
|
||||
const headerCache = new FifoCache(1000)
|
||||
|
||||
validateFieldname(fieldname)
|
||||
|
||||
return function (reply) {
|
||||
let header = reply.getHeader('Vary')
|
||||
|
||||
if (!header) {
|
||||
reply.header('Vary', fieldname)
|
||||
return
|
||||
}
|
||||
|
||||
if (header === '*') {
|
||||
return
|
||||
}
|
||||
|
||||
if (fieldname === '*') {
|
||||
reply.header('Vary', '*')
|
||||
return
|
||||
}
|
||||
|
||||
if (Array.isArray(header)) {
|
||||
header = header.join(', ')
|
||||
}
|
||||
|
||||
if (headerCache.get(header) === undefined) {
|
||||
const vals = parse(header)
|
||||
|
||||
if (vals.indexOf('*') !== -1) {
|
||||
headerCache.set(header, '*')
|
||||
} else if (vals.indexOf(fieldname.toLowerCase()) === -1) {
|
||||
headerCache.set(header, header + ', ' + fieldname)
|
||||
} else {
|
||||
headerCache.set(header, null)
|
||||
}
|
||||
}
|
||||
const cached = headerCache.get(header)
|
||||
if (cached !== null) {
|
||||
reply.header('Vary', cached)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.createAddFieldnameToVary = createAddFieldnameToVary
|
||||
module.exports.addOriginToVaryHeader = createAddFieldnameToVary('Origin')
|
||||
module.exports.addAccessControlRequestHeadersToVaryHeader = createAddFieldnameToVary('Access-Control-Request-Headers')
|
||||
module.exports.parse = parse
|
||||
Reference in New Issue
Block a user