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

zobox

v0.1.1

Published

Zo-native inbox + sorter + router engine.

Readme

Zobox

Zobox is a Zo-native, open-source inbox + sorter + router engine. It accepts arbitrary structured JSON messages with optional file attachments, stores them durably, and routes them according to configurable sorters.

Features

  • Single ingestion endpoint: POST /messages with multipart or JSON support
  • Filesystem-first storage: Envelopes in inbox/, attachments in files/, indexed by SQLite
  • Type-driven sorters: Define types and sorters in zobox.config.toml
  • Worker polling: GET /messages/next for building distributed subscribers
  • Flexible routing: Send messages to webhooks, workers, or store locally
  • Path templating: Control attachment storage with {channel}/{date}/{eventId}/{filename} patterns
  • Multiple auth modes: Admin and read-only API keys via environment variables
  • Lightweight: Bun/Hono server, easy to run as a Zo User Service or standalone

Quick Start

Get Zobox running locally in under 5 minutes:

1. Install Dependencies

bun install

Or with npm:

npm install

2. Set Up Environment

export ZOBOX_ADMIN_API_KEY="dev-admin-key"
export ZOBOX_READ_API_KEY="dev-read-key"

3. Initialize and Start

ZOBOX_ADMIN_API_KEY="dev-admin-key" bunx zobox init --base-dir /home/workspace/Inbox

This command:

  • Creates the directory structure (inbox/, files/, db/, logs/)
  • Copies example config files
  • Runs database migrations
  • Starts the server

Server listens on http://localhost:8787 by default.

4. Ingest Your First Item

curl -X POST "http://localhost:8787/messages" \
  -H "content-type: application/json" \
  -H "x-api-key: $ZOBOX_ADMIN_API_KEY" \
  -d '{
    "type": "update",
    "payload": { "text": "First idea" }
  }'

5. List Items

curl "http://localhost:8787/messages?limit=20" \
  -H "x-api-key: $ZOBOX_READ_API_KEY"

You should see your item in the response!

Development

Prerequisites

  • Bun >= 1.1 (or Node.js >= 18)
  • SQLite (included with Bun)

Setup

# Install dependencies
bun install

# Copy example config
cp config/zobox.config.example.toml /home/workspace/Inbox/zobox.config.toml

# Set environment variables
export ZOBOX_ADMIN_API_KEY="dev-admin-key"
export ZOBOX_READ_API_KEY="dev-read-key"
export ZOBOX_BASE_DIR="/home/workspace/Inbox"

Running

# Development mode (with hot reload)
bun run dev

# Production mode
bun run start

# Or directly
bun run src/server.ts

CLI Commands

# Initialize directory structure, copy configs, run migrations, and start server
bunx zobox init [--base-dir PATH] [--port PORT]

# Start server only (assumes init already done)
bunx zobox serve [--base-dir PATH] [--port PORT]

# Run migrations only
bunx zobox migrate [--base-dir PATH]

# Help
bunx zobox help

Note: The --base-dir flag always takes precedence over ZOBOX_BASE_DIR environment variable and any base_dir value in the config file.

Testing

# Run tests
bun run test

# Run tests in watch mode
bun run test:watch

# Lint and check code
bun run lint

# Lint and auto-fix issues
bun run check

Git Hooks

This project uses Lefthook for automated pre-commit and pre-push checks:

Pre-commit hooks (run in parallel):

  • format: Auto-format code using Biome
  • lint: Check code quality with Biome
  • types: TypeScript type checking with tsc --noEmit
  • test-related: Run tests when test files or source files change

Pre-push hooks:

  • test-all: Run full test suite
  • lint-strict: Strict linting with error-on-warnings

Hooks are installed automatically via the prepare script when you run bun install.

Customizing Hooks

To customize hooks for your local environment, copy the example:

cp .lefthook-local.yml.example .lefthook-local.yml

Then edit .lefthook-local.yml to skip expensive checks during fast iteration:

# Skip type checking and tests on commit (faster iteration)
pre-commit:
  commands:
    types:
      skip: true
    test-related:
      skip: true

Your local customizations won't be committed (.lefthook-local.yml is in .gitignore).

Project Structure

zobox/
  bin/
    zobox.ts              # CLI entrypoint
  src/
    types.ts               # TypeScript type definitions
    config.ts              # TOML config loader
    storage.ts             # SQLite + filesystem storage
    sorters.ts           # sorter and routing logic
    server.ts              # Hono HTTP server
  config/
    zobox.config.example.toml
    routes.example.json
  db/
    migrations/
      001_init.sql
  docs/
    API.md                 # API reference
    CONFIGURATION.md       # Configuration guide

Documentation

Zo Integration

