index.js
function Module (app, options=DEFAULT_OPTIONS) {
  const sessionName        = options.sessionName        || options.session_name        || DEFAULT_OPTIONS.sessionName;
  const utilityName        = options.utilityName        || options.utility_name        || DEFAULT_OPTIONS.utilityName;
  const localsName         = options.localsName         || options.locals_name         || DEFAULT_OPTIONS.localsName;
  const viewName           = options.viewName           || options.view_name           || DEFAULT_OPTIONS.viewName;
  const beforeSingleRender = options.beforeSingleRender || options.beforeSingleRender  || DEFAULT_OPTIONS.beforeSingleRender;
  const afterAllRender     = options.afterAllRender     || options.afterAllRender      || DEFAULT_OPTIONS.afterAllRender;

  /**
  * Render notifications in queue.
  * @private
  */
  function render(req, res, next)  {
    if (!req.session[sessionName].length) {
      next();
    } else {
      const resultHTML = [];
      async.each(
        req.session[sessionName],
        function(item, next) {
          beforeSingleRender(item, function(error, item) {
            if (error) return next(error);
            app.render(viewName, item, function(error, html) {
              if (error) return next(error);
              resultHTML.push(html);
              next(null);
            })
          })
        },
        function(error) {
          if (error) return next(error);
          req.session[sessionName].length = 0;
          afterAllRender(resultHTML, function(error, html) {
            if (error) return next(error);
            res.locals[localsName] = html;
            next();
          })
        }
      )
    }
  }

  /**
  * Adds flash method to req object and renders all notifications found in
  * req.session
  * @param {ReadStream} req
  * @param {WriteStream} res
  * @param {Function} next
  */
  function FlashMiddleware(req, res, next) {
    if (!isObject(req.session)) throw new Error('express-session is required. (npm i express-session)');
    if (!req.session[sessionName] || !isArray(req.session[sessionName])) req.session[sessionName] = [];

    /**
    * Utility used to programmatically add flash notifications
    * @method Flash Utility
    */
    req[utilityName] = function() {
      const argc = arguments.length;
      let notification;
      let redirect = REDIRECT;

      // Parse arguments
      if (argc) {
        if (argc === 1) {
          const arg = arguments[0];
          if (isObject(arg)) {
            notification = arg;
            redirect = (arg.redirect === undefined) ? redirect : arg.redirect;
          } else {
            notification = {
              message: '' + arg
            };
          }
        } else {
          notification = {
            type: '' + arguments[0],
            message: '' + arguments[1]
          };
          redirect = (arguments[2] === undefined) ? redirect : arguments[2];
        }
      }

      // Queue Notification
      if (notification && req.session[sessionName]) {
        req.session[sessionName].push(notification);
      }

      // If redirect is set, refresh or redirect, accordingly. Otherwise, render the
      // notifications now since it's on this request where they will be displayed.
      if (redirect) {
        const redirectUrl = (typeof redirect === 'string') ? redirect : req.originalUrl;
        res.redirect(redirectUrl);
      } else {
        /**
        * When there is no redirect, notifications must be rendered now and since
        * rendering is async (and this method is sync), a *promise* like function is returned.
        * The function can be called with a callback that will be called after all notifcations
        * are rendered, otherwise, rendering will be done during the next request.
        */
        return function ManualRender(callback) {
          render(req, res, callback);
        }
      }
    }

    /**
    * Process Queued Notifications
    */
    render(req, res, next);
  } 

  return FlashMiddleware;
}
function Module (app, options=DEFAULT_OPTIONS) {
  const sessionName        = options.sessionName        || options.session_name        || DEFAULT_OPTIONS.sessionName;
  const utilityName        = options.utilityName        || options.utility_name        || DEFAULT_OPTIONS.utilityName;
  const localsName         = options.localsName         || options.locals_name         || DEFAULT_OPTIONS.localsName;
  const viewName           = options.viewName           || options.view_name           || DEFAULT_OPTIONS.viewName;
  const beforeSingleRender = options.beforeSingleRender || options.beforeSingleRender  || DEFAULT_OPTIONS.beforeSingleRender;
  const afterAllRender     = options.afterAllRender     || options.afterAllRender      || DEFAULT_OPTIONS.afterAllRender;

  /**
  * Render notifications in queue.
  * @private
  */
  function render(req, res, next)  {
    if (!req.session[sessionName].length) {
      next();
    } else {
      const resultHTML = [];
      async.each(
        req.session[sessionName],
        function(item, next) {
          beforeSingleRender(item, function(error, item) {
            if (error) return next(error);
            app.render(viewName, item, function(error, html) {
              if (error) return next(error);
              resultHTML.push(html);
              next(null);
            })
          })
        },
        function(error) {
          if (error) return next(error);
          req.session[sessionName].length = 0;
          afterAllRender(resultHTML, function(error, html) {
            if (error) return next(error);
            res.locals[localsName] = html;
            next();
          })
        }
      )
    }
  }

  /**
  * Adds flash method to req object and renders all notifications found in
  * req.session
  * @param {ReadStream} req
  * @param {WriteStream} res
  * @param {Function} next
  */
  function FlashMiddleware(req, res, next) {
    if (!isObject(req.session)) throw new Error('express-session is required. (npm i express-session)');
    if (!req.session[sessionName] || !isArray(req.session[sessionName])) req.session[sessionName] = [];

    /**
    * Utility used to programmatically add flash notifications
    * @method Flash Utility
    */
    req[utilityName] = function() {
      const argc = arguments.length;
      let notification;
      let redirect = REDIRECT;

      // Parse arguments
      if (argc) {
        if (argc === 1) {
          const arg = arguments[0];
          if (isObject(arg)) {
            notification = arg;
            redirect = (arg.redirect === undefined) ? redirect : arg.redirect;
          } else {
            notification = {
              message: '' + arg
            };
          }
        } else {
          notification = {
            type: '' + arguments[0],
            message: '' + arguments[1]
          };
          redirect = (arguments[2] === undefined) ? redirect : arguments[2];
        }
      }

      // Queue Notification
      if (notification && req.session[sessionName]) {
        req.session[sessionName].push(notification);
      }

      // If redirect is set, refresh or redirect, accordingly. Otherwise, render the
      // notifications now since it's on this request where they will be displayed.
      if (redirect) {
        const redirectUrl = (typeof redirect === 'string') ? redirect : req.originalUrl;
        res.redirect(redirectUrl);
      } else {
        /**
        * When there is no redirect, notifications must be rendered now and since
        * rendering is async (and this method is sync), a *promise* like function is returned.
        * The function can be called with a callback that will be called after all notifcations
        * are rendered, otherwise, rendering will be done during the next request.
        */
        return function ManualRender(callback) {
          render(req, res, callback);
        }
      }
    }

    /**
    * Process Queued Notifications
    */
    render(req, res, next);
  } 

  return FlashMiddleware;
}
Function used to expose express instance and configuration options.
The actual middleware is returned.
@param {Express} app
@param {Object} options