parent
c945240adf
commit
f4f6870831
@ -1,22 +0,0 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2017-2020 Denis Fäcke
|
||||
|
||||
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.
|
@ -1,122 +0,0 @@
|
||||
# fastify-session
|
||||
|
||||

|
||||
[](https://coveralls.io/github/SerayaEryn/fastify-session?branch=master)
|
||||
[](https://www.npmjs.com/package/fastify-session)
|
||||
[](https://standardjs.com)
|
||||
|
||||
A session plugin for [fastify](http://fastify.io/).
|
||||
Requires the [fastify-cookie](https://github.com/fastify/fastify-cookie) plugin.
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
npm install fastify-session
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const fastify = require('fastify');
|
||||
const fastifySession = require('fastify-session');
|
||||
const fastifyCookie = require('fastify-cookie');
|
||||
|
||||
const app = fastify();
|
||||
app.register(fastifyCookie);
|
||||
app.register(fastifySession, {secret: 'a secret with minimum length of 32 characters'});
|
||||
```
|
||||
Store data in the session by adding it to the `session` decorator at the `request`:
|
||||
```js
|
||||
app.register(fastifySession, {secret: 'a secret with minimum length of 32 characters'});
|
||||
app.addHook('preHandler', (request, reply, next) => {
|
||||
request.session.user = {name: 'max'};
|
||||
next();
|
||||
})
|
||||
```
|
||||
**NOTE**: For all unencrypted (HTTP) connections, you need to set the `secure` cookie option to `false`. Look below for all cookie options and their details.
|
||||
The `sessionStore` decorator of the `request` allows to get, save and delete sessions.
|
||||
```js
|
||||
app.register(fastifySession, {secret: 'a secret with minimum length of 32 characters'});
|
||||
app.addHook('preHandler', (request, reply, next) => {
|
||||
const session = request.session;
|
||||
request.sessionStore.destroy(session.sessionId, next);
|
||||
})
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
* [Authentication](https://github.com/fastify/example/tree/master/fastify-session-authentication)
|
||||
|
||||
## API
|
||||
### session(fastify, options, next)
|
||||
The session plugin accepts the following options. It decorates the request with the `sessionStore` and a `session` object. The session data is stored server side using the configured session store.
|
||||
#### options
|
||||
##### secret (required)
|
||||
The secret used to sign the cookie. Must be an array of strings, or a string with length 32 or greater.
|
||||
|
||||
If an array, the first secret is used to sign new cookies, and is the first one to be checked for incoming cookies.
|
||||
Further secrets in the array are used to check incoming cookies, in the order specified.
|
||||
|
||||
Note that the array may be manipulated by the rest of the application during its life cycle. This can be done by storing the array in a separate variable that is later manipulated with mutating methods like unshift(), pop(), splice(), etc.
|
||||
This can be used to rotate the signing secret at regular intervals. A secret should remain somewhere in the array as long as there are active sessions with cookies signed by it. Secrets management is left up to the rest of the application.
|
||||
##### cookieName (optional)
|
||||
The name of the session cookie. Defaults to `sessionId`.
|
||||
##### cookie
|
||||
The options object used to generate the `Set-Cookie` header of the session cookie. May have the following properties:
|
||||
* `path` - The `Path` attribute. Defaults to `/` (the root path).
|
||||
* `maxAge` - A `number` in milliseconds that specifies the `Expires` attribute by adding the specified milliseconds to the current date. If both `expires` and `maxAge` are set, then `expires` is used.
|
||||
* `httpOnly` - The `boolean` value of the `HttpOnly` attribute. Defaults to true.
|
||||
* `secure` - The `boolean` value of the `Secure` attribute. Set this option to false when communicating over an unencrypted (HTTP) connection. Value can be set to `auto`; in this case the `Secure` attribute will be set to false for HTTP request, in case of HTTPS it will be set to true. Defaults to true.
|
||||
* `expires` - The expiration `date` used for the `Expires` attribute. If both `expires` and `maxAge` are set, then `expires` is used.
|
||||
* `sameSite`- The `boolean` or `string` of the `SameSite` attribute. Using `Secure` mode with `auto` attribute will change the behaviour of the `SameSite` attribute in `http` mode. The `SameSite` attribute will automatically be set to `Lax` with a `http` request. See this [link](https://www.chromium.org/updates/same-site).
|
||||
* `domain` - The `Domain` attribute.
|
||||
|
||||
##### store
|
||||
A session store. Needs the following methods:
|
||||
* set(sessionId, session, callback)
|
||||
* get(sessionId, callback)
|
||||
* destroy(sessionId, callback)
|
||||
|
||||
Compatible to stores from [express-session](https://github.com/expressjs/session).
|
||||
|
||||
Defaults to a simple in memory store.</br>
|
||||
**Note**: The default store should not be used in a production environment because it will leak memory.
|
||||
|
||||
##### saveUninitialized (optional)
|
||||
Save sessions to the store, even when they are new and not modified. Defaults to `true`.
|
||||
Setting this to `false` can be useful to save storage space and to comply with the EU cookie law.
|
||||
|
||||
##### idGenerator (optional)
|
||||
|
||||
Function used to generate new session IDs. Defaults to [`uid(24)`](https://github.com/crypto-utils/uid-safe).
|
||||
|
||||
#### request.session
|
||||
|
||||
Allows to access or modify the session data.
|
||||
|
||||
#### request.destroySession(callback)
|
||||
|
||||
Allows to destroy the session in the store
|
||||
|
||||
#### Session#touch()
|
||||
|
||||
Updates the `expires` property of the session.
|
||||
|
||||
#### Session#regenerate()
|
||||
|
||||
Regenerates the session by generating a new `sessionId`.
|
||||
|
||||
### fastify.decryptSession(sessionId, request, next)
|
||||
This plugin also decorates the fastify instance with `decryptSession` in case you want to decrypt the session manually.
|
||||
|
||||
```js
|
||||
const { sessionId } = fastify.parseCookie(cookieHeader);
|
||||
const request = {}
|
||||
fastify.decryptSession(sessionId, request, () => {
|
||||
// request.session should be available here
|
||||
})
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
[MIT](./LICENSE)
|
@ -1,46 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = class Cookie {
|
||||
constructor (cookieOpts) {
|
||||
this.maxAge = cookieOpts.maxAge || null
|
||||
this.path = cookieOpts.path || '/'
|
||||
this.httpOnly = cookieOpts.httpOnly !== undefined ? cookieOpts.httpOnly : true
|
||||
this.secure = cookieOpts.secure
|
||||
this.expires = getExpires(cookieOpts)
|
||||
this.sameSite = cookieOpts.sameSite || null
|
||||
this.domain = cookieOpts.domain || null
|
||||
}
|
||||
|
||||
options (secureConnection) {
|
||||
let secure = this.secure
|
||||
let sameSite = this.sameSite
|
||||
if (secure === 'auto') {
|
||||
if (secureConnection === true) {
|
||||
secure = true
|
||||
} else {
|
||||
sameSite = 'Lax'
|
||||
secure = false
|
||||
}
|
||||
} else {
|
||||
secure = this.secure
|
||||
}
|
||||
return {
|
||||
path: this.path,
|
||||
httpOnly: this.httpOnly,
|
||||
secure: secure,
|
||||
expires: this.expires,
|
||||
sameSite,
|
||||
domain: this.domain
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getExpires (cookieOpts) {
|
||||
let expires = null
|
||||
if (cookieOpts.expires) {
|
||||
expires = cookieOpts.expires
|
||||
} else if (cookieOpts.maxAge) {
|
||||
expires = new Date(Date.now() + cookieOpts.maxAge)
|
||||
}
|
||||
return expires
|
||||
}
|
@ -1,208 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const uid = require('uid-safe').sync
|
||||
const fastifyPlugin = require('fastify-plugin')
|
||||
const Store = require('./store')
|
||||
const Session = require('./session')
|
||||
const metadata = require('./metadata')
|
||||
const cookieSignature = require('cookie-signature')
|
||||
|
||||
function session (fastify, options, next) {
|
||||
const error = checkOptions(options)
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
|
||||
options = ensureDefaults(options)
|
||||
|
||||
fastify.decorate('decryptSession', (sessionId, request, callback) => {
|
||||
decryptSession(sessionId, options, request, callback)
|
||||
})
|
||||
fastify.decorateRequest('sessionStore', options.store)
|
||||
fastify.decorateRequest('session', {})
|
||||
fastify.decorateRequest('destroySession', destroySession)
|
||||
fastify.addHook('preValidation', preValidation(options))
|
||||
fastify.addHook('onSend', onSend(options))
|
||||
next()
|
||||
}
|
||||
|
||||
function decryptSession (sessionId, options, request, done) {
|
||||
const cookieOpts = options.cookie
|
||||
const idGenerator = options.idGenerator
|
||||
const secrets = options.secret
|
||||
const secretsLength = secrets.length
|
||||
const secret = secrets[0]
|
||||
|
||||
let decryptedSessionId = false
|
||||
for (let i = 0; i < secretsLength; ++i) {
|
||||
decryptedSessionId = cookieSignature.unsign(sessionId, secrets[i])
|
||||
if (decryptedSessionId !== false) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if (decryptedSessionId === false) {
|
||||
newSession(secret, request, cookieOpts, idGenerator, done)
|
||||
} else {
|
||||
options.store.get(decryptedSessionId, (err, session) => {
|
||||
if (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
newSession(secret, request, cookieOpts, idGenerator, done)
|
||||
} else {
|
||||
done(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if (!session) {
|
||||
newSession(secret, request, cookieOpts, idGenerator, done)
|
||||
return
|
||||
}
|
||||
if (session && session.expires && session.expires <= Date.now()) {
|
||||
options.store.destroy(sessionId, getDestroyCallback(secret, request, done, cookieOpts, idGenerator))
|
||||
return
|
||||
}
|
||||
request.session = new Session(
|
||||
idGenerator,
|
||||
cookieOpts,
|
||||
secret,
|
||||
session
|
||||
)
|
||||
done()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function preValidation (options) {
|
||||
const cookieOpts = options.cookie
|
||||
const idGenerator = options.idGenerator
|
||||
return function handleSession (request, reply, done) {
|
||||
const url = request.raw.url
|
||||
if (url.indexOf(cookieOpts.path || '/') !== 0) {
|
||||
done()
|
||||
return
|
||||
}
|
||||
const sessionId = request.cookies[options.cookieName]
|
||||
const secret = options.secret[0]
|
||||
if (!sessionId) {
|
||||
newSession(secret, request, cookieOpts, idGenerator, done)
|
||||
} else {
|
||||
decryptSession(sessionId, options, request, done)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onSend (options) {
|
||||
return function saveSession (request, reply, payload, done) {
|
||||
const session = request.session
|
||||
if (!session || !session.sessionId || !shouldSaveSession(request, options.cookie, options.saveUninitialized)) {
|
||||
done()
|
||||
return
|
||||
}
|
||||
options.store.set(session.sessionId, session, (err) => {
|
||||
if (err) {
|
||||
done(err)
|
||||
return
|
||||
}
|
||||
reply.setCookie(
|
||||
options.cookieName,
|
||||
session.encryptedSessionId,
|
||||
session.cookie.options(isConnectionSecure(request))
|
||||
)
|
||||
done()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function getDestroyCallback (secret, request, done, cookieOpts, idGenerator) {
|
||||
return function destroyCallback (err) {
|
||||
if (err) {
|
||||
done(err)
|
||||
return
|
||||
}
|
||||
newSession(secret, request, cookieOpts, idGenerator, done)
|
||||
}
|
||||
}
|
||||
|
||||
function newSession (secret, request, cookieOpts, idGenerator, done) {
|
||||
request.session = new Session(idGenerator, cookieOpts, secret)
|
||||
done()
|
||||
}
|
||||
|
||||
function destroySession (done) {
|
||||
const request = this
|
||||
request.sessionStore.destroy(request.session.sessionId, (err) => {
|
||||
request.session = null
|
||||
done(err)
|
||||
})
|
||||
}
|
||||
|
||||
function checkOptions (options) {
|
||||
if (!options.secret) {
|
||||
return new Error('the secret option is required!')
|
||||
}
|
||||
if (typeof options.secret === 'string' && options.secret.length < 32) {
|
||||
return new Error('the secret must have length 32 or greater')
|
||||
}
|
||||
if (Array.isArray(options.secret) && options.secret.length === 0) {
|
||||
return new Error('at least one secret is required')
|
||||
}
|
||||
}
|
||||
|
||||
function idGenerator () {
|
||||
return uid(24)
|
||||
}
|
||||
|
||||
function ensureDefaults (options) {
|
||||
options.store = options.store || new Store()
|
||||
options.idGenerator = options.idGenerator || idGenerator
|
||||
options.cookieName = options.cookieName || 'sessionId'
|
||||
options.cookie = options.cookie || {}
|
||||
options.cookie.secure = option(options.cookie, 'secure', true)
|
||||
options.saveUninitialized = option(options, 'saveUninitialized', true)
|
||||
options.secret = Array.isArray(options.secret) ? options.secret : [options.secret]
|
||||
return options
|
||||
}
|
||||
|
||||
function getRequestProto (request) {
|
||||
return request.headers['x-forwarded-proto'] || 'http'
|
||||
}
|
||||
|
||||
function isConnectionSecure (request) {
|
||||
if (isConnectionEncrypted(request)) {
|
||||
return true
|
||||
}
|
||||
return getRequestProto(request) === 'https'
|
||||
}
|
||||
|
||||
function isConnectionEncrypted (request) {
|
||||
const socket = request.raw.socket
|
||||
if (socket && socket.encrypted === true) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function shouldSaveSession (request, cookieOpts, saveUninitialized) {
|
||||
if (!saveUninitialized && !isSessionModified(request.session)) {
|
||||
return false
|
||||
}
|
||||
if (cookieOpts.secure !== true || cookieOpts.secure === 'auto') {
|
||||
return true
|
||||
}
|
||||
if (isConnectionEncrypted(request)) {
|
||||
return true
|
||||
}
|
||||
const forwardedProto = getRequestProto(request)
|
||||
return forwardedProto === 'https'
|
||||
}
|
||||
|
||||
function isSessionModified (session) {
|
||||
return (Object.keys(session).length !== 4)
|
||||
}
|
||||
|
||||
function option (options, key, def) {
|
||||
return options[key] === undefined ? def : options[key]
|
||||
}
|
||||
|
||||
exports = module.exports = fastifyPlugin(session, metadata)
|
||||
module.exports.Store = Store
|
||||
module.exports.MemoryStore = Store
|
@ -1,9 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = {
|
||||
fastify: '>=2.0.0',
|
||||
name: 'fastify-session',
|
||||
dependencies: [
|
||||
'fastify-cookie'
|
||||
]
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const Cookie = require('./cookie')
|
||||
const cookieSignature = require('cookie-signature')
|
||||
|
||||
const maxAge = Symbol('maxAge')
|
||||
const secretKey = Symbol('secretKey')
|
||||
const sign = Symbol('sign')
|
||||
const addDataToSession = Symbol('addDataToSession')
|
||||
const generateId = Symbol('generateId')
|
||||
|
||||
module.exports = class Session {
|
||||
constructor (idGenerator, cookieOpts, secret, prevSession = {}) {
|
||||
this[generateId] = idGenerator
|
||||
this.expires = null
|
||||
this.cookie = new Cookie(cookieOpts)
|
||||
this[maxAge] = cookieOpts.maxAge
|
||||
this[secretKey] = secret
|
||||
this[addDataToSession](prevSession)
|
||||
this.touch()
|
||||
if (!this.sessionId) {
|
||||
this.regenerate()
|
||||
}
|
||||
}
|
||||
|
||||
touch () {
|
||||
if (this[maxAge]) {
|
||||
this.expires = new Date(Date.now() + this[maxAge])
|
||||
this.cookie.expires = this.expires
|
||||
}
|
||||
}
|
||||
|
||||
regenerate () {
|
||||
this.sessionId = this[generateId]()
|
||||
this.encryptedSessionId = this[sign]()
|
||||
}
|
||||
|
||||
[addDataToSession] (prevSession) {
|
||||
for (const key in prevSession) {
|
||||
if (!['expires', 'cookie'].includes(key)) {
|
||||
this[key] = prevSession[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[sign] () {
|
||||
return cookieSignature.sign(this.sessionId, this[secretKey])
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const EventEmitter = require('events').EventEmitter
|
||||
const util = require('util')
|
||||
|
||||
function Store (storeMap = new Map()) {
|
||||
this.store = storeMap
|
||||
EventEmitter.call(this)
|
||||
}
|
||||
|
||||
util.inherits(Store, EventEmitter)
|
||||
|
||||
Store.prototype.set = function set (sessionId, session, callback) {
|
||||
this.store.set(sessionId, session)
|
||||
callback()
|
||||
}
|
||||
|
||||
Store.prototype.get = function get (sessionId, callback) {
|
||||
const session = this.store.get(sessionId)
|
||||
callback(null, session)
|
||||
}
|
||||
|
||||
Store.prototype.destroy = function destroy (sessionId, callback) {
|
||||
this.store.delete(sessionId)
|
||||
callback()
|
||||
}
|
||||
|
||||
module.exports = Store
|
16
node_modules/fastify-session/node_modules/fastify-plugin/.github/dependabot.yml
generated
vendored
16
node_modules/fastify-session/node_modules/fastify-plugin/.github/dependabot.yml
generated
vendored
@ -1,16 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: github-actions
|
||||
directory: '/'
|
||||
ignore:
|
||||
- dependency-name: "actions/*"
|
||||
update-types:
|
||||
["version-update:semver-minor", "version-update:semver-patch"]
|
||||
schedule:
|
||||
interval: daily
|
||||
open-pull-requests-limit: 10
|
||||
- package-ecosystem: npm
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: daily
|
||||
open-pull-requests-limit: 10
|
@ -1,21 +0,0 @@
|
||||
# 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
|
61
node_modules/fastify-session/node_modules/fastify-plugin/.github/workflows/ci.yml
generated
vendored
61
node_modules/fastify-session/node_modules/fastify-plugin/.github/workflows/ci.yml
generated
vendored
@ -1,61 +0,0 @@
|
||||
name: CI
|
||||
'on':
|
||||
push:
|
||||
paths-ignore:
|
||||
- docs/**
|
||||
- '*.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- docs/**
|
||||
- '*.md'
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
node-version:
|
||||
- 10
|
||||
- 12
|
||||
- 14
|
||||
- 16
|
||||
os:
|
||||
- macos-latest
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
npm install --ignore-scripts
|
||||
- name: Run Tests
|
||||
run: |
|
||||
npm run test:ci
|
||||
- name: Coveralls Parallel
|
||||
uses: coverallsapp/github-action@1.1.3
|
||||
with:
|
||||
github-token: ${{ secrets.github_token }}
|
||||
parallel: true
|
||||
flag-name: run-${{ matrix.node-version }}-${{ matrix.os }}
|
||||
coverage:
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Coveralls Finished
|
||||
uses: coverallsapp/github-action@1.1.3
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
parallel-finished: true
|
||||
automerge:
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
contents: write
|
||||
steps:
|
||||
- uses: fastify/github-action-merge-dependabot@v3
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
@ -1,4 +0,0 @@
|
||||
ts: false
|
||||
jsx: false
|
||||
flow: false
|
||||
coverage: true
|
@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Fastify
|
||||
|
||||
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.
|
@ -1,158 +0,0 @@
|
||||
# fastify-plugin
|
||||
|
||||

|
||||
[](https://www.npmjs.com/package/fastify-plugin)
|
||||
[](https://snyk.io/test/github/fastify/fastify-plugin)
|
||||
[](https://coveralls.io/github/fastify/fastify-plugin?branch=master)
|
||||
[](https://standardjs.com/)
|
||||
|
||||
`fastify-plugin` is a plugin helper for [Fastify](https://github.com/fastify/fastify).
|
||||
|
||||
When you build plugins for Fastify and you want that 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 v2.x & v3.x series of this module covers Fastify v3. For Fastify v2 support, refer to the v1.x series.__
|
||||
|
||||
## 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, next) {
|
||||
// your plugin code
|
||||
next()
|
||||
})
|
||||
```
|
||||
|
||||
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, next) {
|
||||
// your plugin code
|
||||
next()
|
||||
}, { fastify: '3.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, next) {
|
||||
// your plugin code
|
||||
next()
|
||||
}
|
||||
|
||||
module.exports = fp(plugin, {
|
||||
fastify: '3.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, next) {
|
||||
// your plugin code
|
||||
next()
|
||||
}
|
||||
|
||||
module.exports = fp(plugin, {
|
||||
fastify: '3.x',
|
||||
decorators: {
|
||||
fastify: ['plugin1', 'plugin2'],
|
||||
reply: ['compress']
|
||||
},
|
||||
dependencies: ['plugin1-name', 'plugin2-name']
|
||||
})
|
||||
```
|
||||
|
||||
#### 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, next) => { next() })
|
||||
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 `next` (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, next) => { }
|
||||
fp(pluginCallback)
|
||||
|
||||
// or define your own function declaration that satisfies the existing definitions
|
||||
const pluginCallbackWithTypes = (fastify: FastifyInstance, options: FastifyPluginOptions, next: (error?: FastifyError) => void): void => { }
|
||||
fp(pluginCallbackWithTypes)
|
||||
// or inline
|
||||
fp((fastify: FastifyInstance, options: FastifyPluginOptions, next: (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> => { })
|
||||
```
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
This project is kindly sponsored by:
|
||||
- [nearForm](https://nearform.com)
|
||||
- [LetzDoIt](https://www.letzdoitapp.com/)
|
||||
|
||||
## License
|
||||
|
||||
Licensed under [MIT](./LICENSE).
|
@ -1,37 +0,0 @@
|
||||
{
|
||||
"name": "fastify-plugin",
|
||||
"version": "3.0.1",
|
||||
"description": "Plugin helper for Fastify",
|
||||
"main": "plugin.js",
|
||||
"types": "plugin.d.ts",
|
||||
"scripts": {
|
||||
"test": "standard && tap test/*.js test/esm/*.js --no-check-coverage && npm run typescript",
|
||||
"test:ci": "standard && tap test/*.js test/esm/*.js --no-check-coverage --coverage-report=lcovonly && npm run typescript",
|
||||
"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)",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/fastify/fastify-plugin/issues"
|
||||
},
|
||||
"homepage": "https://github.com/fastify/fastify-plugin#readme",
|
||||
"devDependencies": {
|
||||
"@types/node": "^17.0.0",
|
||||
"fastify": "^3.3.0",
|
||||
"proxyquire": "^2.1.3",
|
||||
"standard": "^16.0.3",
|
||||
"tap": "^15.0.2",
|
||||
"tsd": "^0.19.0",
|
||||
"typescript": "^4.0.5"
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/// <reference types="fastify" />
|
||||
|
||||
import {
|
||||
FastifyPluginCallback,
|
||||
FastifyPluginAsync,
|
||||
} from 'fastify'
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
export default function fp<Options>(fn: FastifyPluginAsync<Options>, options?: PluginMetadata): FastifyPluginAsync<Options>;
|
||||
export default function fp<Options>(fn: FastifyPluginAsync<Options>, options?: string): FastifyPluginAsync<Options>;
|
||||
export default function fp<Options>(fn: FastifyPluginCallback<Options>, options?: PluginMetadata): FastifyPluginCallback<Options>;
|
||||
export default function fp<Options>(fn: FastifyPluginCallback<Options>, options?: string): FastifyPluginCallback<Options>;
|
||||
|
||||
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[]
|
||||
}
|
||||
|
||||
// Exporting PluginOptions for backward compatibility after renaming it to PluginMetadata
|
||||
export interface PluginOptions extends PluginMetadata {}
|
@ -1,85 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const extractPluginName = require('./stackParser')
|
||||
|
||||
let count = 0
|
||||
|
||||
function plugin (fn, options = {}) {
|
||||
let autoName = false
|
||||
|
||||
if (typeof 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}'`
|
||||
)
|
||||
}
|
||||
|
||||
fn[Symbol.for('skip-override')] = true
|
||||
|
||||
const pluginName = (options && options.name) || checkName(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 = pluginName + '-auto-' + count++
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
function checkName (fn) {
|
||||
if (fn.name.length > 0) return fn.name
|
||||
|
||||
try {
|
||||
throw new Error('anonymous function')
|
||||
} catch (e) {
|
||||
return extractPluginName(e.stack)
|
||||
}
|
||||
}
|
||||
|
||||
function toCamelCase (name) {
|
||||
const newName = name.replace(/-(.)/g, function (match, g1) {
|
||||
return g1.toUpperCase()
|
||||
})
|
||||
return newName
|
||||
}
|
||||
|
||||
plugin.default = plugin
|
||||
module.exports = plugin
|
@ -1,74 +0,0 @@
|
||||
import fp from './plugin';
|
||||
import fastify, { FastifyPluginCallback, FastifyPluginAsync, FastifyError, FastifyInstance, FastifyPluginOptions } from 'fastify';
|
||||
import { expectAssignable } from 'tsd'
|
||||
|
||||
interface Options {
|
||||
foo: string
|
||||
}
|
||||
|
||||
const testSymbol = Symbol('foobar')
|
||||
|
||||
// Callback
|
||||
|
||||
const pluginCallback: FastifyPluginCallback = (fastify, options, next) => { }
|
||||
expectAssignable<FastifyPluginCallback>(fp(pluginCallback))
|
||||
|
||||
const pluginCallbackWithTypes = (fastify: FastifyInstance, options: FastifyPluginOptions, next: (error?: FastifyError) => void): void => { }
|
||||
expectAssignable<FastifyPluginCallback>(fp(pluginCallbackWithTypes))
|
||||
|
||||
expectAssignable<FastifyPluginCallback>(fp((fastify: FastifyInstance, options: FastifyPluginOptions, next: (error?: FastifyError) => void): void => { }))
|
||||
|
||||
expectAssignable<FastifyPluginCallback>(fp(pluginCallback, '' ))
|
||||
expectAssignable<FastifyPluginCallback>(fp(pluginCallback, {
|
||||
fastify: '',
|
||||
name: '',
|
||||
decorators: {
|
||||
fastify: [ '', testSymbol ],
|
||||
reply: [ '', testSymbol ],
|
||||
request: [ '', testSymbol ]
|
||||
},
|
||||
dependencies: [ '' ]
|
||||
}))
|
||||
|
||||
const pluginCallbackWithOptions: FastifyPluginCallback<Options> = (fastify, options, next) => {
|
||||
expectAssignable<string>(options.foo)
|
||||
}
|
||||
|
||||
expectAssignable<FastifyPluginCallback<Options>>(fp(pluginCallbackWithOptions))
|
||||
|
||||
// Async
|
||||
|
||||
const pluginAsync: FastifyPluginAsync = async (fastify, options) => { }
|
||||
expectAssignable<FastifyPluginAsync>(fp(pluginAsync))
|
||||
|
||||
const pluginAsyncWithTypes = async (fastify: FastifyInstance, options: FastifyPluginOptions): Promise<void> => { }
|
||||
expectAssignable<FastifyPluginAsync>(fp(pluginAsyncWithTypes))
|
||||
|
||||
expectAssignable<FastifyPluginAsync>(fp(async (fastify: FastifyInstance, options: FastifyPluginOptions): Promise<void> => { }))
|
||||
expectAssignable<FastifyPluginAsync>(fp(pluginAsync, '' ))
|
||||
expectAssignable<FastifyPluginAsync>(fp(pluginAsync, {
|
||||
fastify: '',
|
||||
name: '',
|
||||
decorators: {
|
||||
fastify: [ '', testSymbol ],
|
||||
reply: [ '', testSymbol ],
|
||||
request: [ '', testSymbol ]
|
||||
},
|
||||
dependencies: [ '' ]
|
||||
}))
|
||||
|
||||
const pluginAsyncWithOptions: FastifyPluginAsync<Options> = async (fastify, options) => {
|
||||
expectAssignable<string>(options.foo)
|
||||
}
|
||||
|
||||
expectAssignable<FastifyPluginAsync<Options>>(fp(pluginAsyncWithOptions))
|
||||
|
||||
// Fastify register
|
||||
|
||||
const server = fastify()
|
||||
server.register(fp(pluginCallback))
|
||||
server.register(fp(pluginCallbackWithTypes))
|
||||
server.register(fp(pluginCallbackWithOptions))
|
||||
server.register(fp(pluginAsync))
|
||||
server.register(fp(pluginAsyncWithTypes))
|
||||
server.register(fp(pluginAsyncWithOptions))
|
@ -1,11 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const fpStackTracePattern = /at\s{1}(?:.*\.)?plugin\s{1}.*\n\s*(.*)/
|
||||
const fileNamePattern = /(\w*(\.\w*)*)\..*/
|
||||
|
||||
module.exports = 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'
|
||||
}
|
98
node_modules/fastify-session/node_modules/fastify-plugin/test/bundlers.test.js
generated
vendored
98
node_modules/fastify-session/node_modules/fastify-plugin/test/bundlers.test.js
generated
vendored
@ -1,98 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
const fp = require('../plugin')
|
||||
|
||||
test('webpack removes require.main.filename', (t) => {
|
||||
const filename = require.main.filename
|
||||
const info = console.info
|
||||
t.teardown(() => {
|
||||
require.main.filename = filename
|
||||
console.info = info
|
||||
})
|
||||
|
||||
require.main.filename = null
|
||||
|
||||
console.info = function (msg) {
|
||||
t.fail('logged: ' + msg)
|
||||
}
|
||||
|
||||
fp((fastify, opts, next) => {
|
||||
next()
|
||||
}, {
|
||||
fastify: '^3.0.0'
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('support faux modules', (t) => {
|
||||
const plugin = fp((fastify, opts, next) => {
|
||||
next()
|
||||
})
|
||||
|
||||
t.equal(plugin.default, plugin)
|
||||
t.end()
|
||||
})
|
||||
|
||||
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.equal(plugin.default, 'Existing default field')
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('support ts named imports', (t) => {
|
||||
const plugin = fp((fastify, opts, next) => {
|
||||
next()
|
||||
}, {
|
||||
name: 'hello'
|
||||
})
|
||||
|
||||
t.equal(plugin.hello, plugin)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('from kebabo-case to camelCase', (t) => {
|
||||
const plugin = fp((fastify, opts, next) => {
|
||||
next()
|
||||
}, {
|
||||
name: 'hello-world'
|
||||
})
|
||||
|
||||
t.equal(plugin.helloWorld, plugin)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('from kebab-case to camelCase multiple words', (t) => {
|
||||
const plugin = fp((fastify, opts, next) => {
|
||||
next()
|
||||
}, {
|
||||
name: 'hello-long-world'
|
||||
})
|
||||
|
||||
t.equal(plugin.helloLongWorld, plugin)
|
||||
t.end()
|
||||
})
|
||||
|
||||
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.equal(plugin.helloLongWorld, foobar)
|
||||
t.end()
|
||||
})
|
73
node_modules/fastify-session/node_modules/fastify-plugin/test/checkVersion.test.js
generated
vendored
73
node_modules/fastify-session/node_modules/fastify-plugin/test/checkVersion.test.js
generated
vendored
@ -1,73 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
const fp = require('../plugin')
|
||||
|
||||
test('checkVersion having require.main.filename', (t) => {
|
||||
const info = console.info
|
||||
t.ok(require.main.filename)
|
||||
t.teardown(() => {
|
||||
console.info = info
|
||||
})
|
||||
|
||||
console.info = function (msg) {
|
||||
t.fail('logged: ' + msg)
|
||||
}
|
||||
|
||||
fp((fastify, opts, next) => {
|
||||
next()
|
||||
}, {
|
||||
fastify: '^3.0.0'
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('checkVersion having no require.main.filename but process.argv[1]', (t) => {
|
||||
const filename = require.main.filename
|
||||
const info = console.info
|
||||
t.teardown(() => {
|
||||
require.main.filename = filename
|
||||
console.info = info
|
||||
})
|
||||
|
||||
require.main.filename = null
|
||||
|
||||
console.info = function (msg) {
|
||||
t.fail('logged: ' + msg)
|
||||
}
|
||||
|
||||
fp((fastify, opts, next) => {
|
||||
next()
|
||||
}, {
|
||||
fastify: '^3.0.0'
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
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.teardown(() => {
|
||||
require.main.filename = filename
|
||||
process.argv = argv
|
||||
console.info = info
|
||||
})
|
||||
|
||||
require.main.filename = null
|
||||
process.argv[1] = null
|
||||
|
||||
console.info = function (msg) {
|
||||
t.fail('logged: ' + msg)
|
||||
}
|
||||
|
||||
fp((fastify, opts, next) => {
|
||||
next()
|
||||
}, {
|
||||
fastify: '^3.0.0'
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
16
node_modules/fastify-session/node_modules/fastify-plugin/test/composite.test.js
generated
vendored
16
node_modules/fastify-session/node_modules/fastify-plugin/test/composite.test.js
generated
vendored
@ -1,16 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.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.equal(fn[Symbol.for('plugin-meta')].name, 'composite.test-auto-0')
|
||||
t.equal(fn[Symbol.for('fastify.display-name')], 'composite.test-auto-0')
|
||||
})
|
@ -1,13 +0,0 @@
|
||||
import t from 'tap'
|
||||
|
||||
import fp from '../../plugin.js'
|
||||
|
||||
t.test('esm base support', async t => {
|
||||
fp((fastify, opts, next) => {
|
||||
next()
|
||||
}, {
|
||||
fastify: '^3.0.0'
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
19
node_modules/fastify-session/node_modules/fastify-plugin/test/esm/index.test.js
generated
vendored
19
node_modules/fastify-session/node_modules/fastify-plugin/test/esm/index.test.js
generated
vendored
@ -1,19 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const semver = require('semver')
|
||||
|
||||
if (semver.lt(process.versions.node, '13.3.0')) {
|
||||
t.skip('Skip because Node version <= 13.3.0')
|
||||
t.end()
|
||||
} else {
|
||||
// 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
|
||||
})
|
||||
})
|
||||
}
|
16
node_modules/fastify-session/node_modules/fastify-plugin/test/mu1tip1e.composite.test.js
generated
vendored
16
node_modules/fastify-session/node_modules/fastify-plugin/test/mu1tip1e.composite.test.js
generated
vendored
@ -1,16 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.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.equal(fn[Symbol.for('plugin-meta')].name, 'mu1tip1e.composite.test-auto-0')
|
||||
t.equal(fn[Symbol.for('fastify.display-name')], 'mu1tip1e.composite.test-auto-0')
|
||||
})
|
48
node_modules/fastify-session/node_modules/fastify-plugin/test/stackParser.test.js
generated
vendored
48
node_modules/fastify-session/node_modules/fastify-plugin/test/stackParser.test.js
generated
vendored
@ -1,48 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const extractPluginName = require('../stackParser')
|
||||
|
||||
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'
|
||||
|
||||
t.plan(3)
|
||||
|
||||
t.equal(extractPluginName(winStack), 'hello.test')
|
||||
t.equal(extractPluginName(nixStack), 'this.is.a.test')
|
||||
t.equal(extractPluginName(anonymousStack), 'anonymous')
|
@ -1,239 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const proxyquire = require('proxyquire')
|
||||
const test = t.test
|
||||
const fp = require('../plugin')
|
||||
const Fastify = require('fastify')
|
||||
|
||||
test('fastify-plugin is a function', t => {
|
||||
t.plan(1)
|
||||
t.type(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.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.pass()
|
||||
} catch (e) {
|
||||
t.equal(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.fail()
|
||||
} catch (e) {
|
||||
t.equal(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.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('should check the fastify version', t => {
|
||||
t.plan(1)
|
||||
|
||||
function plugin (fastify, opts, next) {
|
||||
next()
|
||||
}
|
||||
|
||||
try {
|
||||
fp(plugin, '>=0.10.0')
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('the options object should be an object', t => {
|
||||
t.plan(2)
|
||||
|
||||
try {
|
||||
fp(() => { }, null)
|
||||
t.fail()
|
||||
} catch (e) {
|
||||
t.equal(e.message, 'The options object should be an object')
|
||||
}
|
||||
|
||||
try {
|
||||
fp(() => { }, [])
|
||||
t.fail()
|
||||
} catch (e) {
|
||||
t.equal(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.fail()
|
||||
} catch (e) {
|
||||
t.equal(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.ok(plugin[Symbol.for('skip-override')])
|
||||
t.same(plugin[Symbol.for('plugin-meta')], 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.ok(plugin[Symbol.for('skip-override')])
|
||||
t.same(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.equal(fn[Symbol.for('plugin-meta')].name, 'test-auto-0')
|
||||
t.equal(fn[Symbol.for('fastify.display-name')], 'test-auto-0')
|
||||
|
||||
const fn2 = fp((fastify, opts, next) => {
|
||||
next()
|
||||
})
|
||||
|
||||
t.equal(fn2[Symbol.for('plugin-meta')].name, 'test-auto-1')
|
||||
t.equal(fn2[Symbol.for('fastify.display-name')], 'test-auto-1')
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
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.equal(fn[Symbol.for('plugin-meta')].name, functionName)
|
||||
t.equal(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.equal(fn[Symbol.for('plugin-meta')].fastify, '>=0.10.0')
|
||||
})
|
||||
|
||||
test('should check fastify dependency graph - plugin', t => {
|
||||
t.plan(1)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(fp((fastify, opts, next) => next(), {
|
||||
fastify: '3.x',
|
||||
name: 'plugin1-name'
|
||||
}))
|
||||
|
||||
fastify.register(fp((fastify, opts, next) => next(), {
|
||||
fastify: '3.x',
|
||||
name: 'test',
|
||||
dependencies: ['plugin1-name', 'plugin2-name']
|
||||
}))
|
||||
|
||||
fastify.ready(err => {
|
||||
t.equal(err.message, "The dependency 'plugin2-name' of plugin 'test' is not registered")
|
||||
})
|
||||
})
|
||||
|
||||
test('should check fastify dependency graph - decorate', t => {
|
||||
t.plan(1)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.decorate('plugin1', fp((fastify, opts, next) => next(), {
|
||||
fastify: '3.x',
|
||||
name: 'plugin1-name'
|
||||
}))
|
||||
|
||||
fastify.register(fp((fastify, opts, next) => next(), {
|
||||
fastify: '3.x',
|
||||
name: 'test',
|
||||
decorators: { fastify: ['plugin1', 'plugin2'] }
|
||||
}))
|
||||
|
||||
fastify.ready(err => {
|
||||
t.equal(err.message, "The decorator 'plugin2' required by 'test' is not present in Fastify")
|
||||
})
|
||||
})
|
||||
|
||||
test('should check fastify dependency graph - decorateReply', t => {
|
||||
t.plan(1)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.decorateReply('plugin1', fp((fastify, opts, next) => next(), {
|
||||
fastify: '3.x',
|
||||
name: 'plugin1-name'
|
||||
}))
|
||||
|
||||
fastify.register(fp((fastify, opts, next) => next(), {
|
||||
fastify: '3.x',
|
||||
name: 'test',
|
||||
decorators: { reply: ['plugin1', 'plugin2'] }
|
||||
}))
|
||||
|
||||
fastify.ready(err => {
|
||||
t.equal(err.message, "The decorator 'plugin2' required by 'test' is not present in Reply")
|
||||
})
|
||||
})
|
@ -1,8 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"noEmit": true,
|
||||
"strict": true,
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
{
|
||||
"name": "fastify-session",
|
||||
"version": "5.2.1",
|
||||
"description": "a session plugin for fastify",
|
||||
"main": "lib/fastifySession.js",
|
||||
"scripts": {
|
||||
"unit": "ava test/*.test.js",
|
||||
"tsc-check": "tsc --project ./types/tsconfig.json --noEmit",
|
||||
"test": "npm run lint && npm run unit && npm run tsc-check",
|
||||
"lint": "standard lib/* test/*",
|
||||
"coveralls": "nyc npm test",
|
||||
"coverage": "nyc npm test && nyc report --reporter=html"
|
||||
},
|
||||
"keywords": [
|
||||
"session",
|
||||
"fastify"
|
||||
],
|
||||
"author": "Denis Fäcke",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cookie-signature": "^1.1.0",
|
||||
"fastify-plugin": "^3.0.0",
|
||||
"uid-safe": "^2.1.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.13.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/SerayaEryn/fastify-session.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^14.0.0",
|
||||
"ava": "^3.6.0",
|
||||
"fastify": "^3.0.0",
|
||||
"fastify-cookie": "^4.1.0",
|
||||
"got": "^11.6.0",
|
||||
"nyc": "^15.0.0",
|
||||
"standard": "^16.0.1",
|
||||
"typescript": "^4.0.2"
|
||||
},
|
||||
"types": "types/types.d.ts",
|
||||
"files": [
|
||||
"lib",
|
||||
"types/types.d.ts"
|
||||
]
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
/// <reference types="node" />
|
||||
|
||||
import { FastifyPlugin } from "fastify";
|
||||
|
||||
declare module "fastify" {
|
||||
interface FastifyRequest {
|
||||
/** Allows to access or modify the session data. */
|
||||
session: Session;
|
||||
/** A session store. */
|
||||
sessionStore: FastifySessionPlugin.SessionStore;
|
||||
/** Allows to destroy the session in the store. */
|
||||
destroySession(callback: (err?: Error) => void): void;
|
||||
}
|
||||
|
||||
interface Session extends Record<string, any> {
|
||||
sessionId: string;
|
||||
encryptedSessionId: string;
|
||||
/** Updates the `expires` property of the session. */
|
||||
touch(): void;
|
||||
/** Regenerates the session by generating a new `sessionId`. */
|
||||
regenerate(): void;
|
||||
}
|
||||
}
|
||||
|
||||
declare namespace FastifySessionPlugin {
|
||||
interface SessionStore {
|
||||
set(sessionId: string, session: any, callback: (err?: Error) => void): void;
|
||||
get(
|
||||
sessionId: string,
|
||||
callback: (err?: Error, session?: any) => void
|
||||
): void;
|
||||
destroy(sessionId: string, callback: (err?: Error) => void): void;
|
||||
}
|
||||
|
||||
interface Options {
|
||||
/**
|
||||
* The secret used to sign the cookie.
|
||||
*
|
||||
* Must be an array of strings, or a string with length 32 or greater. If an array, the first secret is used to
|
||||
* sign new cookies, and is the first one to be checked for incoming cookies.
|
||||
* Further secrets in the array are used to check incoming cookies, in the order specified.
|
||||
*
|
||||
* Note that the array may be manipulated by the rest of the application during its life cycle.
|
||||
* This can be done by storing the array in a separate variable that is later manipulated with mutating methods
|
||||
* like unshift(), pop(), splice(), etc.
|
||||
* This can be used to rotate the signing secret at regular intervals.
|
||||
* A secret should remain somewhere in the array as long as there are active sessions with cookies signed by it.
|
||||
* Secrets management is left up to the rest of the application.
|
||||
*/
|
||||
secret: string | string[];
|
||||
/** The name of the session cookie. Defaults to `sessionId`. */
|
||||
cookieName?: string;
|
||||
/** The options object used to generate the `Set-Cookie` header of the session cookie. */
|
||||
cookie?: CookieOptions;
|
||||
/**
|
||||
* A session store.
|
||||
* Compatible to stores from express-session.
|
||||
* Defaults to a simple in memory store.
|
||||
* Note: The default store should not be used in a production environment because it will leak memory.
|
||||
*/
|
||||
store?: FastifySessionPlugin.SessionStore;
|
||||
/**
|
||||
* Save sessions to the store, even when they are new and not modified.
|
||||
* Defaults to true. Setting this to false can be useful to save storage space and to comply with the EU cookie law.
|
||||
*/
|
||||
saveUninitialized?: boolean;
|
||||
}
|
||||
|
||||
interface CookieOptions {
|
||||
/** The `Path` attribute. Defaults to `/` (the root path). */
|
||||
path?: string;
|
||||
/** A `number` in milliseconds that specifies the `Expires` attribute by adding the specified milliseconds to the current date. If both `expires` and `maxAge` are set, then `expires` is used. */
|
||||
maxAge?: number;
|
||||
/** The `boolean` value of the `HttpOnly` attribute. Defaults to true. */
|
||||
httpOnly?: boolean;
|
||||
/** The `boolean` value of the `Secure` attribute. Set this option to false when communicating over an unencrypted (HTTP) connection. Value can be set to `auto`; in this case the `Secure` attribute will be set to false for HTTP request, in case of HTTPS it will be set to true. Defaults to true. */
|
||||
secure?: boolean | string;
|
||||
/** The expiration `date` used for the `Expires` attribute. If both `expires` and `maxAge` are set, then `expires` is used. */
|
||||
expires?: Date | number;
|
||||
/** The `boolean` or `string` of the `SameSite` attribute. */
|
||||
sameSite?: string | boolean;
|
||||
/** The `Domain` attribute. */
|
||||
domain?: string;
|
||||
}
|
||||
}
|
||||
|
||||
declare const FastifySessionPlugin: FastifyPlugin<FastifySessionPlugin.Options>;
|
||||
|
||||
export default FastifySessionPlugin;
|
Loading…
Reference in new issue