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

dbfull-library

v1.0.8

Published

Client library for dbfull-backend — simplifies communication with the DBFull Gateway API

Downloads

1,156

Readme

dbfull-library

Client library for the DBFull Gateway API (dbfull-backend).
Simplifica la comunicación con el backend sin tener que escribir fetch o axios en cada proyecto.


Instalación

# desde npm (cuando esté publicada)
npm install dbfull-library

# o directamente desde la carpeta local
npm install ../dbfull-library

Configuración requerida

Necesitas:

  1. La URL base del backend, ej. http://localhost:3001
  2. Un API Key admin válido — para operaciones CRUD
  3. (Opcional) Un API Key de solo lectura — se usa automáticamente en llamadas .query() (SELECT raw)

Cómo funcionan los dos keys

El backend maneja un único header X-API-Key, pero detecta automáticamente el tipo de key:

| Key | Tipo detectado | Operaciones permitidas | |-----|---------------|------------------------| | apiKey (admin) | keyType: 'admin' | Todo: CRUD + query | | queryApiKey (solo lectura) | keyType: 'query' | Solo .query() (SELECT) |

La librería selecciona automáticamente cuál enviar según la operación.


Cifrado de Extremo a Extremo (SHP Protocol)

dbfull-library integra el protocolo SHP (Secure Headers & Payload) para proporcionar cifrado E2EE transparente. Cuando está activo, todos los datos se cifran en el cliente usando AES-256-GCM y las llaves se intercambian mediante RSA-OAEP.

Configuración de SHP

Solo necesitas proporcionar la llave pública RSA del servidor en la configuración inicial:

const client = new DBFullClient({
  baseUrl: 'http://localhost:3001',
  apiKey:  'tu-api-key',
  // Configuración de cifrado
  shp: {
    publicKey: '-----BEGIN PUBLIC KEY...\n...', // Llave RSA del backend
    enabled: true,                             // Opcional (defecto: true)
  }
});

¿Cómo funciona?

  • Transparente: No necesitas cambiar tus llamadas a .findAll(), .create(), etc. La librería intercepta las peticiones y cifra el payload automáticamente.
  • Seguridad Zero-Trust: Los datos viajan cifrados por la red y solo pueden ser descifrados por el backend que posee la llave privada correspondiente.
  • Protección de Headers: Además del cuerpo del mensaje, SHP protege los metadatos de la petición.

Parámetros de conexión

La ruta completa sigue este patrón:

{baseUrl}/api/v1/{projectSlug}/{syncGroupId}/{table}

| Parámetro | Descripción | Ejemplo | |-----------|-------------|---------| | projectSlug | Slug del Project registrado en el gateway (auto-generado al crear el proyecto, ej. de nombre "Fibex Telecom" → slug "fibex-telecom") | fibex-telecom | | syncGroupId | ID del grupo de sincronización de la Connection (campo sync_group_id en la tabla connections). Identifica el cluster/par de réplicas que el gateway debe usar. | sae-anzoategui | | table | Nombre de la tabla en la base de datos destino | tm_contratos |

Nota: El syncGroupId no es el nombre de la base de datos. Es el identificador del cluster de conexiones registrado en el gateway bajo ese proyecto. Un proyecto puede tener varios sync groups (uno por cada BD o conjunto de réplicas).

Ejemplo de URL resultante:

http://localhost:3001/api/v1/fibex-telecom/sae-anzoategui/tm_contratos

Uso

Patrón 1 — DBFullClient (recomendado para proyectos con múltiples tablas)

import { DBFullClient } from 'dbfull-library';

const client = new DBFullClient({
  baseUrl:     'http://localhost:3001',
  apiKey:      'tu-api-key-admin',      // CRUD (create, update, delete, findAll...)
  queryApiKey: 'tu-api-key-query',      // opcional — SELECT raw via .query()
});

// client.table(projectSlug, syncGroupId, table)
const contratos = client.table('fibex-telecom', 'sae-anzoategui', 'tm_contratos');

const result  = await contratos.findAll({ page: 1, limit: 20 });  // usa apiKey
const one     = await contratos.findById('abc-123');               // usa apiKey
const created = await contratos.create({ nombre: 'Juan', estado: 'activo' }); // usa apiKey

await contratos.update(created.data.id, { estado: 'inactivo' });  // usa apiKey
await contratos.delete(created.data.id);                           // usa apiKey
await contratos.restore(created.data.id);                          // usa apiKey

Patrón 2 — DBFullDatabase (varias tablas del mismo cluster)

// client.database(projectSlug, syncGroupId)
const db = client.database('fibex-telecom', 'sae-anzoategui');

const contratos = db.table('tm_contratos');
const pagos     = db.table('tm_pagos');

const [cs, ps] = await Promise.all([
  contratos.findAll({ limit: 100 }),
  pagos.findAll({ limit: 100 }),
]);

// Ejecutar query SQL directamente sobre este cluster
const result = await db.query("SELECT COUNT(*) as total FROM tm_contratos");
console.log(result.data, result.count);

Patrón 3 — DBFullTable standalone (ideal para inyección de dependencias / servicios)

