Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,19 @@ A session store. Needs the following methods:

Stores written for [express-session](https://github.com/expressjs/session) need an adapter that implements `compareAndSet`.

When the store is backed by Redis, you can make its connection identify this plugin to the server through [`CLIENT SETINFO`](https://redis.io/docs/latest/commands/client-setinfo/), so that it shows up in `CLIENT LIST` as `node-redis(fastify-session_v<version>)` instead of a plain `node-redis`:

```js
const { createClient } = require('redis')
const { RedisStore } = require('connect-redis')

const client = createClient({ clientInfoTag: fastifySession.getDefaultClientInfoTag() })
client.connect().catch(console.error)
const store = new RedisStore({ client })
```

`getDefaultClientInfoTag()` returns `fastify-session_v<version>`; ioredis accepts the same `clientInfoTag` option.

If you are terminating HTTPs at
the reverse proxy, you need to add the `trustProxy` setting to your fastify instance if you want to use secure cookies.

Expand Down
4 changes: 3 additions & 1 deletion benchmark/bench.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ function createServer (sessionPlugin, cookiePlugin, storeType) {

if (storeType === 'redis') {
if (!redisClient) {
redisClient = createClient()
redisClient = createClient({
clientInfoTag: fastifySession.getDefaultClientInfoTag()
})
redisClientConnecting = redisClient.connect()
}
store = new RedisStore({ client: redisClient })
Expand Down
4 changes: 3 additions & 1 deletion examples/redis.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ const { RedisStore } = require('connect-redis')

const fastify = Fastify()

const redisClient = createClient()
const redisClient = createClient({
clientInfoTag: fastifySession.getDefaultClientInfoTag()
})
redisClient.connect().catch(console.error)

class AtomicRedisStore extends RedisStore {
Expand Down
15 changes: 15 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ const Store = require('./lib/store')
const Session = require('./lib/session')
const { getSessionGeneration } = require('./lib/sessionMetadata')

/**
* Get the default clientInfoTag for identifying the framework in Redis CLIENT SETINFO.
* This can be used when creating Redis clients for session stores.
* @returns {string} The client info tag (e.g., "fastify-session_v11.1.1")
*/
function getDefaultClientInfoTag () {
try {
const version = require('./lib/version')
return `fastify-session_v${version}`
} catch {
return 'fastify-session'
}
}

function fastifySession (fastify, options, next) {
const error = checkOptions(options)
if (error) {
Expand Down Expand Up @@ -288,3 +302,4 @@ module.exports.fastifySession = fastifySession

module.exports.Store = Store
module.exports.MemoryStore = Store
module.exports.getDefaultClientInfoTag = getDefaultClientInfoTag
4 changes: 4 additions & 0 deletions lib/version.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
'use strict'

// This file is auto-generated during the release process
module.exports = '11.1.6'
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
"redis": "docker run -p 6379:6379 --rm redis",
"benchmark": "node benchmark/bench.js",
"lint": "eslint",
"lint:fix": "eslint --fix"
"lint:fix": "eslint --fix",
"prepack": "node scripts/generate-version.js",
"version": "node scripts/generate-version.js"
},
"keywords": [
"session",
Expand Down
17 changes: 17 additions & 0 deletions scripts/generate-version.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env node
'use strict'

const { writeFileSync } = require('node:fs')
const { join } = require('node:path')

const pkg = require('../package.json')

const versionFilePath = join(__dirname, '..', 'lib', 'version.js')
const content = `'use strict'

// This file is auto-generated during the release process
module.exports = '${pkg.version}'
`

writeFileSync(versionFilePath, content, 'utf8')
console.log(`Generated lib/version.js with version ${pkg.version}`)
46 changes: 46 additions & 0 deletions test/clientInfoTag.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use strict'

const test = require('node:test')
const fastifySession = require('..')

test('getDefaultClientInfoTag should return version tag', (t) => {
t.plan(1)
const tag = fastifySession.getDefaultClientInfoTag()
t.assert.match(tag, /^fastify-session_v\d+\.\d+\.\d+$/)
})

test('getDefaultClientInfoTag should be accessible from module', (t) => {
t.plan(1)
t.assert.strictEqual(typeof fastifySession.getDefaultClientInfoTag, 'function')
})

test('getDefaultClientInfoTag should fallback to fastify-session when version is unavailable', (t) => {
t.plan(1)

// Mock require to simulate missing version.js
const Module = require('module')
const originalRequire = Module.prototype.require

Module.prototype.require = function (id) {
if (id === './lib/version') {
throw new Error('Cannot find module')
}
return originalRequire.apply(this, arguments)
}

// Clear the require cache
delete require.cache[require.resolve('..')]
delete require.cache[require.resolve('../lib/version')]

const fastifySessionMocked = require('..')
const tag = fastifySessionMocked.getDefaultClientInfoTag()

// Restore original require
Module.prototype.require = originalRequire

// Clear cache again
delete require.cache[require.resolve('..')]
delete require.cache[require.resolve('../lib/version')]

t.assert.strictEqual(tag, 'fastify-session')
})
14 changes: 14 additions & 0 deletions test/version.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
'use strict'

const fs = require('node:fs')
const path = require('node:path')
const { test } = require('node:test')

test('lib/version.js should be the same as package.json', t => {
t.plan(1)

const json = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json')).toString('utf8'))
const version = require('../lib/version')

t.assert.strictEqual(version, json.version)
})
9 changes: 9 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ declare module 'fastify' {
type FastifySession = FastifyPluginCallback<fastifySession.FastifySessionOptions> & {
Store: fastifySession.MemoryStore,
MemoryStore: fastifySession.MemoryStore,
getDefaultClientInfoTag: () => string,
}

type Callback = (err?: any) => void
Expand Down Expand Up @@ -230,6 +231,14 @@ declare namespace fastifySession {

export const Store: MemoryStore

/**
* Get the default clientInfoTag for identifying the framework in Redis CLIENT SETINFO.
* This can be used when creating Redis clients for session stores.
* @link https://redis.io/docs/latest/commands/client-setinfo/
* @returns The client info tag (e.g., "fastify-session_v11.1.1")
*/
export function getDefaultClientInfoTag (): string

export const fastifySession: FastifySession
export { fastifySession as default }
}
Expand Down
1 change: 1 addition & 0 deletions types/index.tst.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ declare module 'fastify' {

expect(plugin.Store).type.toBe<SessionStore>()
expect(plugin.MemoryStore).type.toBe<SessionStore>()
expect(plugin.getDefaultClientInfoTag()).type.toBe<string>()

const secret = 'ABCDEFGHIJKLNMOPQRSTUVWXYZ012345'

Expand Down