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

teeny-express-server

v0.1.1

Published

A small configurable static server powered by Express

Downloads

6

Readme

Teeny Static Server

npm version

Teeny Express Server is a simple configurable static server, powered by Express.

It provides some default out of the box:

  • Authentication via Passport
    • Registration
    • Registration verification
    • Session expiration
    • Login
    • Logout
    • Password recovery
  • Database persistence
  • Routes configuration
    • Static caching
    • GZIP compression
    • Automatic HTTPS redirection
    • Custom favicon
    • Authentication
    • Token verification (useful for registration)
    • Access to internal database API (proxied to either MongoDB or Lowdb)
      • findUser()
      • updateUser()
      • addUser()

Installation

> cd your-project
> npm install --save teeny-express-server

Starting

Assuming you created a configuration file under your-project/config.js, you can start your new server with the following command line:

> cd your-project
> npx teeny-express-server --config config.js

Configuration

The configuration file is a JavaScript module.

// my-project/config.js
const path = require("path");

module.exports = {
  /**
   * Port the server will listen to.
   */
  port: 3000,
  /**
   * Database configuration.
   */
  database: (DB_TYPE) => ({
    /**
     * The type of database to use for this project.
     * One of DB_TYPE.MONGODB or DB_TYPE.LOWDB.
     */
    type: DB_TYPE.MONGODB,
    /**
     * The location of the DB.
     * For LowDB, it needs to be the full path to a JSON file.
     * For MongoDB, it is only used in dev mode, and needs to be a folder.
     * In production, MongoDB with rely on the environment variable
     * ATLAS_DB_URI.
     */
    location: path.join(process.cwd(), "tmp/DB"),
  }),
  /**
   * Authentication redirects.
   * This object list all potential redirects for the following actions:
   * login, register, activate, forgot and update.
   */
  auth: {
    login: {
      /**
       * Where to redirect when login is successful.
       */
      successRedirectTo: "/",
      /**
       * Where to redirect when access requires authentication
       * and the user is not authenticated.
       */
      notAuthenticatedRedirectTo: "/login",
      /**
       * Where to redirect when login is not successful.
       * This can be for multiple reasons: user does not exist or password
       * is invalid. The parameter used here (auth=401) is simply an
       * example, but anything can be used instead.
       */
      failureRedirectTo: "/login?auth=401",
    },
    register: {
      /**
       * Where to redirect when a user has successfully registered a
       * new account (but not yet activated).
       */
      successRedirectTo: "/login?auth=201",
      /**
       * Where to redirect when a user has failed to registered a
       * new account. The reason is unknown (internal serve error).
       */
      failureRedirectTo: "/login?auth=500",
      /**
       * Where to redirect when a user has failed to registered a
       * new account. The reason is because the account already exists.
       */
      alreadyExistsRedirectTo: "/login?auth=403",
      /**
       * How to confirm the registration.
       * 2 choices:
       * - none: once someone registers, it's done!
       * - json: this adds one step to the registration process: activation.
       * By choosing json, the response from the registration will be a JSON
       * object with one key: "url" with an activation URL.
       * It's up to the implementer to use that URL and provide it to the
       * person who is registering. One way is to send an email with it.
       * Once this URL is hit, the account is activated and the user can
       * login. As long as this URL is not used, the account remains dormant.
       */
      confirmation: "json",
    },
    activate: {
      /**
       * Where to redirect to when a user is hitting the "activate" URL provided
       * during registration if the confirmation choice was "json" (see above).
       */
      successRedirectTo: "/",
      /**
       * Where to redirect to when a user is hitting an "activate " URL that is
       * invalid (invalid token, or it's been used before).
       */
      failureRedirectTo: "/login?auth=406",
    },
    forgot: {
      /**
       * Where to redirect to when a user ask for their password to be reset, but
       * the request failed.
       */
      failureRedirectTo: "/login?auth=500",
    },
    update: {
      /**
       * What is the corresponding static route where password reset activation
       * requests should be routed to. Please see the special "token" key provided
       * in the static route.
       */
      updatePassword: "/update",
      /**
       * Where to redirect to when password reset has been successful.
       */
      successRedirectTo: "/login?auth=202",
      /**
       * Where to redirect to when password reset has not been successful.
       */
      failureRedirectTo: "/login?auth=500",
    },
  },
  /**
   * What favicon to use for this application.
   */
  favicon: path.join(process.cwd(), "public/favicon.ico"),
  /**
   * List of static path that needs special caching. For example,
   * JavaScript, CSS or images files. Each routes can use the "utils" helper
   * that provides a few constants, such as times in milliseconds that can
   * be used for caching expiration (but you can use your own if needed):
   *  - utils.TWENTY_FOUR_HOURS
   *  - utils.TWO_WEEKS
   *  - utils.ONE_YEAR
   */
  static: ({ utils }) => [
    {
      /**
       * Use this option to create a virtual path prefix (where the path does
       * not actually exist in the file system) for files that are served.
       */
      virtual: "",
      /**
       * This specifies the root directory from which to serve static assets.
       */
      root: path.join(process.cwd(), "public/js"),
      /**
       * Set the max-age property of the Cache-Control header in milliseconds or
       * a string in ms format (see https://www.npmjs.com/package/ms).
       */
      maxAge: utils.isProd() ? utils.ONE_YEAR : 0,
    },
  ],
  /**
   * List of middleware and HTTP method routes (such as get, put, post, and so on).
   * Based on the keys provided, Teeny Static Server will interpret them as either
   * pure redirect to a static file or pure API request. If the special key "token"
   * is used and a token is available in the server (for example during activation),
   * it will be passed as a parameter to the corresponding URL, as in url?token=xxx.
   */
  routes: ({ utils }) => [
    /**
     * Example for a login page.
     * - route is the path to listen to
     * - method is the HTTP method (get, put, post, etc.)
     * - auth is a boolean indicating this route should not be protected by authentication
     * - file is the actual file to render when the route is resolved
     * - root is root directory from which to serve the file.
     */
    {
      route: "/login",
      method: "GET",
      auth: false,
      file: "login.html",
      root: path.join(process.cwd(), "public"),
    },
    /**
     * Example for a main page.
     * - route is the path to listen to
     * - method is the HTTP method (get, put, post, etc.)
     * - auth is a boolean indicating this route should be protected by authentication
     * - file is the actual file to render when the route is resolved
     * - root is root directory from which to serve the file.
     */
    {
      route: "/",
      method: "GET",
      auth: true,
      file: "index.html",
      root: path.join(process.cwd(), "public"),
    },
    /**
     * Example for a reset password page.
     * - route is the path to listen to
     * - method is the HTTP method (get, put, post, etc.)
     * - auth is a boolean indicating this route should not be protected by authentication
     * - token is a boolean indicating that any activation token should be passed as a param
     * - file is the actual file to render when the route is resolved
     * - root is root directory from which to serve the file.
     */
    {
      route: "/update",
      method: "GET",
      auth: false,
      token: true,
      file: "update.html",
      root: path.join(process.cwd(), "public"),
    },
    /**
     * Example for an API.
     * - route is the REST path
     * - method is the HTTP method (post)
     * - auth is a boolean indicating this route should be protected by authentication
     * - action is accepting a method to run, receiving req, res and next
     */
    {
      route: "/api/users",
      method: "POST",
      auth: true,
      action: (req, res, next) => {
        utils.db.findUser({ username: "testing" }, (err, user) => {
          res.send(err ? { status: "error" } : user);
        });
      },
    },
    /**
     * The last route should often be a catch all (*) and renders a 404 page.
     */
    {
      route: "*",
      method: "all",
      auth: false,
      file: "404.html",
      status: utils.constants.HTTP_NOT_FOUND,
      root: path.join(process.cwd(), "public"),
    },
  ],
};

Appendix

Mongo Shell

List all users

> mongo mongodb://localhost/teeny-server-s
MongoDB shell version v4.2.1
connecting to: mongodb://localhost:27017/teeny-server-s

db.users.find()