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

@dblm/middleware

v2.1.0

Published

REST middleware for dblm: self-service user registration, natural-language queries, and fassad templates, routed through the dblm broker (mTLS, role-based, horizontally scalable)

Readme

@dblm/middleware

HTTP middleware that exposes dblm over a REST API — register users, run natural-language queries, and run fassad templates — all routed through a dblm broker (dblm server). Flutter apps, dashboards, and other clients query your databases without ever touching a DSN, and the middleware itself holds no database credentials.

How it works

register once:  end user ──► /register ──► broker issues a user + cert bundle

then, with the user's own cert (role-based):
  end user ──► @dblm/middleware (HTTP) ──mTLS──► dblm server (broker fleet) ──► your databases
                                                  └─ shared Postgres: schema · knowledge ·
                                                     modules · history · fassad templates · users

The middleware is a thin HTTP gateway in front of a dblm server broker. It exposes three surfaces — /register (provision a user + client cert), /qd (natural-language queries), and /fassad (stored query templates) — and forwards each to the broker over HTTP/2 + mTLS. Nothing is executed locally; the broker runs everything against the databases. Run the broker with state_backend=postgres and both the middleware and the broker scale horizontally — any instance serves any request.

Auth model. Every request (except /health) sends the service-level X-API-Key plus an X-User-Id identifying the end user. Browsing (GET /fassad, GET /fassad/:name) uses the middleware's service identity; executing (POST /qd, POST /fassad/:name/run) uses the end user's own client cert (from /register), so the broker enforces that user's role/ACL. For /qd, the user id also scopes conversation history.

Prerequisites

  • A running dblm broker (dblm server start) reachable over the network — started with --admin-token (for /register) and, for a shared/scalable fassad + user store, state_backend=postgres.
  • A service bundle for the middleware (dblm server user add middleware-svc …).
  • Fassad templates created on the broker side with dblm fassad create.
  • Node.js 18+ (the middleware does not need the dblm binary on its host).

Install

npm install -g @dblm/middleware
# or run without installing:
npx @dblm/middleware

Configuration

Create a .env file (or set environment variables):

PORT=3000          # HTTP port (default: 3000)
API_KEY=secret     # Required — all requests must send X-API-Key: <value>

# Broker connection (required — every endpoint routes through the broker).
# Preferred: the service bundle produced by `dblm server user add`
# (contains endpoint + CA + client cert/key).
DBLM_BROKER_BUNDLE=/etc/dblm/middleware.bundle.json

# ...or configure the pieces explicitly instead of a bundle:
# DBLM_BROKER_ENDPOINT=https://broker.internal:8443
# DBLM_BROKER_CLIENT_CERT=/etc/dblm/client.crt
# DBLM_BROKER_CLIENT_KEY=/etc/dblm/client.key
# DBLM_BROKER_CA_CERT=/etc/dblm/ca.crt
# DBLM_BROKER_TIMEOUT_MS=300000   # per-request timeout (default: 300000)

# User provisioning (required for /register). Must match the broker's
# `dblm server start --admin-token <value>`.
DBLM_ADMIN_TOKEN=change-me

# Role → grants mapping for /register: inline JSON, or a path via DBLM_ROLES_FILE.
DBLM_ROLES={"analyst":[{"connection":"pg","readOnly":true}],"ops":[{"connection":"pg"}]}
# DBLM_ROLES_FILE=/etc/dblm/roles.json

The middleware authenticates to the broker with its own service bundle (DBLM_BROKER_BUNDLE). The broker must be started with a matching --admin-token for /register to work.

API_KEY is required (service-level auth). Any request without a matching X-API-Key header is rejected with 401.

Every request (except /health) must also send X-User-Id: <id> — the unique id of the end user making the call. Requests missing it are rejected with 400. The middleware authenticates to the broker as a single service identity (the bundle above); the per-request X-User-Id is the end-user identity, carried into the broker as the history session and LLM context.

Start

# using npx
npx @dblm/middleware

# or if installed globally
dblm-middleware

REST API

All endpoints (except /health) require both headers: X-API-Key: <your-key> (service auth) and X-User-Id: <end-user-id> (caller identity).

GET /health

Health check — no auth required.

{ "status": "ok" }

GET /fassad

