npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

slay

v4.1.0

Published

Rock-solid structured application layout for building APIs and web apps in Node.js

Downloads

55

Readme

Build
Status

Rock-solid structured application layout for building APIs and web apps in Node.js.

Motivation

The goal of slay is to provide the absolute minimum amount of consistency in a Node.js application without forcing an enormous amount of convention onto users. The consistency goal also centers around encouraging modularity in application-level code for maximum reuse. This is accomplished through three simple features: application layout, "preboots", and a consistent application startup.

Application layout

By convention slay looks for user-defined modules in the following locations:

lib/preboots
lib/middlewares
lib/routes

This is done using standard, built-in Node.js module loading which means that each of these could be individual files of the same name instead of folders. Feel free to mix and match as your application's complexity grows. e.g.:

lib/preboots/index.js
lib/middlewares.js
lib/routes/index.js

What is a "preboot"?

"A preboot is a middleware for application extensibility"

That is, instead of function (req, res, next) a preboot is function (app, options, done). By enforcing a consistent function signature to application extensibility all require ordering problems become trivial. For example:

lib/preboots/index.js

module.exports = function (app, options, done) {
  //
  // **SCHEDULE** the attachment and initialization of
  // connections to our models.
  //
  app.preboot(require('./models'));
  done();
};

lib/preboots/models.js

module.exports = function (app, options, next) {
  //
  // Attach all of the models for our API / microservices
  // to the app itself and connect to them
  // (e.g. initialize TCP sockets, etc).
  //
  app.models = require('../models');
  app.models.connect(next);
};

While this may seem too obvious it does several things:

  1. Makes application extensibility simple and elegant. No complex plugin system required.
  2. Ensures that all application extensibility is ordered in a single location: lib/preboots/index.js.
  3. Encourages modularity through extending the core app by creating new preboots instead of creating an arbitrary, ad-hoc set of utility modules with a (potentially) much more complex internal dependency graph.

Consistent application startup

const slay = require('slay');
const app = new slay.App(__dirname);
app.start(options, function (err) {
  if (err) { throw err; }
  app.log.info(`Listening on ${app.config.get('http')`);
});

Calling app.start above will trigger two main interceptors:

  1. "setup" interceptor.
  • /preboots will be loaded in app.before('setup')
  • routers
    • app.perform('routers') triggered in app.before('setup')
    • app.router will be available by app.after('routers') or by app.perform('setup')
  1. "start" interceptor
  • lib/routes will be loaded in app.before('start')
    • lib/routes/index.js should call app.perform('actions') once to make sure all routes from app.router are loaded in the app.
  • lib/middlewares will be loaded in before('start')

For more information look at App.Bootstrap

API documentation

App

The App exposed by slay has all of the functionality exposed by an app created by express along with:

| Method | Description | Inherited from | | --------------- | --------------------------------------- | ----------------- | | App.bootstrap | Core slay bootstrap flow | slay.App | | app.hookable | Defines a hookable action | slay.App | | app.stack | Defines a middleware stack | slay.App | | app.config | Config loading through nconf | config preboot | | app.log | Logger defined through winston | logger preboot | | app.routes | Top-level express Router | routers preboot | | app.preboot | Schedule a preboot | broadway | | app.mixin | Add functionality into the app | broadway | | app.start | Start the application | broadway | | app.close | Shutdown the application | broadway | | app.perform | Execute a named interceptor | understudy | | app.before | Execute before a named interceptor | understudy | | app.after | Execute after a named interceptor | understudy |

Interceptors

| Name | Description | Invoked by | | --------- | --------------------------------------- | ---------- | | setup | Pre-start bootstrap setup | slay | | start | Main application startup | slay | | routers | Definition of app.routes | slay | | actions | Critical path application functionality | User |

Stacks

A Stack is a lightweight container for a set of before and after middlewares. This becomes very useful when you have potentially multiple routers in your application. A Stack can be defined using app.stack as follows:

middlewares.js

module.exports = function (app, options, next) {
  //
  // An authorization middleware for different roles
  // returns an HTTP middleware function when invoked.
  //
  var authorize = require('./authorize');

  //
  // Stack middlewares can be declared and used inline
  //
  app.use(
    app.stack({
      name: 'admin-only',
      before: [authorize('admin')]
    }).middleware(function (req, res, next) {
      // Dispatch (req, res) to a router.
    })
  );

  //
  // Or extended from a previous declaration and used inline
  //
  app.use(
    app.stacks['designer-only']
      .before(authorize('designer'))
      .middleware(function (req, res, next) {
        // Dispatch (req, res) to a router.
      })
  );
};

All Stack instances created by invoking app.stack will be exposed on the app.stacks object.

App startup in-detail

  1. App is bootstrapped and app.start([options], callback); is invoked.
  2. app.perform('setup') performs before "setup" interceptors (see: understudy interceptors). This executes the built-in slay preboots which:
  • Creates app.config(an instance of nconf.Provider).
  • Creates app.log (an instance of winston.Logger).
  • Creates user preboots (in your app lib/preboots[.js]?). This allows arbitrary user-defined preboots for extensibility in a sync or async fashion.
  • Schedules middlewares (in your app lib/middlewares[.js]?).
  • Schedules routes (in your app lib/routes[.js]?).
  • Schedules creation of default 404 route.
  1. Any after "setup" interceptors are invoked. (see: understudy interceptors). slay runs nothing by default here.
  2. app.perform('start') performs before "start" interceptors (see: understudy interceptors). This executes the built-in slay preboots which:
  • Schedules defaults for after "routers"
  • Invokes app.perform('routers') which performs before "routers" interceptors, adds app.routes, and performs after "routers" interceptors.
  • Invokes user-defined preboots (in your app lib/preboots[.js]?). scheduled in (2) above.
  • Invokes user-defined middlewares (in your app lib/middlewares[.js]?) scheduled in (2) above.
  • Invokes user-defined routes (in your app lib/routes[.js]?) scheduled in (2) above.
  • Adds the final 404 handler on app.routes.
  1. App.prototype._listen is invoked which creates any http and/or https servers.
  2. Any after "start" interceptors are invoked. (see: understudy interceptors). slay runs nothing by default here.
  3. The callback from app.start([options], callback); is invoked. The app is now started and ready for use.

Tests

npm test

License

MIT

Contributors: Fady Matar, Charlie Robbins