@fastify/cors
Advanced tools
@@ -17,2 +17,5 @@ name: CI | ||
| permissions: | ||
| contents: read | ||
| jobs: | ||
@@ -19,0 +22,0 @@ test: |
+6
-2
@@ -49,2 +49,4 @@ 'use strict' | ||
| let hideOptionsRoute = true | ||
| let logLevel | ||
| if (typeof opts === 'function') { | ||
@@ -56,3 +58,2 @@ handleCorsOptionsDelegator(opts, fastify, { hook: defaultOptions.hook }, next) | ||
| } else { | ||
| if (opts.hideOptionsRoute !== undefined) hideOptionsRoute = opts.hideOptionsRoute | ||
| const corsOptions = normalizeCorsOptions(opts) | ||
@@ -70,2 +71,4 @@ validateHook(corsOptions.hook, next) | ||
| } | ||
| if (opts.logLevel !== undefined) logLevel = opts.logLevel | ||
| if (opts.hideOptionsRoute !== undefined) hideOptionsRoute = opts.hideOptionsRoute | ||
@@ -78,3 +81,4 @@ // The preflight reply must occur in the hook. This allows fastify-cors to reply to | ||
| // This route simply enables fastify to accept preflight requests. | ||
| fastify.options('*', { schema: { hide: hideOptionsRoute } }, (req, reply) => { | ||
| fastify.options('*', { schema: { hide: hideOptionsRoute }, logLevel }, (req, reply) => { | ||
| if (!req.corsPreflightEnabled) { | ||
@@ -81,0 +85,0 @@ // Do not handle preflight requests if the origin option disabled CORS |
+3
-1
| MIT License | ||
| Copyright (c) 2018 Fastify | ||
| 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 | ||
@@ -6,0 +8,0 @@ of this software and associated documentation files (the "Software"), to deal |
+3
-3
| { | ||
| "name": "@fastify/cors", | ||
| "version": "11.0.1", | ||
| "version": "11.1.0", | ||
| "description": "Fastify CORS", | ||
@@ -63,3 +63,3 @@ "main": "index.js", | ||
| "@fastify/pre-commit": "^2.1.0", | ||
| "@types/node": "^22.0.0", | ||
| "@types/node": "^24.0.8", | ||
| "c8": "^10.1.2", | ||
@@ -70,3 +70,3 @@ "cors": "^2.8.5", | ||
| "neostandard": "^0.12.0", | ||
| "tsd": "^0.31.1", | ||
| "tsd": "^0.32.0", | ||
| "typescript": "~5.8.2" | ||
@@ -73,0 +73,0 @@ }, |
+8
-4
@@ -18,9 +18,9 @@ # @fastify/cors | ||
| | ---------------|-----------------| | ||
| | `^11.x` | `^5.x` | | ||
| | `^10.x` | `^5.x` | | ||
| | `^8.x` | `^4.x` | | ||
| | `^7.x` | `^3.x` | | ||
| | `^3.x` | `^2.x` | | ||
| | `^1.x` | `^1.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 | ||
@@ -79,2 +79,6 @@ in the table above. | ||
| * `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. | ||
@@ -196,2 +200,2 @@ #### :warning: DoS attacks | ||
| Licensed under [MIT](./LICENSE).<br/> | ||
| [`expressjs/cors` license](https://github.com/expressjs/cors/blob/master/LICENSE) | ||
| [`expressjs/cors` license](https://github.com/expressjs/cors/blob/master/LICENSE) |
+102
-0
@@ -489,1 +489,103 @@ 'use strict' | ||
| }) | ||
| 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() | ||
| }) |
+11
-2
| /// <reference types="node" /> | ||
| import { FastifyInstance, FastifyPluginCallback, FastifyRequest } from 'fastify' | ||
| import { FastifyInstance, FastifyPluginCallback, FastifyRequest, LogLevel } from 'fastify' | ||
@@ -90,3 +90,3 @@ type OriginCallback = (err: Error | null, origin: ValueOrArray<OriginType>) => void | ||
| /** | ||
| * Pass the CORS preflight response to the route handler (default: false). | ||
| * Pass the CORS preflight response to the route handler (default: true). | ||
| */ | ||
@@ -103,2 +103,11 @@ preflight?: boolean; | ||
| 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; | ||
| } | ||
@@ -105,0 +114,0 @@ |
@@ -168,3 +168,4 @@ import fastify, { FastifyRequest } from 'fastify' | ||
| preflight: false, | ||
| strictPreflight: false | ||
| strictPreflight: false, | ||
| logLevel: 'silent' | ||
| }) | ||
@@ -171,0 +172,0 @@ |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
118376
2.82%3225
2.94%198
1.54%2
100%