Deploy Zobox as a Zo User Service:

1. Initialize Zobox (One-Time Setup)

ZOBOX_ADMIN_API_KEY="your-admin-key" bunx zobox init --base-dir /home/workspace/Inbox

This creates the directory structure, copies config files, and runs migrations. You can stop the server after initialization (Ctrl+C).

2. Create User Service

Configure in Zo:

  • Label: zobox
  • Type: http
  • Local port: 8787
  • Entrypoint: bunx zobox serve
  • Workdir: /home/workspace/Inbox

3. Set Environment Variables

Add to your Zo service configuration:

  • ZOBOX_ADMIN_API_KEY (required)
  • ZOBOX_READ_API_KEY (optional, recommended)

Your Zobox service will start automatically with Zo.

API Overview

See docs/API.md for complete documentation.

Core Endpoints

  • POST /messages: Ingest messages (JSON or multipart with attachments)
  • GET /messages: List messages with filtering and cursor pagination (response key: items)
  • GET /messages/next: Worker polling for unclaimed messages
  • POST /messages/:id/ack: Acknowledge item processing
  • GET /health: Health check

Authentication

# Admin key (full access)
x-api-key: YOUR_ADMIN_KEY

# Read key (read-only)
x-api-key: YOUR_READ_KEY

# Or Bearer token
authorization: Bearer YOUR_KEY

Configure in zobox.config.toml:

[auth]
admin_api_key_env_var = "ZOBOX_ADMIN_API_KEY"
read_api_key_env_var  = "ZOBOX_READ_API_KEY"
required = true

Ingest Examples

JSON only:

curl -X POST "http://localhost:8787/messages" \
  -H "content-type: application/json" \
  -H "x-api-key: YOUR_ADMIN_KEY" \
  -d '{"type":"update","payload":{"text":"Hello"}}'

JSON + base64 attachments:

curl -X POST "http://localhost:8787/messages" \
  -H "content-type: application/json" \
  -H "x-api-key: YOUR_ADMIN_KEY" \
  -d '{
    "type":"post",
    "payload":{"title":"My post"},
    "attachments":[{"filename":"photo.jpg","mimeType":"image/jpeg","base64":"..."}]
  }'

Multipart with files:

curl -X POST "http://localhost:8787/messages" \
  -H "x-api-key: YOUR_ADMIN_KEY" \
  -F 'event={"type":"post","payload":{"title":"My post"}}' \
  -F '[email protected]'

Configuration

See docs/CONFIGURATION.md for complete guide.

Types and Sorters

Define types in zobox.config.toml:

[types.update]
description = "Generic status update"
channel = "Updates"

[sorters.updates]
type = "update"
files_path_template = "{baseFilesDir}/Updates/{date}/{eventId}/{filename}"
append_to_file = "/home/workspace/Inbox/updates.md"
destination = "store_only"

Path Templates

Control where attachments are stored using tokens:

  • {baseFilesDir}: Base files directory
  • {channel}: Item channel
  • {date}: ISO date (YYYY-MM-DD)
  • {eventId}: Item UUID
  • {timestamp}: Sanitized timestamp
  • {filename}: Final filename

Example: {baseFilesDir}/{channel}/{date}/{eventId}/{filename} Renders: /home/workspace/Inbox/files/Updates/2025-11-22/550e8400.../photo.jpg

Filename Strategies

  • original: Keep original filename
  • timestampPrefix: Prefix with 20251122T123456_
  • eventIdPrefix: Prefix with item UUID
  • uuid: Replace filename with new UUID

Route Destinations

Define routing in routes.json:

{
  "destinations": {
    "store_only": {
      "kind": "noop"
    },
    "publish_to_worker": {
      "kind": "http",
      "url": "http://localhost:9000/zobox/messages",
      "method": "POST",
      "enabled": true
    }
  }
}

Reference in sorter:

[sorters.posts]
type = "post"
destination = "publish_to_worker"

Storage Layout

Given base_dir = "/home/workspace/Inbox":

/home/workspace/Inbox/
  zobox.config.toml
  routes.json
  inbox/
    YYYY-MM-DD/
      <message-id>.json   # Message envelopes
  files/
    <channel>/
      YYYY-MM-DD/
        <item-id>/
          <filename>        # Attachments
  db/
    zobox.db              # SQLite index
    migrations/
      001_init.sql
  logs/                    # Reserved for future use

SQLite Schema

Table messages:

  • id, type, channel, created_at
  • file_path, file_dir
  • attachments_count, has_attachments
  • subscribed_by, subscribed_at
  • summary (reserved for future previews)
  • tags (JSON string)

Indexes on created_at, type, channel, has_attachments, tags for fast queries.