Skip to content
Merged
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
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,15 @@ Allows to access or modify the session data.

#### Session#destroy(callback)

Allows to destroy the session in the store
Allows to destroy the session in the store. If you do not pass a callback, a Promise will be returned.

#### Session#touch()

Updates the `expires` property of the session.

#### Session#regenerate(callback)

Regenerates the session by generating a new `sessionId` and persist it to the store.
Regenerates the session by generating a new `sessionId` and persist it to the store. If you do not pass a callback, a Promise will be returned.
```js
fastify.get('/regenerate', (request, reply, done) => {
request.session.regenerate(error => {
Expand All @@ -127,11 +127,11 @@ fastify.get('/regenerate', (request, reply, done) => {

#### Session#reload(callback)

Reloads the session data from the store and re-populates the `request.session` object.
Reloads the session data from the store and re-populates the `request.session` object. If you do not pass a callback, a Promise will be returned.

#### Session#save(callback)

Save the session back to the store, replacing the contents on the store with the contents in memory.
Save the session back to the store, replacing the contents on the store with the contents in memory. If you do not pass a callback, a Promise will be returned.

#### Session#get(key)

Expand Down
96 changes: 76 additions & 20 deletions lib/session.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,29 @@ module.exports = class Session {
}

regenerate (callback) {
const session = new Session(this[requestKey], this[generateId], this[cookieOptsKey], this[secretKey])

this[requestKey].sessionStore.set(session.sessionId, session, error => {
this[requestKey].session = session

callback(error)
})
if (callback) {
const session = new Session(this[requestKey], this[generateId], this[cookieOptsKey], this[secretKey])

this[requestKey].sessionStore.set(session.sessionId, session, error => {
this[requestKey].session = session

callback(error)
})
} else {
return new Promise((resolve, reject) => {
const session = new Session(this[requestKey], this[generateId], this[cookieOptsKey], this[secretKey])

this[requestKey].sessionStore.set(session.sessionId, session, error => {
this[requestKey].session = session

if (error) {
reject(error)
} else {
resolve()
}
})
})
}
}

[addDataToSession] (prevSession) {
Expand All @@ -62,25 +78,65 @@ module.exports = class Session {
}

destroy (callback) {
this[requestKey].sessionStore.destroy(this.sessionId, error => {
this[requestKey].session = null

callback(error)
})
if (callback) {
this[requestKey].sessionStore.destroy(this.sessionId, error => {
this[requestKey].session = null

callback(error)
})
} else {
return new Promise((resolve, reject) => {
this[requestKey].sessionStore.destroy(this.sessionId, error => {
this[requestKey].session = null

if (error) {
reject(error)
} else {
resolve()
}
})
})
}
}

reload (callback) {
this[requestKey].sessionStore.get(this.sessionId, (error, session) => {
this[requestKey].session = new Session(this[requestKey], this[generateId], this[cookieOptsKey], this[secretKey], session)

callback(error)
})
if (callback) {
this[requestKey].sessionStore.get(this.sessionId, (error, session) => {
this[requestKey].session = new Session(this[requestKey], this[generateId], this[cookieOptsKey], this[secretKey], session)

callback(error)
})
} else {
return new Promise((resolve, reject) => {
this[requestKey].sessionStore.get(this.sessionId, (error, session) => {
this[requestKey].session = new Session(this[requestKey], this[generateId], this[cookieOptsKey], this[secretKey], session)

if (error) {
reject(error)
} else {
resolve()
}
})
})
}
}

save (callback) {
this[requestKey].sessionStore.set(this.sessionId, this, error => {
callback(error)
})
if (callback) {
this[requestKey].sessionStore.set(this.sessionId, this, error => {
callback(error)
})
} else {
return new Promise((resolve, reject) => {
this[requestKey].sessionStore.set(this.sessionId, this, error => {
if (error) {
reject(error)
} else {
resolve()
}
})
})
}
}

[sign] () {
Expand Down
136 changes: 136 additions & 0 deletions test/session.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -540,3 +540,139 @@ test('should save the session', async (t) => {

t.is(response.statusCode, 200)
})

test('destroy supports promises', async t => {
t.plan(2)
const port = await testServer(async (request, reply) => {
await t.notThrowsAsync(request.session.destroy())

reply.send(200)
}, DEFAULT_OPTIONS)

const { response } = await request(`http://localhost:${port}`)

t.is(response.statusCode, 200)
})

