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

orbitchat

v3.6.5

Published

A standalone chat application for ORBIT that can be installed as an npm package and run as a CLI tool. All API communication is routed through a built-in Express proxy that maps adapter names to backend API keys, so **no secrets ever reach the browser**.

Readme

ORBIT Chat App

A standalone chat application for ORBIT that can be installed as an npm package and run as a CLI tool. All API communication is routed through a built-in Express proxy that maps adapter names to backend API keys, so no secrets ever reach the browser. Uses the open-source @schmitech/markdown-renderer for rich content display including math and charts.

Installation

As an npm Package (CLI Tool)

Install globally:

npm install -g orbitchat

Or install locally:

npm install orbitchat

Installed CLI commands:

  • orbitchat — starts the ORBIT Chat server directly
  • orbitchat-daemon — shell wrapper with --start/--stop/--restart/--force-restart/--status

Quick Start

  1. Define your adapter secrets via the ORBIT_ADAPTER_KEYS or VITE_ADAPTER_KEYS environment variable:

    # Mapping of Adapter ID -> API Key
    export ORBIT_ADAPTER_KEYS='{"simple-chat":"my-secret-key"}'
  2. (Optional) Configure adapter URLs and metadata in orbitchat.yaml:

    adapters:
      - id: "simple-chat"
        name: "Simple Chat"
        apiUrl: "http://localhost:3000"
        description: "Default conversational agent."
  3. Run the CLI:

    orbitchat --config ./orbitchat.yaml --port 5173
  4. Open http://localhost:5173 — select an agent and start chatting.

Architecture

Browser  ──X-Adapter-Name──▶  Express proxy  ──X-API-Key──▶  ORBIT backend
                              (bin/orbitchat.js)

The frontend never handles API keys. Instead:

  • The browser sends an X-Adapter-Name header with every API request.
  • The Express proxy looks up the adapter, injects the real X-API-Key, and forwards the request to the configured backend URL.
  • GET /api/adapters returns non-secret adapter metadata (name, description, notes, model) — never keys or backend URLs.

CLI Options

orbitchat [options]

Options:
  --port PORT        Server port (default: 5173)
  --host HOST        Server host (default: localhost)
  --open             Open browser automatically
  --config PATH      Path to orbitchat.yaml (default: ./orbitchat.yaml)
  --api-only         Run API proxy only (no UI serving)
  --cors-origin URL  Allowed CORS origin in api-only mode (default: *)
  --help, -h         Show help message
  --version, -v      Show version number

Examples

# Start with a custom config file
orbitchat --config /path/to/orbitchat.yaml

# Start with adapter keys defined inline
ORBIT_ADAPTER_KEYS='{"Chat":"mykey"}' orbitchat

# API proxy only — no UI, no build required
orbitchat --api-only --port 5174

# API proxy with restricted CORS origin
orbitchat --api-only --port 5174 --cors-origin http://localhost:3001

API-Only Mode

Use --api-only to run the Express proxy without serving the built-in chat UI. This is useful when you are building your own frontend and only need the proxy layer to keep API keys off the browser.

orbitchat --api-only --port 5174

