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

databridge-server

v0.1.5

Published

HTTP gateway com governança de SQL para consultas read-only em MySQL. Backend do DataBridge.

Downloads

647

Readme

databridge-server

HTTP gateway com governança de SQL para consultas somente leitura em MySQL. Backend do DataBridge.

Expõe /v1/* em Fastify, guarda organizações e usuários num arquivo SQLite local (via better-sqlite3) e cifra as credenciais MySQL em repouso com AES-256-GCM.

Instalação e uso

# Rodar sem instalar (precisa Node >= 18.17)
npx databridge-server

# Ou instalar globalmente
npm i -g databridge-server
databridge-server

Servidor sobe em http://0.0.0.0:8787. Dados ficam em ./databridge/app.db (organizações, usuários, políticas por org). Os segredos (DATABRIDGE_JWT_SECRET, DATABRIDGE_MYSQL_SECRETS_KEY) não são persistidos no .db — você precisa defini-los no .env do projeto consumidor. Backup: .db + seu .env (sem a chave, as credenciais MySQL cifradas são irrecuperáveis).

Opções

databridge-server [opções]

  --port <n>          Porta HTTP (default 8787, env DATABRIDGE_PORT ou PORT)
  --sqlite <caminho>  Arquivo SQLite (default ./databridge/app.db, env DATABRIDGE_SQLITE_PATH ou SQLITE_PATH)
  -v, --version
  -h, --help

Variáveis de ambiente

Todas as vars do server usam o prefixo DATABRIDGE_ pra não colidir com outras libs no mesmo .env. As vars de config aceitam os nomes curtos como fallback (útil em PaaS que injetam PORT automaticamente).

| Var | Obrigatória? | Default | Uso | |---|---|---|---| | DATABRIDGE_JWT_SECRET | sim | — | Assinatura dos JWT | | DATABRIDGE_MYSQL_SECRETS_KEY | sim | — | Cifragem AES-256-GCM das credenciais MySQL | | DATABRIDGE_PORT (fallback PORT) | não | 8787 | Porta HTTP | | DATABRIDGE_SQLITE_PATH (fallback SQLITE_PATH) | não | ./databridge/app.db | Caminho do arquivo SQLite |

Exemplo de .env no projeto consumidor:

DATABRIDGE_JWT_SECRET=<48 bytes base64url>
DATABRIDGE_MYSQL_SECRETS_KEY=<48 bytes base64url>

Gere chaves fortes com:

node -e "console.log(require('crypto').randomBytes(48).toString('base64url'))"

.gitignore do projeto consumidor

O server cria ./databridge/ no cwd (ou em SQLITE_PATH se definido) e você usa .env para os segredos. Nenhum dos dois deve ir pro git. Adicione ao seu .gitignore:

# DataBridge
databridge/
.env
  • databridge/ — arquivo SQLite (app.db, app.db-wal, app.db-shm) com credenciais MySQL cifradas e usuários bcrypt.
  • .env — onde JWT_SECRET e MYSQL_SECRETS_KEY moram. Se caírem no git, comprometem tudo.

Se você já commitou esses arquivos antes de ignorá-los, remova do índice sem apagar do disco:

git rm --cached -r databridge/ .env
git commit -m "stop tracking databridge state"

Para verificar que o ignore pegou:

git check-ignore -v databridge/app.db
# → .gitignore:N:databridge/  databridge/app.db

Primeiro uso (admin)

Criar a organização + admin (testa a conexão MySQL antes de persistir):

curl -X POST http://localhost:8787/v1/orgs \
  -H 'Content-Type: application/json' \
  -d '{
    "slug": "minha-empresa",
    "name": "Minha Empresa",
    "mysql": {
      "host": "replica.mysql.minha-empresa.com",
      "port": 3306,
      "database": "producao",
      "username": "readonly",
      "password": "..."
    },
    "admin": { "login": "admin", "password": "segredo123" }
  }'

Retorna { token, login, displayName, isAdmin }. Use o token como Authorization: Bearer <token> nas demais rotas.

Rotas (prefixo /v1)

| Método | Rota | Auth | Uso | |---|---|---|---| | POST | /orgs | — | Cria org + admin | | POST | /auth/login | — | { orgSlug, login, password } → JWT | | GET | /schema | Bearer | information_schema filtrado pela política | | POST | /query | Bearer | { sql } (só SELECT) | | GET/PUT | /policy | Bearer admin | Lê/sobrescreve política da org | | GET/POST/DELETE | /trusted-users[/:id] | Bearer admin | CRUD de trusted users |

Storage pluggable (avançado)

Por padrão o server usa SQLite local — bom pra dev e deploys single-node com disco persistente. Para Cloud SQL, Postgres gerenciado, DynamoDB, ou qualquer backend próprio, você importa buildApp como biblioteca e injeta uma implementação da interface AppStorage:

import {
  buildApp,
  createSqliteStorage,
  type AppStorage,
  type AppDeps,
} from "databridge-server";
// segredos, política e criptografia continuam vindo dos helpers padrão:
import { loadEmbeddedPolicy, createMysqlFieldCrypto } from "databridge-server";
import Fastify from "fastify";

const storage: AppStorage = createSqliteStorage(); // ou a sua implementação

const deps: AppDeps = {
  storage,
  jwtSecret: process.env.DATABRIDGE_JWT_SECRET!,
  templatePolicy: loadEmbeddedPolicy(),
  mysqlFieldCrypto: createMysqlFieldCrypto(process.env.DATABRIDGE_MYSQL_SECRETS_KEY!),
};
const app = await buildApp(deps);
await app.listen({ port: 8787, host: "0.0.0.0" });

A interface está em server-node/src/storage/types.ts. Métodos:

  • orgs: createOrg, getOrgById, getOrgBySlug, updateOrgPolicyJson
  • users: createUser, getUserByLogin, getAdminLogin, listTrustedUsers, deleteTrustedUser
  • lifecycle: close

Obrigações da implementação:

  • Retornar null em lookups não encontrados (nunca lançar).
  • Lançar StorageUniqueError(field) em createOrg/createUser quando houver violação de unicidade (slug duplicado, login já existente). O server converte em HTTP 409.
  • Ser seguro para chamadas concorrentes (o Fastify processa rotas em paralelo).

Esboço de Postgres:

import { Pool } from "pg";
import { StorageUniqueError, type AppStorage } from "databridge-server";

export function createPostgresStorage(connString: string): AppStorage {
  const pool = new Pool({ connectionString: connString });
  return {
    async createOrg(input) {
      try {
        await pool.query(
          `INSERT INTO organizations (id, slug, name, mysql_host, mysql_port, mysql_database, mysql_username, mysql_password, policy_json, created_at)
           VALUES ($1,$2,$3,$4,$5,$6,$7,$8,NULL,$9)`,
          [input.id, input.slug, input.name, input.mysql.host, input.mysql.port, input.mysql.database, input.mysql.usernameCiphertext, input.mysql.passwordCiphertext, input.createdAt],
        );
      } catch (e: any) {
        if (e?.code === "23505") throw new StorageUniqueError("slug");
        throw e;
      }
    },
    // ... demais métodos análogos ao createSqliteStorage
    async close() { await pool.end(); },
  };
}

O schema SQL equivalente às migrations do SQLite está em server-node/src/sqlite.ts (adapte os tipos para o dialeto alvo — TEXTVARCHAR/TEXT, etc.).

Segurança

  • Guard de SQL rejeita qualquer coisa que não seja SELECT (paridade com databridge-core em Rust).
  • Credenciais MySQL são cifradas com DATABRIDGE_MYSQL_SECRETS_KEY antes de irem pro SQLite. A chave nunca é persistida — fica só no .env do projeto consumidor.
  • Senhas de usuários do app são bcrypt (rounds=12).
  • DATABRIDGE_MYSQL_SECRETS_KEY e DATABRIDGE_JWT_SECRET são chaves independentes — rotacione uma sem afetar a outra. Rotacionar DATABRIDGE_MYSQL_SECRETS_KEY invalida credenciais MySQL já cifradas.

Licença

ISC