import { DBFullTable } from 'dbfull-library';

interface Contrato {
  id: string;
  nombre: string;
  estado: 'activo' | 'inactivo';
  fecha_inicio: string;
}

export const contratosTable = new DBFullTable<Contrato>({
  baseUrl:     process.env.DBFULL_URL!,
  apiKey:      process.env.DBFULL_API_KEY!,
  queryApiKey: process.env.DBFULL_QUERY_API_KEY, // opcional
  org:   'fibex-telecom',     // projectSlug — slug del Project en el gateway
  db:    'sae-anzoategui',   // syncGroupId — ID del cluster/grupo de la Connection
  table: 'tm_contratos',
});

const list = await contratosTable.findAll({ sort: 'nombre:asc', limit: 50 }); // usa apiKey

Filtros por campo — searchParams

El backend detecta automáticamente cualquier query param que coincida con un campo real de la tabla y lo convierte en un filtro WHERE. La librería expone esto como la opción searchParams dentro de findAll.

// Igualdad simple (campo = valor)
const activos = await contratos.findAll({
  searchParams: { estado: 'activo' },
});

// Con operador explícito
const busqueda = await contratos.findAll({
  searchParams: {
    nombre: { op: 'like', val: 'Juan' },   // WHERE nombre LIKE '%Juan%'
    monto:  { op: 'gte',  val: 500  },     // WHERE monto >= 500
  },
});

Operadores disponibles:

| Operador | SQL generado | Ejemplo | |----------|--------------|---------| | eq (default) | campo = valor | { estado: 'activo' } | | ne / neq | campo != valor | { estado: { op: 'ne', val: 'inactivo' } } | | like | campo LIKE '%valor%' | { nombre: { op: 'like', val: 'Juan' } } | | gt | campo > valor | { monto: { op: 'gt', val: 100 } } | | gte | campo >= valor | { monto: { op: 'gte', val: 100 } } | | lt | campo < valor | { monto: { op: 'lt', val: 500 } } | | lte | campo <= valor | { monto: { op: 'lte', val: 500 } } | | in | campo IN (...) | { id: { op: 'in', val: '1,2,3' } } | | nin | campo NOT IN (...) | { id: { op: 'nin', val: '4,5' } } |


Raw SQL — query

Ejecuta una consulta SELECT directamente sobre la base de datos. El backend impone:

  • Solo SELECT — cualquier INSERT, UPDATE, DELETE, DROP, etc. es rechazado con 403.
  • Máximo 5000 filas — el backend aplica un LIMIT 5000 automáticamente si no se especifica.

⚠️ No disponible para conexiones Redis (no soporta SQL crudo).

// Vía DBFullDatabase (recomendado)
const db = client.database('fibex-telecom', 'sae-anzoategui');

const result = await db.query<{ nombre: string; estado: string }>(
  "SELECT nombre, estado FROM tm_contratos WHERE estado = 'activo' LIMIT 100"
);

console.log(result.data);  // { nombre: string; estado: string }[]
console.log(result.count); // número de filas retornadas

// Vía DBFullHttpClient (bajo nivel)
const raw = await client.http.query(
  'fibex-telecom',   // projectSlug
  'sae-anzoategui',  // syncGroupId
  'SELECT COUNT(*) as total FROM tm_contratos'
);

Health Check — verificar conectividad

Métodos disponibles en DBFullClient para verificar el estado del gateway. No requieren API Key.

client.isAlive() — ping simple

La forma más fácil: retorna true si el gateway responde healthy, false si no (incluso ante errores de red).

if (!(await client.isAlive())) {
  console.error('Gateway DBFull no disponible');
  process.exit(1);
}

client.health() — estado general

const { data } = await client.health();

console.log(data.status);    // 'healthy' | 'unhealthy'
console.log(data.uptime);    // segundos desde último reinicio
console.log(data.gatewayDb); // 'connected' | 'disconnected'

client.healthConnections() — estado de conexiones individuales

const { data } = await client.healthConnections();

if (data.overall === 'degraded') {
  console.warn('Algunas conexiones están degradadas:');
  for (const [id, status] of Object.entries(data.connections)) {
    console.warn(`  ${id}: ${status.status}`, status.error ?? '');
  }
}

Métodos de conveniencia

first(options?) — primer registro

Devuelve directamente T | null en lugar de un paginado. Usa sort para controlar cuál es "el primero".

const primero    = await contratos.first();
const masAntiguo = await contratos.first({ sort: 'fecha_inicio:asc' });

last(options?) — último registro

Igual que first pero invierte el sort automáticamente. Si no se pasa sort, usa id:desc.

const ultimo      = await contratos.last();
const masReciente = await contratos.last({ sort: 'fecha_inicio:asc' }); // → desc

count(searchParams?) — total de registros

Hace una petición mínima (limit: 1) y lee pagination.total. Ideal para dashboards y guards.

const total   = await contratos.count();
const activos = await contratos.count({ estado: 'activo' });

exists(id) — verificar existencia

Retorna boolean. Solo captura el 404 — cualquier otro error se propaga normalmente.

