├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── examples ├── express2 │ ├── app.js │ ├── package.json │ └── views │ │ ├── index.ejs │ │ └── layout.ejs └── express3 │ ├── app.js │ ├── package.json │ └── views │ └── index.ejs ├── lib ├── flash.js └── index.js ├── package.json └── test ├── flash-test.js └── index-test.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac OS X 2 | .DS_Store 3 | 4 | # Node.js 5 | node_modules 6 | npm-debug.log 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | README.md 2 | Makefile 3 | doc/ 4 | examples/ 5 | test/ 6 | 7 | # Mac OS X 8 | .DS_Store 9 | 10 | # Node.js 11 | .npmignore 12 | node_modules/ 13 | npm-debug.log 14 | 15 | # Git 16 | .git* 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: "node_js" 2 | node_js: 3 | - 0.4 4 | - 0.6 5 | - 0.8 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2012-2013 Jared Hanson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SOURCES = lib/*.js 2 | 3 | # ============================================================================== 4 | # Node Tests 5 | # ============================================================================== 6 | 7 | VOWS = ./node_modules/.bin/vows 8 | TESTS ?= test/*-test.js 9 | 10 | test: 11 | @NODE_ENV=test NODE_PATH=lib $(VOWS) $(TESTS) 12 | 13 | # ============================================================================== 14 | # Static Analysis 15 | # ============================================================================== 16 | 17 | JSHINT = jshint 18 | 19 | hint: lint 20 | lint: 21 | $(JSHINT) $(SOURCES) 22 | 23 | 24 | .PHONY: test hint lint 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # connect-flash 2 | 3 | The flash is a special area of the session used for storing messages. Messages 4 | are written to the flash and cleared after being displayed to the user. The 5 | flash is typically used in combination with redirects, ensuring that the message 6 | is available to the next page that is to be rendered. 7 | 8 | This middleware was extracted from [Express](http://expressjs.com/) 2.x, after 9 | Express 3.x removed direct support for the flash. connect-flash brings this 10 | functionality back to Express 3.x, as well as any other middleware-compatible 11 | framework or application. +1 for [radical reusability](http://substack.net/posts/b96642/the-node-js-aesthetic). 12 | 13 | --- 14 | 15 |

16 | Advertisement 17 |
18 | The Complete 2020 Web Development Bootcamp
Become a full-stack web developer with just one course. HTML, CSS, Javascript, Node, React, MongoDB and more! 19 |

