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 🙏

© 2026 – Pkg Stats / Ryan Hefner

securesite

v1.0.4

Published

a light fastify website with basic security

Downloads

295

Readme

securesite

A lightweight, secure web server factory for Fastify with built-in session authentication, security headers, and static file serving.

Features

  • 🔐 Session-based Authentication - Secure cookie sessions with customizable login/logout endpoints
  • 🛡️ Security First - Helmet.js integration for security headers
  • 📁 Static File Serving - Optional static file support with configurable paths
  • Fastify Powered - High-performance Node.js web framework
  • 🎯 Flexible Routing - Declarative route configuration with public/private route support
  • 📝 Request Context - Clean handler API with user session, body, query, and params

Installation

npm install securesite

Quick Start

const securesite = require('securesite');

const app = securesite({
  secret: 'your-super-secret-key-must-be-at-least-32-chars-long',
  onAuthenticate: async (username, password) => {
    // Your auth logic here
    if (username === 'admin' && password === 'password') {
      return { id: 1, username: 'admin' };
    }
    return null;
  }
});

app.listen({ port: 3000 }, (err) => {
  if (err) throw err;
  console.log('Server running on http://localhost:3000');
});

Configuration Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | secret | string | required | Session secret (min 32 characters) | | onAuthenticate | function | null | Async function (username, password) => userData \\| null | | staticPath | string | null | Path to static files directory | | loginUrl | string | /login | Custom login endpoint path | | logoutUrl | string | /logout | Custom logout endpoint path | | sessionMaxAge | number | 1800000 (30min) | Session cookie max age in milliseconds | | trustProxy | boolean | true | Trust proxy headers (for secure cookies behind proxy) | | limit | string | 1mb | Request body size limit | | verbose | boolean \\| function | false | Enable logging or provide custom logger function |

Route Configuration

Define routes using HTTP method keys (get, post, put, delete, patch):

const app = securesite({
  secret: 'your-super-secret-key-must-be-at-least-32-chars-long',
  onAuthenticate: async (username, password) => {
    // Return user data or null
    return { id: 1, username };
  },
  
  // Public routes (no authentication required)
  get: {
    '/': async (ctx) => ({ message: 'Welcome!' }),
    '/public': { public: true, handler: async (ctx) => ({ data: 'public data' }) }
  },
  
  // Protected routes (require authentication)
  post: {
    '/api/data': async (ctx) => {
      // ctx.user contains authenticated user data
      return { created: true, by: ctx.user.username };
    }
  }
});

Handler Context

Route handlers receive a context object (ctx) with:

{
  user: req.session.user || null,     // Authenticated user data
  session: req.session,               // Full session object
  body: req.body,                     // Request body
  query: req.query,                   // Query parameters
  params: req.params,                 // URL parameters
  headers: req.headers,               // Request headers
  ip: req.ip,                         // Client IP address
  req: req                            // Original Fastify request
}

Authentication API

Login

POST /login
Content-Type: application/json

{
  \"username\": \"admin\",
  \"password\": \"password\"
}

Success Response:

{
  \"success\": true,
  \"user\": { \"id\": 1, \"username\": \"admin\" }
}

Error Response:

{
  \"error\": \"Unauthorized\",
  \"message\": \"Invalid credentials\"
}

Logout

POST /logout

Response:

{
  \"success\": true
}

Complete Example

const securesite = require('securesite');
const path = require('path');

const app = securesite({
  secret: process.env.SESSION_SECRET || 'default-secret-key-32-chars-long!!',
  staticPath: './public',
  verbose: true,
  
  onAuthenticate: async (username, password) => {
    // Replace with your database/auth logic
    const users = [
      { id: 1, username: 'admin', password: 'admin123', role: 'admin' },
      { id: 2, username: 'user', password: 'user123', role: 'user' }
    ];
    
    const user = users.find(u => u.username === username && u.password === password);
    if (user) {
      const { password, ...userData } = user;
      return userData;
    }
    return null;
  },
  
  // Public routes
  get: {
    '/health': { public: true, handler: async () => ({ status: 'ok' }) }
  },
  
  // Protected routes
  get: {
    '/api/profile': async (ctx) => ({
      user: ctx.user,
      message: `Hello ${ctx.user.username}!`
    })
  },
  
  post: {
    '/api/echo': async (ctx) => ({
      received: ctx.body,
      user: ctx.user.username
    })
  }
});

app.listen({ port: 3000, host: '0.0.0.0' }, (err) => {
  if (err) {
    console.error(err);
    process.exit(1);
  }
  console.log('🚀 Server ready at http://localhost:3000');
});

Security Considerations

  • Session Secret: Always use a strong, random secret of at least 32 characters in production
  • HTTPS: Set NODE_ENV=production to enable secure cookies (requires HTTPS)
  • Trust Proxy: Enable when running behind a reverse proxy (Nginx, etc.)
  • Body Limit: Adjust limit option based on your application's needs

Dependencies

License

MIT

Author

littlejustnode