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

@holix/router

v0.0.2

Published

A lightweight and fast router for Node.js with middleware support

Readme

@holix/router

Custom protocol router for Holix applications. Handles HTTP-like routing for Electron custom protocols (e.g., app://).

Installation

pnpm add @holix/router

Features

  • 🎯 Custom Protocol Support: Handle app://, holix:// or any custom protocol
  • 🚀 Radix3 Based: Fast route matching using radix tree
  • 🔧 Middleware Support: Onion-style middleware chain
  • 📦 Type-safe: Full TypeScript support
  • 🌐 HTTP-like API: Familiar request/response pattern
  • 🛠️ HTML Builder: Built-in HTML generation utilities

Usage

Basic Setup

import { HolixProtocolRouter } from '@holix/router'

// Create a router for custom protocol
const router = new HolixProtocolRouter()

// Register the protocol handler in Electron main process
protocol.handle('app', async (request) => {
  return await router.fetch(request)
})

Defining Routes

// Simple route
router.get('/app/home', async (ctx) => {
  ctx.html('<h1>Home Page</h1>')
})

// Route with parameters
router.get('/app/users/:id', async (ctx) => {
  const { id } = ctx.params
  ctx.json({ userId: id })
})

// Multiple HTTP methods
router.post('/app/api/data', async (ctx) => {
  ctx.json({ message: 'Data received' })
})

// All methods
router.all('/app/health', async (ctx) => {
  ctx.text('OK')
})

Context API

The route handler receives a context object with convenient methods:

router.get('/app/example', async (ctx) => {
  // Request information
  ctx.url        // URL object
  ctx.params     // Route parameters
  ctx.method     // HTTP method
  ctx.scheme     // Protocol scheme (e.g., 'app')

  // Response methods
  ctx.status(200)                    // Set status code
  ctx.header('X-Custom', 'value')    // Set header
  ctx.headers({ ... })               // Set multiple headers

  // Send response
  ctx.text('Plain text')             // Plain text response
  ctx.json({ data: 'value' })        // JSON response
  ctx.html('<h1>HTML</h1>')          // HTML response
  ctx.buffer(Buffer.from('data'))    // Binary response
  ctx.stream(readableStream)         // Stream response
  ctx.redirect('/app/other')         // Redirect
})

HTML Builder

Built-in HTML generation utilities:

import { html } from '@holix/router'

router.get('/app/page', async (ctx) => {
  const page = ctx.createHtml()
    .tag('html', { lang: 'en' })
    .tag('head')
    .tag('title')
    .text('My Page')
    .close()
    .tag('meta', { charset: 'utf-8' })
    .close() // close head
    .tag('body')
    .tag('h1')
    .text('Welcome')
    .close()
    .tag('p')
    .text('This is a page')
    .close()
    .close() // close body
    .close() // close html

  ctx.html(page.toString())
})

// Or use the helper function
router.get('/app/simple', async (ctx) => {
  const content = html('div', { class: 'container' })
    .tag('h1')
    .text('Title')
    .close()
    .tag('p')
    .text('Content')
    .close()

  ctx.html(content.toString())
})

Middleware

Use middleware for cross-cutting concerns:

// Logger middleware
router.use('/app/*', async (ctx, next) => {
  console.log(`${ctx.method} ${ctx.url.pathname}`)
  await next()
})

// Auth middleware
router.use('/app/admin/*', async (ctx, next) => {
  if (!isAuthenticated(ctx)) {
    ctx.status(401).text('Unauthorized')
    return
  }
  await next()
})

// Error handling
router.use('/app/*', async (ctx, next) => {
  try {
    await next()
  }
  catch (error) {
    console.error(error)
    ctx.status(500).text('Internal Server Error')
  }
})

Complete Example

import { HolixProtocolRouter } from '@holix/router'
import { app, protocol } from 'electron'

app.whenReady().then(() => {
  const router = new HolixProtocolRouter()

  // Home page
  router.get('/app/index.html', async (ctx) => {
    const page = ctx.createHtml()
      .tag('html')
      .tag('head')
      .tag('title')
      .text('My App')
      .close()
      .close()
      .tag('body')
      .tag('h1')
      .text('Welcome to My App')
      .close()
      .close()
      .close()

    ctx.html(page.toString())
  })

  // API endpoint
  router.get('/app/api/users/:id', async (ctx) => {
    const user = await getUserById(ctx.params.id)
    ctx.json(user)
  })

  // Static file fallback
  router.get('/app/*', async (ctx) => {
    // Serve static files
    const filePath = ctx.url.pathname.replace('/app', '')
    const file = await readFile(filePath)
    ctx.buffer(file)
  })

  // Register protocol
  protocol.handle('app', async (request) => {
    return await router.fetch(request)
  })
})

API Reference

HolixProtocolRouter

Main router class for handling custom protocol requests.

Methods

  • get(path, handler) - Register GET route
  • post(path, handler) - Register POST route
  • put(path, handler) - Register PUT route
  • delete(path, handler) - Register DELETE route
  • patch(path, handler) - Register PATCH route
  • all(path, handler) - Register route for all methods
  • use(path, handler) - Register middleware
  • fetch(request) - Handle incoming request

RouteContext

Context object passed to route handlers.

interface RouteContext {
  url: URL
  params: Record<string, string>
  req: Request
  method: string
  scheme: string
  domain?: string
}

ExtendedRouteContext

Extended context with response methods.

interface ExtendedRouteContext extends RouteContext {
  status: (code: number) => this
  header: (name: string, value: string) => this
  headers: (headers: Record<string, string>) => this
  text: (body: string, statusCode?: number) => void
  json: (data: any, statusCode?: number) => void
  html: (body: string, statusCode?: number) => void
  buffer: (body: Buffer, statusCode?: number) => void
  stream: (body: Readable, statusCode?: number) => void
  redirect: (url: string, statusCode?: number) => void
  createHtml: () => HtmlBuilder
}

Note

This package provides the routing infrastructure for custom protocols. File-based routing functionality is not yet implemented. For now, you need to manually define routes using the router API.

License

MIT