20 | 21 | --- 22 | 23 | ## Install 24 | 25 | $ npm install connect-flash 26 | 27 | ## Usage 28 | 29 | #### Express 3.x 30 | 31 | Flash messages are stored in the session. First, setup sessions as usual by 32 | enabling `cookieParser` and `session` middleware. Then, use `flash` middleware 33 | provided by connect-flash. 34 | 35 | ```javascript 36 | var flash = require('connect-flash'); 37 | var app = express(); 38 | 39 | app.configure(function() { 40 | app.use(express.cookieParser('keyboard cat')); 41 | app.use(express.session({ cookie: { maxAge: 60000 }})); 42 | app.use(flash()); 43 | }); 44 | ``` 45 | 46 | With the `flash` middleware in place, all requests will have a `req.flash()` function 47 | that can be used for flash messages. 48 | 49 | ```javascript 50 | app.get('/flash', function(req, res){ 51 | // Set a flash message by passing the key, followed by the value, to req.flash(). 52 | req.flash('info', 'Flash is back!') 53 | res.redirect('/'); 54 | }); 55 | 56 | app.get('/', function(req, res){ 57 | // Get an array of flash messages by passing the key to req.flash() 58 | res.render('index', { messages: req.flash('info') }); 59 | }); 60 | ``` 61 | 62 | ## Examples 63 | 64 | For an example using connect-flash in an Express 3.x app, refer to the [express3](https://github.com/jaredhanson/connect-flash/tree/master/examples/express3) 65 | example. 66 | 67 | ## Tests 68 | 69 | $ npm install --dev 70 | $ make test 71 | 72 | [![Build Status](https://secure.travis-ci.org/jaredhanson/connect-flash.png)](http://travis-ci.org/jaredhanson/connect-flash) 73 | 74 | ## Credits 75 | 76 | - [Jared Hanson](http://github.com/jaredhanson) 77 | - [TJ Holowaychuk](https://github.com/visionmedia) 78 | 79 | ## License 80 | 81 | [The MIT License](http://opensource.org/licenses/MIT) 82 | 83 | Copyright (c) 2012-2013 Jared Hanson <[http://jaredhanson.net/](http://jaredhanson.net/)> 84 | -------------------------------------------------------------------------------- /examples/express2/app.js: -------------------------------------------------------------------------------- 1 | var express = require('express') 2 | , flash = require('../..') 3 | , util = require('util'); 4 | 5 | 6 | var app = express.createServer(); 7 | 8 | // configure Express 9 | app.configure(function() { 10 | app.set('views', __dirname + '/views'); 11 | app.set('view engine', 'ejs'); 12 | app.use(express.logger()); 13 | app.use(express.cookieParser()); 14 | app.use(express.session({ secret: 'keyboard cat' })); 15 | 16 | // Setting `unsafe` to `true` causes connect-flash's implementation to 17 | // override Express 2.x's implementation. Functionally these are equivalent, 18 | // so there is no reason to use connect-flash with Express 2.x. This example 19 | // is for illustrative purposes only. 20 | 21 | app.use(flash({ unsafe: true })); 22 | app.use(app.router); 23 | }); 24 | 25 | 26 | app.get('/', function(req, res){ 27 | res.render('index', { message: req.flash('info') }); 28 | }); 29 | 30 | app.get('/flash', function(req, res){ 31 | req.flash('info', 'Hi there!') 32 | res.redirect('/'); 33 | }); 34 | 35 | app.get('/multiple-flash', function(req, res){ 36 | req.flash('info', ['Welcome', 'Please Enjoy']); 37 | res.redirect('/'); 38 | }); 39 | 40 | app.get('/no-flash', function(req, res){ 41 | res.redirect('/'); 42 | }); 43 | 44 | app.listen(3000); 45 | -------------------------------------------------------------------------------- /examples/express2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "connect-flash-examples-express2", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "express": "2.x.x", 6 | "ejs": "0.6.x" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /examples/express2/views/index.ejs: -------------------------------------------------------------------------------- 1 |

2 | Flash | 3 | No Flash 4 |

5 | 6 | <% if (message) { %> 7 |

<%= message %>

8 | <% } %> 9 | -------------------------------------------------------------------------------- /examples/express2/views/layout.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Express 2.x Example for connect-flash 5 | 6 | 7 | <%- body %> 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/express3/app.js: -------------------------------------------------------------------------------- 1 | var express = require('express') 2 | , flash = require('../..') 3 | , util = require('util'); 4 | 5 | 6 | var app = express(); 7 | 8 | // configure Express 9 | app.configure(function() { 10 | app.set('views', __dirname + '/views'); 11 | app.set('view engine', 'ejs'); 12 | app.use(express.logger()); 13 | app.use(express.cookieParser('keyboard cat')); 14 | app.use(express.session({ key: 'sid', cookie: { maxAge: 60000 }})); 15 | 16 | // Use connect-flash middleware. This will add a `req.flash()` function to 17 | // all requests, matching the functionality offered in Express 2.x. 18 | 19 | app.use(flash()); 20 | app.use(app.router); 21 | }); 22 | 23 | 24 | app.get('/', function(req, res){ 25 | res.render('index', { message: req.flash('info') }); 26 | }); 27 | 28 | app.get('/flash', function(req, res){ 29 | req.flash('info', 'Hi there!') 30 | res.redirect('/'); 31 | }); 32 | 33 | app.get('/no-flash', function(req, res){ 34 | res.redirect('/'); 35 | }); 36 | 37 | app.get('/multiple-flash', function(req, res){ 38 | req.flash('info', ['Welcome', 'Please Enjoy']); 39 | res.redirect('/'); 40 | }); 41 | 42 | app.listen(3000); 43 | -------------------------------------------------------------------------------- /examples/express3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "connect-flash-examples-express3", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "express": "3.x.x", 6 | "ejs": "0.6.x" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /examples/express3/views/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Express 3.x Example for connect-flash 5 | 6 | 7 | 8 |

