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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@noturbob/redact

v2.2.1

Published

A simple, user-friendly web API framework built in Node.js.

Readme

🛡️ Redact.js

The Declarative, "Just Return" Framework for Modern Node.js

npm version License: MIT Node.js

Why Redact?FeaturesInstallationDocumentationContributing


📖 Introduction

Redact.js is a next-generation micro-framework for Node.js built on a simple premise: Web servers should be simple function calls, not complex state managers.

It abandons the traditional, imperative style of Express (req, res, next) in favor of a clean, declarative syntax. With Redact, you define your API as a structured object, and your logic is pure: You receive input, and you return output. The framework handles the HTTP complexity for you.


🆚 Why Redact? (vs Express)

Most Node.js frameworks are Imperative: you have to tell the server how to send a response step-by-step. Redact is Declarative: you tell the server what the response is.


✨ Key Features

⚡ Declarative Routing

Define your API structure in a readable, nested object syntax.

↩️ "Just Return" Logic

Return an Object/Array for JSON, or a String for text. No res object needed.

🔌 Built-in WebSockets

Real-time support out of the box with app.socket().

🔀 Dynamic Routing

Native support for parameters like /users/:id.

🛡️ Automatic Security

Built-in protection against DoS attacks (1MB body limit).

⚙️ Smart Middleware

Filter requests globally before they hit your logic.

📦 Zero Config • 🚄 Lightning Fast • 🎯 Type-Friendly


💾 Installation

npm install @noturbob/redact ws

Note: ws is required for WebSocket features


🚀 Quick Start

const app = require('@noturbob/redact')();

// Define your API
app.routes({
  path: "/",
  GET: "Welcome to Redact!", // Returns text
  POST: (body) => {
    // Returns JSON automatically
    return { status: "created", data: body };
  }
});

app.listen(3000, () => {
  console.log("🚀 Server running at http://localhost:3000");
});

📚 Documentation

1️⃣ Declarative Routing

Instead of writing imperative code, describe your API.

app.routes({
  path: "/api/v1/status",
  GET: { status: "online", uptime: process.uptime() }
});

2️⃣ Handling Input (input vs req)

Your route handlers receive two arguments:

  • input: The parsed data (JSON body for POST/PUT, or empty object).
  • req: The full request context (headers, params, query).
app.routes({
  path: "/products",
  POST: (body, req) => {
    // 'body' is the JSON payload sent by the user
    console.log("User Agent:", req.headers['user-agent']);
    
    return { success: true, product: body };
  }
});

3️⃣ Dynamic Routes

Use : to define dynamic parameters. Access them via req.params.

app.routes({
  path: "/users/:id",
  GET: (input, req) => {
    // GET /users/500 -> { userId: "500" }
    return { userId: req.params.id };
  }
});

4️⃣ Real-Time WebSockets

Redact creates a unified server for both HTTP and WebSockets.

app.socket({
  path: '/chat',
  
  open: (ws) => {
    console.log("✅ Client connected");
    ws.send("Welcome!");
  },

  message: (ws, data, clients) => {
    // 'data' is auto-parsed JSON
    // 'clients' is a Set of all connected users (for broadcasting)
    clients.forEach(client => client.send(JSON.stringify(data)));
  },

  close: () => {
    console.log("❌ Client disconnected");
  }
});

5️⃣ Middleware

Middleware runs before every request. It follows the "Just Return" philosophy:

  • Return undefined: Request proceeds to the route handler.
  • Return a value: Request stops, and that value is sent as the response.
app.use((req) => {
  // Log every request
  console.log(`[${req.method}] ${req.url}`);

  // Security Check
  if (req.url.includes("/admin")) {
    // Stop the request immediately with a 403-like error
    return { error: "Unauthorized Access" };
  }
});

6️⃣ Query Parameters

Query strings are automatically parsed into req.query.

Request: GET /search?q=javascript&sort=desc

app.routes({
  path: "/search",
  GET: (input, req) => {
    return {
      results: [],
      meta: {
        query: req.query.q,    // "javascript"
        sort: req.query.sort   // "desc"
      }
    };
  }
});

🎯 Example: Complete REST API

const app = require('@noturbob/redact')();

let users = [
  { id: 1, name: "Alice" },
  { id: 2, name: "Bob" }
];

app.routes({
  path: "/api/users",
  
  // Get all users
  GET: () => users,
  
  // Create new user
  POST: (body) => {
    const newUser = { id: users.length + 1, ...body };
    users.push(newUser);
    return newUser;
  }
});

app.routes({
  path: "/api/users/:id",
  
  // Get specific user
  GET: (input, req) => {
    const user = users.find(u => u.id === parseInt(req.params.id));
    return user || { error: "User not found" };
  },
  
  // Update user
  PUT: (body, req) => {
    const index = users.findIndex(u => u.id === parseInt(req.params.id));
    if (index === -1) return { error: "User not found" };
    users[index] = { ...users[index], ...body };
    return users[index];
  },
  
  // Delete user
  DELETE: (input, req) => {
    const index = users.findIndex(u => u.id === parseInt(req.params.id));
    if (index === -1) return { error: "User not found" };
    users.splice(index, 1);
    return { success: true };
  }
});

app.listen(3000);

🤝 Contributing

We welcome contributions! Please fork the repository and submit a Pull Request.

  1. 🍴 Fork the Project
  2. 🌿 Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. 💾 Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. 🚀 Push to the Branch (git push origin feature/AmazingFeature)
  5. 🎉 Open a Pull Request

📄 License

Distributed under the MIT License. See LICENSE for more information.


🌟 Show Your Support

If you find Redact.js helpful, please consider giving it a ⭐ on GitHub!


Built with ❤️ by noturbob

⬆ back to top