if (await contratos.exists('abc-123')) {
  await contratos.update('abc-123', { estado: 'inactivo' });
}

Escritura masiva — bulkCreate vs bulkUpsert

Ambos métodos escriben múltiples registros en una sola petición HTTP, pero se comportan diferente ante registros duplicados:

| | bulkCreate | bulkUpsert | |---|---|---| | Comportamiento | INSERT puro | INSERT ... ON CONFLICT DO UPDATE | | Primera ejecución | ✅ OK | ✅ OK | | Ejecuciones siguientes | ❌ Falla (clave duplicada) | ✅ Actualiza el registro existente | | Idempotente | No | | | Uso recomendado | Inserts únicos garantizados | Sincronizaciones, ETL, reintentos |

// ❌ bulkCreate — solo para inserts que nunca van a repetirse
const res = await contratos.bulkCreate([
  { id_persona: '123', cedula: 'V-12345678', franquicia: 'Caracas' },
]);
// Segunda llamada con el mismo id_persona → Internal Server Error (PK duplicada)

// ✅ bulkUpsert — idempotente, safe para sync periódicos
const res = await contratos.bulkUpsert([
  { id_persona: '123', cedula: 'V-12345678', franquicia: 'Caracas' },
]);
// Segunda llamada → actualiza el registro existente sin error
console.log(`Upserted: ${res.count}`);

Nota: bulkUpsert usa la clave primaria de la tabla detectada por el gateway para resolver el conflicto.


API Reference

DBFullClient methods

| Método | Descripción | Retorna | |--------|-------------|---------| | database(projectSlug, syncGroupId) | Instancia de DBFullDatabase para un cluster concreto | DBFullDatabase | | table<T>(projectSlug, syncGroupId, table) | Instancia de DBFullTable<T> | DBFullTable<T> | | health() | Estado general del gateway | Promise<HealthResponse> | | healthConnections() | Estado de cada conexión registrada | Promise<ConnectionsHealthResponse> | | isAlive() | Ping simple — true si healthy | Promise<boolean> | | http | Cliente HTTP de bajo nivel | DBFullHttpClient |

DBFullTable<T> methods

| Método | Descripción | Retorna | |--------|-------------|---------| | findAll(options?) | Lista paginada de registros | PaginatedResponse<T> | | findById(id) | Un registro por ID | SingleResponse<T> | | search(query, fields?, options?) | Búsqueda full-text | PaginatedResponse<T> | | create(data) | Crea un registro | SingleResponse<T> | | bulkCreate(records) | Inserta múltiples registros (falla con duplicados) | BulkCreateResponse<T> | | bulkUpsert(records) | Inserta o actualiza múltiples registros — idempotente ✅ | BulkUpsertResponse<T> | | update(id, data) | Actualiza parcialmente un registro | SingleResponse<T> | | delete(id) | Soft-delete de un registro | DeleteResponse | | restore(id) | Restaura un registro borrado | RestoreResponse | | first(options?) | Primer registro o null | T \| null | | last(options?) | Último registro o null (sort invertido) | T \| null | | count(searchParams?) | Total de registros | number | | exists(id) | true si existe, false si 404 | boolean |

DBFullDatabase methods

Todos los métodos de DBFullTable están disponibles directamente pasando tableName como primer argumento, más:

| Método | Descripción | Retorna | |--------|-------------|---------| | table<T>(tableName) | Instancia de DBFullTable<T> | DBFullTable<T> | | query<T>(sql) | Ejecuta SELECT SQL crudo | Promise<QueryResponse<T>> | | bulkUpsert<T>(tableName, records) | Inserta o actualiza múltiples registros | Promise<BulkUpsertResponse<T>> |

FindAllOptions

| Propiedad | Tipo | Descripción | |-----------|------|-------------| | page | number | Página (desde 1) | | limit | number | Resultados por página | | sort | string \| SortOption \| SortOption[] | Ordenamiento, ej. "nombre:asc" | | search | string | Término de búsqueda full-text | | includeDeleted | boolean | Incluir registros borrados | | searchParams | SearchParams | Filtros por campo (ver sección anterior) |

Tipos exportados

import type {
  DBFullClientOptions,
  FindAllOptions, SortOption, SearchParams, FieldFilter, FilterOperator,
  PaginatedResponse, SingleResponse, BulkCreateResponse, BulkUpsertResponse,
  DeleteResponse, RestoreResponse, PaginationMeta,
  QueryResponse,
  HealthResponse, ConnectionHealthStatus, ConnectionsHealthResponse,
  DBFullErrorResponse,
} from 'dbfull-library';

Manejo de errores

Todos los errores son instancias de DBFullError:

import { DBFullError } from 'dbfull-library';

try {
  await contratos.findById('no-existe');
} catch (err) {
  if (err instanceof DBFullError) {
    console.error(err.message);    // mensaje del backend
    console.error(err.statusCode); // 404
    console.error(err.errorCode);  // "NOT_FOUND"
  }
}

Build

npm install
npm run build

Los archivos compilados quedan en /dist.