List all fassad templates (served from the broker's shared template store).

[
  {
    "name": "top-films",
    "mode": "sql",
    "param_count": 1,
    "created_at": "2024-01-15T10:00:00Z"
  }
]

GET /fassad/:name

Get full details for a template, including its parameters. Placeholders in the body use {name} syntax.

{
  "name": "top-films",
  "mode": "sql",
  "connection": "pg",
  "body": "SELECT title FROM film ORDER BY rental_rate DESC LIMIT {limit}",
  "params": [
    { "name": "limit", "kind": "int", "required": true }
  ],
  "created_at": "2024-01-15T10:00:00Z",
  "updated_at": "2024-01-15T10:00:00Z"
}

POST /fassad/:name/run

Execute a template as the calling user, on the broker, against the fassad's target connection. Like /qd, you present your own clientCert + clientKey (from /register) so the broker enforces your role/ACL — a read-only grant rejects a mutating template even with bound parameters. The cert's CommonName must match X-User-Id.

Request: headers X-API-Key, X-User-Id; body:

{
  "params": { "limit": "10" },
  "clientCert": "-----BEGIN CERTIFICATE-----\n...",
  "clientKey": "-----BEGIN EC PRIVATE KEY-----\n..."
}
  • params — values for the template's declared parameters (bound positionally).
  • clientCert + clientKey (required) — from your /register bundle.
  • db / module (optional) — override the fassad's stored target.

Response (SQL fassad): columns and rows.

{
  "columns": ["title"],
  "rows": [["ACE GOLDFINGER"], ["AFFAIR PREJUDICE"]],
  "source": "pg"
}

NLQ-mode fassads return the broker's full NLQ result instead.

POST /register

Self-service provisioning. Creates a user in the dblm broker with a role's grants and issues them a client certificate. The desired user id is the X-User-Id header; the role is in the body. Returns a bundle — keep the client_key secret; you'll send the cert + key on every /qd call.

Request: headers X-API-Key, X-User-Id: [email protected]; body:

{ "role": "analyst", "days": 365 }

Response 201: the user bundle.

{
  "schema": "dblm-bundle/v1",
  "endpoint": "https://broker.internal:8443",
  "user": "[email protected]",
  "ca_cert": "-----BEGIN CERTIFICATE-----\n...",
  "client_cert": "-----BEGIN CERTIFICATE-----\n...",
  "client_key": "-----BEGIN EC PRIVATE KEY-----\n..."
}

Errors: 400 unknown/missing role (response includes knownRoles); 409 the user already exists (re-issuance is an admin/CLI operation).


POST /qd

Run a natural-language query ("qd") through the broker as the calling user. You present your own client_cert + client_key (from /register), so the broker enforces your role/ACL. The cert's CommonName must match X-User-Id.

Request: headers X-API-Key, X-User-Id; body:

{
  "question": "how many films are rated PG-13?",
  "module": "sales",
  "sessionId": "alice-2024-06-30",
  "clientCert": "-----BEGIN CERTIFICATE-----\n...",
  "clientKey": "-----BEGIN EC PRIVATE KEY-----\n..."
}
  • question (required).
  • clientCert + clientKey (required) — from your /register bundle.
  • module or connections (mutually exclusive; optional) — omit both to use every connection your user is granted.
  • sessionId (optional) — name an explicit conversation thread (use different ids for separate threads). Omitting it defaults the session to your user id, so each user has one continuing conversation by default.
  • stateless (optional, true) — opt out of memory entirely for a genuine fire-and-forget query (no prior turns injected, no continuation).
  • raw, noSummary, forceSummary, rule, context — optional.

Session modes: omit sessionId → your default per-user thread (continuity); pass sessionId → a separate named thread; pass stateless: true → one-off, no memory.

Response: the broker's NLQ result (sources, generated SQL, rows, summary).

Use as Express middleware

Instead of running a standalone server, you can mount the fassad router into your existing Express app:

import express from 'express';
import { createFassadRouter, createQdRouter, createRegisterRouter } from '@dblm/middleware/router';

const app = express();
app.use(express.json());

app.use('/register', createRegisterRouter({ apiKey: 'your-secret' }));
app.use('/fassad', createFassadRouter({ apiKey: 'your-secret' }));
app.use('/qd', createQdRouter({ apiKey: 'your-secret' }));

app.listen(3000);

All the same REST endpoints are available under the mount paths. API-key auth and the X-User-Id requirement are applied automatically. All three routers forward to the broker, so they need the broker env vars described under Configuration.

Example: curl

# 1. Register to get a bundle (save client_cert / client_key from the response)
curl -X POST http://localhost:3000/register \
  -H "X-API-Key: secret" -H "X-User-Id: alice" \
  -H "Content-Type: application/json" \
  -d '{"role": "analyst"}'

# 2. List templates (uses the middleware's service identity)
curl -H "X-API-Key: secret" -H "X-User-Id: alice" http://localhost:3000/fassad

# 3. Run a template as alice (clientCert/clientKey from the bundle above)
curl -X POST http://localhost:3000/fassad/top-films/run \
  -H "X-API-Key: secret" -H "X-User-Id: alice" \
  -H "Content-Type: application/json" \
  -d '{"params": {"limit": "10"}, "clientCert": "-----BEGIN CERTIFICATE-----\n...", "clientKey": "-----BEGIN EC PRIVATE KEY-----\n..."}'

Using with the Flutter SDK

This middleware is the backend for the fassad_ui Flutter package. Point FassadClient at the middleware with your apiKey and the end user's X-User-Id.

Note: execution is now role-based through the broker. A client must first POST /register to obtain a bundle, then send that bundle's clientCert + clientKey on each /fassad/:name/run and /qd call. Browsing (GET /fassad) needs only the API key + X-User-Id. (Older SDK versions that called run without a cert target the pre-broker middleware and need updating.)

License

MIT