In this mode:

  • No dist/ directory or npm run build is required.
  • CORS headers are added automatically (default Access-Control-Allow-Origin: *). Use --cors-origin to restrict to a specific origin.
  • All /api/* proxy routes and GET /api/adapters work exactly the same as in full mode.

API contract for custom UIs

Your frontend needs to do two things:

  1. Discover adaptersGET /api/adapters returns:

    {
      "adapters": [
        { "name": "Simple Chat", "description": "...", "notes": "...", "model": "gpt-4o-mini" }
      ]
    }
  2. Send requests with X-Adapter-Name — every call to /api/* must include the header:

    X-Adapter-Name: Simple Chat

    The proxy resolves the adapter, injects the real X-API-Key, and forwards the request to the backend URL configured for that adapter.

Endpoint reference

| Method | Path | Headers | Description | |--------|------|---------|-------------| | GET | /api/adapters | — | List available adapter metadata (name, description, notes, model) | | POST | /api/v1/chat | X-Adapter-Name, X-Session-ID | Send a chat message (SSE streaming response) | | POST | /api/files/upload | X-Adapter-Name | Upload a file (multipart/form-data) | | GET | /api/files | X-Adapter-Name | List uploaded files | | GET | /api/files/:id | X-Adapter-Name | Get file info | | DELETE | /api/files/:id | X-Adapter-Name | Delete a file | | GET | /api/v1/autocomplete?q=...&limit=5 | X-Adapter-Name | Autocomplete suggestions |

Configuring Adapters

Configuration is split between metadata/URLs (in orbitchat.yaml) and secrets (in environment variables).

1. Metadata in orbitchat.yaml

Define your adapters list in the YAML file:

adapters:
  - id: "simple-chat"
    name: "Simple Chat"
    apiUrl: "http://localhost:3000"
    description: "Basic chat interface using the default conversational agent."
  - id: "document-qa"
    name: "Document QA"
    apiUrl: "http://localhost:3000"
    description: "Chat with uploaded documents."
    notes: "Supports PDF, DOCX, and plain text uploads."

| Field | Description | |-------|-------------| | id | Required. Unique identifier used to match the API key in .env | | name | Display name shown in the agent selector | | apiUrl | Backend URL (defaults to api.url, then http://localhost:3000) | | description | Short summary shown in dropdowns | | notes | Markdown content shown in the chat empty state |

2. Secrets in .env

Provide the API keys via ORBIT_ADAPTER_KEYS (or VITE_ADAPTER_KEYS) as a JSON object keyed by adapter id:

VITE_ADAPTER_KEYS='{
  "simple-chat": "secret-key-1",
  "document-qa": "secret-key-2"
}'

The system deep-merges these sources at runtime.

Configuration

Runtime Config File

Runtime settings are loaded from orbitchat.yaml (see orbitchat.yaml.example). The configuration uses a nested structure:

application:
  name: "ORBIT Chat"
api:
  url: "http://localhost:3000"
features:
  enableUpload: true
server:
  trustProxy: false

Header logos (header.logoUrl, header.logoUrlLight, header.logoUrlDark) support:

  • Remote URLs, for example https://example.com/logo.png
  • Local file paths (absolute or relative to orbitchat.yaml), for example ./public/logo.png

Theme-aware logo selection order:

  • Light theme: header.logoUrlLight -> header.logoUrl -> header.logoUrlDark
  • Dark theme: header.logoUrlDark -> header.logoUrl -> header.logoUrlLight

Default logo fallback behavior:

  • If header.logoUrlLight is empty or whitespace, ORBIT Chat uses /orbit-logo-light.png.
  • If header.logoUrlDark is empty or whitespace, ORBIT Chat uses /orbit-logo-dark.png.
  • These paths are resolved from the app root (Vite public/ directory), alongside favicon.svg.
  • Example:
    header:
      logoUrlLight: ""
      logoUrlDark: ""
    With this config, light/dark themes automatically use the default files from public/.

Server/reverse proxy setting:

  • server.trustProxy maps directly to Express app.set('trust proxy', value).
  • Default is false.
  • Set server.trustProxy: 1 when ORBIT Chat is behind a single trusted reverse proxy.

Environment Variables

Adapter secrets are provided via:

  • ORBIT_ADAPTER_KEYS (Preferred)
  • VITE_ADAPTER_KEYS

Auth secrets are read from:

  • VITE_AUTH_DOMAIN
  • VITE_AUTH_CLIENT_ID
  • VITE_AUTH_AUDIENCE

The CLI loads .env and .env.local from the current working directory on startup.

Development

Local Development Setup

Clone the repository and install dependencies:

npm install
npm run dev

Building for Production

npm run build

The output is written to dist/. Serve it with:

orbitchat --port 8080

public/ assets are copied into dist/ during build. Because the npm package publishes dist/, default logo assets such as orbit-logo-light.png and orbit-logo-dark.png are included in published builds.

Troubleshooting

No Adapters Available

If the agent selector shows no adapters:

  1. Ensure VITE_ADAPTER_KEYS is set and contains valid JSON.
  2. Verify that the adapter id in orbitchat.yaml exactly matches the key used in VITE_ADAPTER_KEYS.
  3. Check the CLI startup logs for "Available Adapters: ...".

Stale Configuration

If you've updated orbitchat.yaml but don't see changes:

  1. The CLI watches the YAML file and should restart automatically.
  2. Clear browser site data/localStorage for the app origin to ensure no stale session state is being used.

ERR_ERL_UNEXPECTED_X_FORWARDED_FOR (rate limit + reverse proxy)

If you see a log like:

ValidationError: The 'X-Forwarded-For' header is set but the Express 'trust proxy' setting is false (default).
code: 'ERR_ERL_UNEXPECTED_X_FORWARDED_FOR'

this usually means ORBIT Chat is running behind a reverse proxy (Nginx, ingress controller, load balancer, Cloudflare, etc.) that adds X-Forwarded-For, but Express is still using the default trust proxy = false.

Why this matters:

  1. The app still runs (this is a validation warning), but guest rate limiting may identify client IPs incorrectly.
  2. In the worst case, many users can be rate-limited as if they were a single client.

How to prevent it:

  1. If you are behind a trusted reverse proxy, set this in orbitchat.yaml:
    server:
      trustProxy: 1
  2. If you are not intentionally behind a proxy, remove unexpected X-Forwarded-For injection in your network path.
  3. As a temporary workaround, disable guest rate limiting in orbitchat.yaml:
    guestLimits:
      rateLimit:
        enabled: false

Reference: https://express-rate-limit.github.io/ERR_ERL_UNEXPECTED_X_FORWARDED_FOR/

Security

  • The browser never sees real API keys. The Express proxy maps adapter names to keys server-side.
  • GET /api/adapters only exposes non-secret metadata (name, description, notes, model) — never keys or backend URLs.
  • Keep VITE_ADAPTER_KEYS out of source control.
  • Run the proxy behind HTTPS in production.