diff --git a/README.md b/README.md index bdbcadd..5abd33e 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ 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() @@ -112,7 +112,7 @@ 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 => { @@ -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) diff --git a/lib/session.js b/lib/session.js index b309eb8..62c0e77 100644 --- a/lib/session.js +++ b/lib/session.js @@ -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) { @@ -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] () { diff --git a/test/session.test.js b/test/session.test.js index 1632281..8c57200 100644 --- a/test/session.test.js +++ b/test/session.test.js @@ -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) +}) diff --git a/types/types.d.ts b/types/types.d.ts index ae9b068..daf0d45 100644 --- a/types/types.d.ts +++ b/types/types.d.ts @@ -27,15 +27,19 @@ interface SessionData extends ExpressSessionData { * Regenerates the session by generating a new `sessionId`. */ regenerate(callback: (err?: Error) => void): void; + regenerate(): Promise; /** Allows to destroy the session in the store. */ destroy(callback: (err?: Error) => void): void; + destroy(): Promise; /** Reloads the session data from the store and re-populates the request.session object. */ reload(callback: (err?: Error) => void): void; + reload(): Promise; /** 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; /** sets values in the session. */ set(key: string, value: unknown): void; diff --git a/types/types.test-d.ts b/types/types.test-d.ts index b4ce8dc..c130a86 100644 --- a/types/types.test-d.ts +++ b/types/types.test-d.ts @@ -61,6 +61,7 @@ app.route({ url: '/', preHandler(req, _rep, next) { expectType(req.session.destroy(next)); + expectType>(req.session.destroy()); }, async handler(request, reply) { expectType(request); @@ -82,5 +83,9 @@ app.route({ expectType(request.session.destroy(() => {})); expectType(request.session.regenerate(() => {})); expectType(request.session.save(() => {})); + expectType>(request.session.reload()); + expectType>(request.session.destroy()); + expectType>(request.session.regenerate()); + expectType>(request.session.save()); } });