9 | Flash | 10 | No Flash 11 |

12 | 13 | <% if (message) { %> 14 |

<%= message %>

15 | <% } %> 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /lib/flash.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module dependencies. 3 | */ 4 | var format = require('util').format; 5 | var isArray = require('util').isArray; 6 | 7 | 8 | /** 9 | * Expose `flash()` function on requests. 10 | * 11 | * @return {Function} 12 | * @api public 13 | */ 14 | module.exports = function flash(options) { 15 | options = options || {}; 16 | var safe = (options.unsafe === undefined) ? true : !options.unsafe; 17 | 18 | return function(req, res, next) { 19 | if (req.flash && safe) { return next(); } 20 | req.flash = _flash; 21 | next(); 22 | } 23 | } 24 | 25 | /** 26 | * Queue flash `msg` of the given `type`. 27 | * 28 | * Examples: 29 | * 30 | * req.flash('info', 'email sent'); 31 | * req.flash('error', 'email delivery failed'); 32 | * req.flash('info', 'email re-sent'); 33 | * // => 2 34 | * 35 | * req.flash('info'); 36 | * // => ['email sent', 'email re-sent'] 37 | * 38 | * req.flash('info'); 39 | * // => [] 40 | * 41 | * req.flash(); 42 | * // => { error: ['email delivery failed'], info: [] } 43 | * 44 | * Formatting: 45 | * 46 | * Flash notifications also support arbitrary formatting support. 47 | * For example you may pass variable arguments to `req.flash()` 48 | * and use the %s specifier to be replaced by the associated argument: 49 | * 50 | * req.flash('info', 'email has been sent to %s.', userName); 51 | * 52 | * Formatting uses `util.format()`, which is available on Node 0.6+. 53 | * 54 | * @param {String} type 55 | * @param {String} msg 56 | * @return {Array|Object|Number} 57 | * @api public 58 | */ 59 | function _flash(type, msg) { 60 | if (this.session === undefined) throw Error('req.flash() requires sessions'); 61 | var msgs = this.session.flash = this.session.flash || {}; 62 | if (type && msg) { 63 | // util.format is available in Node.js 0.6+ 64 | if (arguments.length > 2 && format) { 65 | var args = Array.prototype.slice.call(arguments, 1); 66 | msg = format.apply(undefined, args); 67 | } else if (isArray(msg)) { 68 | msg.forEach(function(val){ 69 | (msgs[type] = msgs[type] || []).push(val); 70 | }); 71 | return msgs[type].length; 72 | } 73 | return (msgs[type] = msgs[type] || []).push(msg); 74 | } else if (type) { 75 | var arr = msgs[type]; 76 | delete msgs[type]; 77 | return arr || []; 78 | } else { 79 | this.session.flash = {}; 80 | return msgs; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Expose middleware. 3 | */ 4 | exports = module.exports = require('./flash'); 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "connect-flash", 3 | "version": "0.1.1", 4 | "description": "Flash message middleware for Connect.", 5 | "keywords": ["connect", "express", "flash", "messages"], 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/jaredhanson/connect-flash.git" 9 | }, 10 | "bugs": { 11 | "url": "http://github.com/jaredhanson/connect-flash/issues" 12 | }, 13 | "author": { 14 | "name": "Jared Hanson", 15 | "email": "jaredhanson@gmail.com", 16 | "url": "http://www.jaredhanson.net/" 17 | }, 18 | "licenses": [ { 19 | "type": "MIT", 20 | "url": "http://www.opensource.org/licenses/MIT" 21 | } ], 22 | "main": "./lib", 23 | "dependencies": { 24 | }, 25 | "devDependencies": { 26 | "vows": "0.6.x" 27 | }, 28 | "scripts": { 29 | "test": "NODE_PATH=lib node_modules/.bin/vows test/*-test.js" 30 | }, 31 | "engines": { "node": ">= 0.4.0" } 32 | } 33 | -------------------------------------------------------------------------------- /test/flash-test.js: -------------------------------------------------------------------------------- 1 | var vows = require('vows'); 2 | var assert = require('assert'); 3 | var util = require('util'); 4 | var flash = require('flash'); 5 | 6 | 7 | function MockRequest() { 8 | this.session = {}; 9 | } 10 | 11 | function MockRequestWithoutSession() { 12 | } 13 | 14 | function MockResponse() { 15 | } 16 | 17 | 18 | vows.describe('flash').addBatch({ 19 | 20 | 'middleware': { 21 | topic: function() { 22 | return flash(); 23 | }, 24 | 25 | 'when handling a request': { 26 | topic: function(flash) { 27 | var self = this; 28 | var req = new MockRequest(); 29 | var res = new MockResponse(); 30 | 31 | function next(err) { 32 | self.callback(err, req, res); 33 | } 34 | process.nextTick(function () { 35 | flash(req, res, next) 36 | }); 37 | }, 38 | 39 | 'should not error' : function(err, req, res) { 40 | assert.isNull(err); 41 | }, 42 | 'should add a flash function' : function(err, req, res) { 43 | assert.isFunction(req.flash); 44 | }, 45 | 'should set flash message' : function(err, req, res) { 46 | var count = req.flash('error', 'Something went wrong'); 47 | assert.equal(count, 1); 48 | assert.lengthOf(Object.keys(req.session.flash), 1); 49 | assert.lengthOf(req.session.flash['error'], 1); 50 | }, 51 | 'should get and clear previously set flash message' : function(err, req, res) { 52 | var msgs = req.flash('error'); 53 | assert.lengthOf(msgs, 1); 54 | assert.equal(msgs[0], 'Something went wrong'); 55 | assert.lengthOf(Object.keys(req.session.flash), 0); 56 | }, 57 | 'should set multiple flash messages' : function(err, req, res) { 58 | req.flash('info', 'Welcome'); 59 | var count = req.flash('info', 'Check out this great new feature'); 60 | assert.equal(count, 2); 61 | assert.lengthOf(Object.keys(req.session.flash), 1); 62 | assert.lengthOf(req.session.flash['info'], 2); 63 | }, 64 | 'should set flash messages in one call' : function(err, req, res) { 65 | var count = req.flash('warning', ['username required', 'password required']); 66 | assert.equal(count, 2); 67 | var msgs = req.flash('warning'); 68 | assert.lengthOf(msgs, 2); 69 | assert.equal(msgs[0], 'username required'); 70 | assert.equal(msgs[1], 'password required'); 71 | }, 72 | 'should get and clear multiple previously set flash messages' : function(err, req, res) { 73 | var msgs = req.flash('info'); 74 | assert.lengthOf(msgs, 2); 75 | assert.equal(msgs[0], 'Welcome'); 76 | assert.equal(msgs[1], 'Check out this great new feature'); 77 | assert.lengthOf(Object.keys(req.session.flash), 0); 78 | }, 79 | 'should set flash messages of multiple types' : function(err, req, res) { 80 | req.flash('info', 'Welcome back'); 81 | req.flash('notice', 'Last login was yesterday'); 82 | assert.lengthOf(Object.keys(req.session.flash), 2); 83 | assert.lengthOf(req.session.flash['info'], 1); 84 | assert.lengthOf(req.session.flash['notice'], 1); 85 | }, 86 | 'should independently get and clear messages of multiple types' : function(err, req, res) { 87 | var msgs = req.flash('info'); 88 | assert.lengthOf(msgs, 1); 89 | assert.equal(msgs[0], 'Welcome back'); 90 | assert.lengthOf(Object.keys(req.session.flash), 1); 91 | msgs = req.flash('notice'); 92 | assert.lengthOf(msgs, 1); 93 | assert.equal(msgs[0], 'Last login was yesterday'); 94 | }, 95 | 'should return all messages' : function(err, req, res) { 96 | req.flash('error', 'Database is down'); 97 | req.flash('error', 'Message queue is down'); 98 | req.flash('notice', 'Things are looking bleak'); 99 | var msgs = req.flash(); 100 | assert.lengthOf(Object.keys(msgs), 2); 101 | assert.lengthOf(msgs['error'], 2); 102 | assert.lengthOf(msgs['notice'], 1); 103 | assert.lengthOf(Object.keys(req.session.flash), 0); 104 | }, 105 | 'should format messages' : function(err, req, res) { 106 | if (util.format) { 107 | req.flash('info', 'Hello %s', 'Jared'); 108 | var msg = req.flash('info')[0]; 109 | assert.equal(msg, 'Hello Jared') 110 | 111 | req.flash('info', 'Hello %s %s', 'Jared', 'Hanson'); 112 | var msg = req.flash('info')[0]; 113 | assert.equal(msg, 'Hello Jared Hanson') 114 | } 115 | }, 116 | 'should return empty array for flash type with no messages' : function(err, req, res) { 117 | var msgs = req.flash('what'); 118 | assert.lengthOf(msgs, 0); 119 | }, 120 | }, 121 | 122 | 'when handling a request with an existing flash function': { 123 | topic: function(flash) { 124 | var self = this; 125 | var req = new MockRequest(); 126 | req.flash = function(type, msg) { 127 | this.session.flash = 'I Exist' 128 | } 129 | var res = new MockResponse(); 130 | 131 | function next(err) { 132 | self.callback(err, req, res); 133 | } 134 | process.nextTick(function () { 135 | flash(req, res, next) 136 | }); 137 | }, 138 | 139 | 'should not error' : function(err, req, res) { 140 | assert.isNull(err); 141 | }, 142 | 'should not overwrite flash function' : function(err, req, res) { 143 | req.flash('question', 'Do you?') 144 | assert.equal(req.session.flash, 'I Exist'); 145 | }, 146 | }, 147 | 148 | 'when handling a request without a session': { 149 | topic: function(flash) { 150 | var self = this; 151 | var req = new MockRequestWithoutSession(); 152 | var res = new MockResponse(); 153 | 154 | function next(err) { 155 | self.callback(err, req, res); 156 | } 157 | process.nextTick(function () { 158 | flash(req, res, next) 159 | }); 160 | }, 161 | 162 | 'should not error' : function(err, req, res) { 163 | assert.isNull(err); 164 | }, 165 | 'should add a flash function' : function(err, req, res) { 166 | assert.isFunction(req.flash); 167 | }, 168 | 'should throw when attempting to set a flash message' : function(err, req, res) { 169 | assert.throws(function() { 170 | req.flash('error', 'Something went wrong'); 171 | }); 172 | }, 173 | }, 174 | }, 175 | 176 | 'middleware with an unsafe option': { 177 | topic: function() { 178 | return flash({ unsafe: true }); 179 | }, 180 | 181 | 'when handling a request with an existing flash function': { 182 | topic: function(flash) { 183 | var self = this; 184 | var req = new MockRequest(); 185 | req.flash = function(type, msg) { 186 | this.session.flash = 'I Exist' 187 | } 188 | var res = new MockResponse(); 189 | 190 | function next(err) { 191 | self.callback(err, req, res); 192 | } 193 | process.nextTick(function () { 194 | flash(req, res, next) 195 | }); 196 | }, 197 | 198 | 'should not error' : function(err, req, res) { 199 | assert.isNull(err); 200 | }, 201 | 'should overwrite flash function' : function(err, req, res) { 202 | req.flash('info', 'It works!'); 203 | assert.lengthOf(Object.keys(req.session.flash), 1); 204 | assert.lengthOf(req.session.flash['info'], 1); 205 | }, 206 | }, 207 | }, 208 | 209 | }).export(module); 210 | -------------------------------------------------------------------------------- /test/index-test.js: -------------------------------------------------------------------------------- 1 | var vows = require('vows'); 2 | var assert = require('assert'); 3 | var flash = require('index'); 4 | 5 | 6 | vows.describe('connect-flash').addBatch({ 7 | 8 | 'module': { 9 | 'should export middleware': function () { 10 | assert.isFunction(flash); 11 | }, 12 | }, 13 | 14 | }).export(module); 15 | --------------------------------------------------------------------------------