├── .gitignore ├── .travis.yml ├── Makefile ├── example.js ├── package.json ├── index.js ├── LICENSE ├── README.md └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.11" 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | NODE_ENV=test ./node_modules/.bin/mocha \ 3 | --harmony \ 4 | --reporter spec 5 | 6 | .PHONY: test 7 | -------------------------------------------------------------------------------- /example.js: -------------------------------------------------------------------------------- 1 | var koa = require('koa') 2 | , session = require('koa-session') 3 | , flash = require('koa-flash'); 4 | 5 | var app = koa(); 6 | 7 | app.keys = ['foo']; 8 | app.use(session()); 9 | app.use(flash()); 10 | 11 | app.use(function *() { 12 | if (this.method === 'POST') { 13 | this.flash = { error: 'This is a flash error message.' }; 14 | } else if (this.method === 'GET') { 15 | this.body = this.flash.error || 'No flash data.'; 16 | } 17 | }); 18 | 19 | app.listen(3000); 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "koa-flash", 3 | "version": "1.0.0", 4 | "description": "Flash messages for your koa application.", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/rickharrison/koa-flash" 9 | }, 10 | "keywords": [ 11 | "koa", 12 | "middleware", 13 | "flash", 14 | "messages", 15 | "session" 16 | ], 17 | "author": "Rick Harrison", 18 | "license": "MIT", 19 | "bugs": { 20 | "url": "https://github.com/rickharrison/koa-flash/issues" 21 | }, 22 | "homepage": "https://github.com/rickharrison/koa-flash", 23 | "devDependencies": { 24 | "koa": "~0.5.1", 25 | "koa-session": "~2.0.0", 26 | "mocha": "~1.18.2", 27 | "supertest": "~0.9.2" 28 | }, 29 | "scripts": { 30 | "test": "make test" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Initialize flash middleware with `opts` 3 | * 4 | * - `key` session property name (default: koa-flash) 5 | * - `defaultValue` default value for this.flash (default: {}) 6 | * 7 | * @param {Object} opts 8 | * @return {GeneratorFunction} 9 | * @api public 10 | */ 11 | 12 | module.exports = function (opts) { 13 | var opts = opts || {}; 14 | var key = opts.key || 'koa-flash'; 15 | var defaultValue = opts.defaultValue || {}; 16 | 17 | return function *flash(next) { 18 | if (this.session === undefined) throw new Error('koa-flash requires the koa-session middleware.'); 19 | 20 | var data = this.session[key] || defaultValue; 21 | 22 | delete this.session[key]; 23 | 24 | Object.defineProperty(this, 'flash', { 25 | enumerable: true, 26 | get: function() { 27 | return data; 28 | }, 29 | set: function(val) { 30 | this.session[key] = val; 31 | } 32 | }); 33 | 34 | yield *next; 35 | 36 | if (this.status == 302 && this.session && !(this.session[key])) { 37 | this.session[key] = data; 38 | } 39 | }; 40 | }; 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Rick Harrison 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, 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, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #koa-flash 2 | 3 | Flash messages for your [koa](https://github.com/koajs/koa) application. 4 | 5 | [![Build Status](https://travis-ci.org/rickharrison/koa-flash.svg?branch=master)](https://travis-ci.org/rickharrison/koa-flash) 6 | 7 | ## Installation 8 | 9 | ```js 10 | $ npm install koa-flash 11 | ``` 12 | 13 | koa-flash also depends on [koa-session](https://github.com/koajs/session). You must add koa-session as a middleware prior to adding koa-flash as seen in the example: 14 | 15 | ## Example 16 | 17 | ```js 18 | var koa = require('koa') 19 | , session = require('koa-session') 20 | , flash = require('koa-flash'); 21 | 22 | var app = koa(); 23 | 24 | app.keys = ['foo']; 25 | app.use(session()); 26 | app.use(flash()); 27 | 28 | app.use(function *() { 29 | if (this.method === 'POST') { 30 | this.flash = { error: 'This is a flash error message.' }; 31 | } else if (this.method === 'GET') { 32 | this.body = this.flash.error || 'No flash data.'; 33 | } 34 | }); 35 | 36 | app.listen(3000); 37 | ``` 38 | 39 | ## Semantics 40 | 41 | Flash data when set will be saved to the user's session for exactly one more request. You can save any javascript object into `this.flash` (Object, Number, String, etc.). A common use case is to save an error message from a `POST` request when redirecting to a `GET` request to display the form again. 42 | 43 | ## Options 44 | 45 | Flash data is saved into `this.session['koa-flash']` by default. You can change this by passing in a `key` option. 46 | 47 | ```js 48 | app.use(flash({ key: 'foo' })); 49 | ``` 50 | 51 | Also, you can set `defaultValue` instead of `{}`. 52 | 53 | ```js 54 | app.use(flash({ defaultValue: 'bar' })); 55 | ``` 56 | 57 | ## License 58 | 59 | MIT 60 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var koa = require('koa') 2 | , session = require('koa-session') 3 | , flash = require('./') 4 | , request = require('supertest'); 5 | 6 | function App(opts) { 7 | var app = koa(); 8 | 9 | app.keys = ['foo']; 10 | app.use(session()); 11 | app.use(flash(opts)); 12 | 13 | return app; 14 | } 15 | 16 | describe('koa flash', function () { 17 | it('should add a flash property', function (done) { 18 | var app = App(); 19 | 20 | app.use(function *() { 21 | this.body = this.flash; 22 | }); 23 | 24 | request(app.listen()) 25 | .get('/') 26 | .expect({}) 27 | .expect(200, done); 28 | }); 29 | 30 | it('should require koa-session', function (done) { 31 | var app = koa(); 32 | app.use(flash()); 33 | 34 | request(app.listen()) 35 | .get('/') 36 | .expect(500, done); 37 | }); 38 | 39 | it('should set flash into session', function (done) { 40 | var app = App(); 41 | 42 | app.use(function *() { 43 | this.flash = 'foo'; 44 | 45 | this.body = this.session['koa-flash']; 46 | }); 47 | 48 | request(app.listen()) 49 | .get('/') 50 | .expect('foo') 51 | .expect(200, done); 52 | }); 53 | 54 | it('should set flash into opts.key', function (done) { 55 | var app = App({ key: 'foo' }); 56 | 57 | app.use(function *() { 58 | this.flash = 'bar'; 59 | 60 | this.body = this.session.foo; 61 | }); 62 | 63 | request(app.listen()) 64 | .get('/') 65 | .expect('bar') 66 | .expect(200, done); 67 | }); 68 | 69 | it('defaultValue for flash', function (done) { 70 | var app = App({ defaultValue: 'bar' }); 71 | 72 | app.use(function *() { 73 | this.body = this.flash; 74 | }); 75 | 76 | request(app.listen()) 77 | .get('/') 78 | .expect('bar') 79 | .expect(200, done); 80 | }); 81 | 82 | describe('when flash is set', function () { 83 | var agent; 84 | 85 | beforeEach(function (done) { 86 | var app = App(); 87 | 88 | app.use(function *() { 89 | if (this.path == '/redirect') { 90 | return this.redirect('back'); 91 | } 92 | 93 | this.body = this.flash; 94 | 95 | if (this.method === 'POST') { 96 | this.flash = { foo: 'bar' }; 97 | } 98 | }); 99 | 100 | agent = request.agent(app.listen()); 101 | 102 | agent.post('/') 103 | .end(function (err) { 104 | if (err) return done(err); 105 | 106 | setImmediate(function () { 107 | done(); 108 | }); 109 | }); 110 | }); 111 | 112 | function expectFlash(done) { 113 | agent.get('/') 114 | .expect({ foo: 'bar' }) 115 | .expect(200, done); 116 | } 117 | 118 | function expectFlashDeleted(done) { 119 | agent.get('/') 120 | .expect({ foo: 'bar' }) 121 | .expect(200) 122 | .end(function(err) { 123 | setImmediate(function() { 124 | agent.get('/') 125 | .expect({}) 126 | .expect(200, done); 127 | }); 128 | }); 129 | } 130 | 131 | it('should remember flash messages for one request', expectFlash); 132 | 133 | it('should delete flash messages after one request', expectFlashDeleted); 134 | 135 | describe('and app redirects a request', function () { 136 | 137 | beforeEach(function (done) { 138 | agent.get('/redirect').expect(302, function(err) { 139 | setImmediate(function() { 140 | agent.get('/redirect').expect(302, done) 141 | }) 142 | }) 143 | }) 144 | 145 | it('should remember flash messages across redirects', expectFlash); 146 | 147 | it('should delete flash messages after redirect is resolved', expectFlashDeleted); 148 | 149 | }) 150 | }); 151 | }); 152 | --------------------------------------------------------------------------------