From fe477ae5b2d518ea5de05578705288867214aaaa Mon Sep 17 00:00:00 2001 From: Daniel Skogly Date: Fri, 17 Oct 2025 15:30:14 +0200 Subject: [PATCH] feat: add preventTouch option to Session.save method Fixes #870 --- README.md | 19 ++++++++++++++++++- index.js | 24 +++++++++++++++++++----- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b880e6b4..6688e52c 100644 --- a/README.md +++ b/README.md @@ -398,7 +398,7 @@ req.session.reload(function(err) { }) ``` -#### Session.save(callback) +#### Session.save([preventTouch, callback]) Save the session back to the store, replacing the contents on the store with the contents in memory (though a store may do something else--consult the store's @@ -412,12 +412,29 @@ does not need to be called. There are some cases where it is useful to call this method, for example, redirects, long-lived requests or in WebSockets. +If `preventTouch` is `true`, `store.touch` will not be called at the end of the +HTTP response, which can be useful if using this library with something like +[Next.js getServerSideProps](https://github.com/expressjs/session/issues/870) to prevent [gssp-no-mutating-res](https://nextjs.org/docs/messages/gssp-no-mutating-res). + +**Note** `rolling: true` may still cause the above error. + ```js req.session.save(function(err) { // session saved }) ``` +```js +// session saved + store.touch will not be called +req.session.save(true) +``` + +```js +req.session.save(true, function(err) { + // session saved + store.touch will not be called +}) +``` + #### Session.touch() Updates the `.maxAge` property. Typically this is diff --git a/index.js b/index.js index d41b2378..1cf92e0b 100644 --- a/index.js +++ b/index.js @@ -213,6 +213,7 @@ function session(options) { var originalId; var savedHash; var touched = false + var preventTouchForReq = false // expose store req.sessionStore = store; @@ -408,10 +409,23 @@ function session(options) { _reload.call(this, rewrapmethods(this, callback)) } - function save() { - debug('saving %s', this.id); - savedHash = hash(this); - _save.apply(this, arguments); + function save(preventTouchOrCb, cb) { + debug('saving %s', this.id) + savedHash = hash(this) + + var _cb = cb; + + if (typeof preventTouchOrCb === 'function') { + _cb = preventTouchOrCb + preventTouchOrCb = false + } + + if (preventTouchOrCb === true) { + preventTouchForReq = true + debug('touch disabled for this request via save(preventTouch=true)') + } + + _save.call(this, _cb) } Object.defineProperty(sess, 'reload', { @@ -465,7 +479,7 @@ function session(options) { return false; } - return cookieId === req.sessionID && !shouldSave(req); + return !preventTouchForReq && cookieId === req.sessionID && !shouldSave(req); } // determine if cookie should be set on response