test('destroy supports rejecting promises', async t => {
t.plan(2)
const port = await testServer(async (request, reply) => {
await t.throwsAsync(request.session.destroy(), { message: 'no can do' })

reply.send(200)
}, {
...DEFAULT_OPTIONS,
store: {
set (id, data, cb) { cb(null) },
get (id, cb) { cb(null) },
destroy (id, cb) { cb(new Error('no can do')) }
}
})

const { response } = await request(`http://localhost:${port}`)

// 200 since we assert inline and swallow the error
t.is(response.statusCode, 200)
})

test('regenerate supports promises', async t => {
t.plan(2)
const port = await testServer(async (request, reply) => {
await t.notThrowsAsync(request.session.regenerate())

reply.send(200)
}, DEFAULT_OPTIONS)

const { response } = await request(`http://localhost:${port}`)

t.is(response.statusCode, 200)
})

test('regenerate supports rejecting promises', async t => {
t.plan(2)
const port = await testServer(async (request, reply) => {
await t.throwsAsync(request.session.regenerate(), { message: 'no can do' })

reply.send(200)
}, {
...DEFAULT_OPTIONS,
store: {
set (id, data, cb) { cb(new Error('no can do')) },
get (id, cb) { cb(null) },
destroy (id, cb) { cb(null) }
}
})

const { response } = await request(`http://localhost:${port}`)

// 200 since we assert inline and swallow the error
t.is(response.statusCode, 200)
})

test('reload supports promises', async t => {
t.plan(2)
const port = await testServer(async (request, reply) => {
await t.notThrowsAsync(request.session.reload())

reply.send(200)
}, DEFAULT_OPTIONS)

const { response } = await request(`http://localhost:${port}`)

t.is(response.statusCode, 200)
})

test('reload supports rejecting promises', async t => {
t.plan(2)
const port = await testServer(async (request, reply) => {
await t.throwsAsync(request.session.reload(), { message: 'no can do' })

reply.send(200)
}, {
...DEFAULT_OPTIONS,
store: {
set (id, data, cb) { cb(null) },
get (id, cb) { cb(new Error('no can do')) },
destroy (id, cb) { cb(null) }
}
})

const { response } = await request(`http://localhost:${port}`)

// 200 since we assert inline and swallow the error
t.is(response.statusCode, 200)
})

test('save supports promises', async t => {
t.plan(2)
const port = await testServer(async (request, reply) => {
await t.notThrowsAsync(request.session.save())

reply.send(200)
}, DEFAULT_OPTIONS)

const { response } = await request(`http://localhost:${port}`)

t.is(response.statusCode, 200)
})

test('save supports rejecting promises', async t => {
t.plan(2)
const port = await testServer(async (request, reply) => {
await t.throwsAsync(request.session.save())

reply.send(200)
}, {
...DEFAULT_OPTIONS,
store: {
set (id, data, cb) { cb(new Error('no can do')) },
get (id, cb) { cb(null) },
save (id, cb) { cb(null) }
}
})

const { response } = await request(`http://localhost:${port}`)

// 200 since we assert inline and swallow the error
t.is(response.statusCode, 200)
})
4 changes: 4 additions & 0 deletions types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,19 @@ interface SessionData extends ExpressSessionData {
* Regenerates the session by generating a new `sessionId`.
*/
regenerate(callback: (err?: Error) => void): void;
regenerate(): Promise<void>;

/** Allows to destroy the session in the store. */
destroy(callback: (err?: Error) => void): void;
destroy(): Promise<void>;

/** Reloads the session data from the store and re-populates the request.session object. */
reload(callback: (err?: Error) => void): void;
reload(): Promise<void>;

/** Save the session back to the store, replacing the contents on the store with the contents in memory. */
save(callback: (err?: Error) => void): void;
save(): Promise<void>;

/** sets values in the session. */
set(key: string, value: unknown): void;
Expand Down
5 changes: 5 additions & 0 deletions types/types.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ app.route({
url: '/',
preHandler(req, _rep, next) {
expectType<void>(req.session.destroy(next));
expectType<Promise<void>>(req.session.destroy());
},
async handler(request, reply) {
expectType<FastifyRequest>(request);
Expand All @@ -82,5 +83,9 @@ app.route({
expectType<void>(request.session.destroy(() => {}));
expectType<void>(request.session.regenerate(() => {}));
expectType<void>(request.session.save(() => {}));
expectType<Promise<void>>(request.session.reload());
expectType<Promise<void>>(request.session.destroy());
expectType<Promise<void>>(request.session.regenerate());
expectType<Promise<void>>(request.session.save());
}
});