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

cry-ebus-proxy

v1.0.3

Published

ebus to rest + websocket proxy

Readme

ebus-proxy

High-performance HTTP proxy server for cry-ebus2 client requests, built with uWebSockets.js.

Installation

npm install

Configuration

Create a .env file with the following variables:

| Variable | Description | Default | |----------|-------------|---------| | HOST | Server bind address | 0.0.0.0 | | PORT | Server port | 3033 | | TIMEOUT | Default request timeout in ms | 500 | | DEBUG | Enable debug logging | false | | MAX_BODY_SIZE_MB | Maximum request body size in MB | 1 | | ALLOWED_ORIGINS | Comma-separated list of allowed origins (hostname only, port ignored) | - | | API_KEYS | Comma-separated list of valid API keys | - |

Security

When ALLOWED_ORIGINS or API_KEYS are configured, requests must satisfy at least one of these conditions:

  • Origin check: The Origin header hostname matches one in ALLOWED_ORIGINS
  • API key: A valid key is provided via:
    • Query parameter: ?apikey=<key> or ?api_key=<key>
    • Header: X-API-Key: <key> or Authorization: Bearer <key>
    • Cookie: apikey=<key> (set via /apikey/<key> endpoint)

If neither ALLOWED_ORIGINS nor API_KEYS are configured, all requests are allowed and a warning is printed on startup.

Cookie Authentication

Set an API key as an HttpOnly cookie by visiting /apikey/<key>. Clear the cookie with /apikey/clear.

Example .env:

ALLOWED_ORIGINS=example.com, localhost, app.example.com
API_KEYS=secret-key-1, secret-key-2

Usage

npm start

REST API

GET or POST to /

All payloads use msgpack binary format with structuredClone: true, base64-encoded for query parameters.

Parameters: | Parameter | Description | Required | |-----------|-------------|----------| | service | Service name to call | Yes | | payload | Base64-encoded msgpack payload | No | | timeout | Request timeout in ms | No |

Response: application/msgpack binary

JavaScript Client Example

import { Packr, Unpackr } from "msgpackr";

const packr = new Packr({ structuredClone: true });
const unpackr = new Unpackr({ structuredClone: true });

// Encode payload as base64
const payload = Buffer.from(packr.pack({ key: "value" })).toString("base64");

// GET request
const response = await fetch(`http://localhost:3033/?service=my-service&payload=${payload}&apikey=secret-key-1`);
const result = unpackr.unpack(new Uint8Array(await response.arrayBuffer()));

// POST request
const postResponse = await fetch("http://localhost:3033/", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": "secret-key-1"
  },
  body: JSON.stringify({ service: "my-service", payload })
});
const postResult = unpackr.unpack(new Uint8Array(await postResponse.arrayBuffer()));

Utility Endpoints

| Endpoint | Auth | Description | |----------|------|-------------| | / | Yes | Returns ebus-proxy when no service specified | | /ping | No | Returns pong <ISO-date> for health checks | | /doc | No | Returns available endpoints | | /apikey/:key | No | Sets API key as HttpOnly cookie (1 week) | | /apikey/clear | No | Clears the API key cookie | | /spec | Yes | Returns OpenAPI specification (YAML) | | /stat | Yes | Returns server statistics | | /debug | Yes | Returns debug status | | /debug/on | Yes | Enables debug logging | | /debug/off | Yes | Disables debug logging |

WebSocket API

Connect to ws://localhost:3033/ for real-time pub/sub messaging. Authentication uses the same origin/API key checks as HTTP (pass API key via query param: ws://localhost:3033/?apikey=secret-key-1).

All messages use msgpack binary format with structuredClone: true for efficient serialization of Maps, Sets, Dates, and RegExps.

Message Types

Client → Server:

| Type | Fields | Description | |------|--------|-------------| | subscribe | channel, id? | Subscribe to a channel | | unsubscribe | channel, id? | Unsubscribe from a channel | | publish | channel, data, id? | Publish message to a channel | | ping | id? | Keep-alive ping |

Server → Client:

| Type | Fields | Description | |------|--------|-------------| | connected | - | Connection established | | subscribed | channel, id?, already? | Subscription confirmed | | unsubscribed | channel, id? | Unsubscription confirmed | | published | channel, id? | Publish confirmed | | message | channel, data | Incoming message from subscribed channel | | pong | id? | Ping response | | error | error, id? | Error message |

The optional id field can be used to correlate requests with responses:

// Client sends request with id
ws.send(packr.pack({ type: "subscribe", channel: "events", id: "req-123" }));

// Server responds with same id
// { type: "subscribed", channel: "events", id: "req-123" }

JavaScript Client Example

import { Packr, Unpackr } from "msgpackr";

const packr = new Packr({ structuredClone: true });
const unpackr = new Unpackr({ structuredClone: true });

const ws = new WebSocket("ws://localhost:3033/?apikey=secret-key-1");
ws.binaryType = "arraybuffer";

const pending = new Map();
let reqId = 0;

function send(message) {
  return new Promise((resolve) => {
    const id = String(++reqId);
    pending.set(id, resolve);
    ws.send(packr.pack({ ...message, id }));
  });
}

ws.onmessage = (event) => {
  const msg = unpackr.unpack(new Uint8Array(event.data));
  if (msg.id && pending.has(msg.id)) {
    pending.get(msg.id)(msg);
    pending.delete(msg.id);
  } else if (msg.type === "message") {
    console.log("Channel message:", msg.channel, msg.data);
  }
};

// Usage with async/await
await send({ type: "subscribe", channel: "my-channel" });
await send({ type: "publish", channel: "my-channel", data: { hello: "world" } });
await send({ type: "unsubscribe", channel: "my-channel" });

TypeScript Support

Type definitions are available for both REST and WebSocket APIs:

import type {
  ServiceRequestBody,
  ServiceRequestQuery,
  WsClientMessage,
  WsServerMessage,
  WsChannelMessage,
} from "cry-ebus-proxy/contract.types";

For runtime validation with Zod, use the full contract:

import { contract, schemas } from "cry-ebus-proxy/contract.zod";

API Documentation

OpenAPI 3.1 specification is available at openapi.yaml.

Development

Build

Compile TypeScript contract files:

npm run build

This generates dist/ with compiled JavaScript and type declarations.

Publish

npm run build
npm publish

The prepublishOnly script automatically runs the build before publishing.

Published Files

  • index.mjs - Main server
  • dist/contract.types.js + .d.ts - Pure TypeScript types
  • dist/contract.zod.js + .d.ts - Zod schemas and ts-rest contract
  • openapi.yaml - OpenAPI specification