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

@ferresdb/typescript-sdk

v0.3.0

Published

TypeScript SDK for FerresDB vector database

Readme

FerresDB TypeScript SDK

SDK TypeScript oficial para o FerresDB - banco de dados vetorial de alta performance.

📦 Instalação

pnpm add @ferresdb/typescript-sdk
# ou
npm install @ferresdb/typescript-sdk
# ou
yarn add @ferresdb/typescript-sdk

🐳 Executando FerresDB com Docker

Para usar o SDK contra uma instância real do FerresDB, você pode subir o backend e o frontend com as imagens oficiais.

Baixar as imagens

docker pull ferresdb/ferres-db-core
docker pull ferresdb/ferres-db-frontend

Subir o backend (API)

docker run -d \
  --name ferres-db-core \
  -p 8080:8080 \
  -e PORT=8080 \
  -e STORAGE_PATH=/data \
  -e FERRESDB_API_KEYS=ferres_sk_sua_chave_aqui \
  -v ferres-data:/data \
  ferresdb/ferres-db-core
  • API: http://localhost:8080
  • FERRESDB_API_KEYS: chave(s) de API aceitas pelo servidor (opcional; se omitir, use uma chave criada depois via dashboard ou API de keys, se disponível).
  • O volume ferres-data persiste coleções e dados entre reinícios.

Subir o frontend (dashboard)

Com o backend já em execução:

docker run -d \
  --name ferres-db-frontend \
  -p 3000:80 \
  -e VITE_API_BASE_URL=http://localhost:8080 \
  -e VITE_API_KEY=ferres_sk_sua_chave_aqui \
  ferresdb/ferres-db-frontend
  • Dashboard: http://localhost:3000
  • VITE_API_BASE_URL: URL do backend (ajuste se o backend estiver em outro host/porta).
  • VITE_API_KEY: mesma chave configurada no backend, para o dashboard autenticar.

Se o navegador acessar o frontend em uma máquina diferente do host onde o backend roda, use a URL acessível do backend em VITE_API_BASE_URL (ex.: http://ip-do-servidor:8080).

Usar o SDK apontando para o backend

Com o backend no ar em http://localhost:8080 e a mesma API key:

import { VectorDBClient } from "@ferres-db/typescript-sdk";

const client = new VectorDBClient({
  baseUrl: "http://localhost:8080",
  apiKey: "ferres_sk_sua_chave_aqui",
});
// criar coleções, upsert, search, etc.

🚀 Quick Start

Autenticação

Todas as rotas de dados (coleções, pontos, busca, API keys) exigem autenticação. Passe a API key nas opções do cliente; o SDK envia automaticamente o header Authorization: Bearer <apiKey> em todas as requisições.

const client = new VectorDBClient({
  baseUrl: "http://localhost:8080",
  apiKey: "ferres_sk_...", // obrigatório para rotas protegidas
});

Sem apiKey, o servidor responderá 401 em rotas protegidas.

Exemplo Básico

import { VectorDBClient, DistanceMetric } from "@ferres-db/typescript-sdk";

// Cria uma instância do cliente (apiKey necessário para criar/listar coleções, etc.)
const client = new VectorDBClient({
  baseUrl: "http://localhost:8080",
  apiKey: "ferres_sk_...",
  timeout: 30000,
});

// Cria uma coleção
const collection = await client.createCollection({
  name: "documents",
  dimension: 384, // Dimensão dos vetores (ex: all-MiniLM-L6-v2)
  distance: DistanceMetric.Cosine,
});

console.log("Coleção criada:", collection.name);

// Insere pontos
const points = [
  {
    id: "doc-1",
    vector: [0.1, 0.2, 0.3 /* ... 384 dimensões */],
    metadata: { text: "Primeiro documento", category: "tech" },
  },
  {
    id: "doc-2",
    vector: [0.4, 0.5, 0.6 /* ... 384 dimensões */],
    metadata: { text: "Segundo documento", category: "science" },
  },
];

const result = await client.upsertPoints("documents", points);
console.log(`Inseridos: ${result.upserted}, Falhos: ${result.failed.length}`);

// Busca os 5 pontos mais similares
const queryVector = [0.15, 0.25, 0.35 /* ... 384 dimensões */];
const results = await client.search("documents", {
  vector: queryVector,
  limit: 5,
});

for (const result of results) {
  console.log(`ID: ${result.id}, Score: ${result.score.toFixed(4)}`);
  console.log(`Metadata:`, result.metadata);
}

Exemplo com Embeddings Reais

import { VectorDBClient, DistanceMetric } from "@ferres-db/typescript-sdk";

// Assumindo que você tem uma função que gera embeddings
async function generateEmbedding(text: string): Promise<number[]> {
  // Use sua biblioteca de embeddings (OpenAI, Cohere, etc)
  // Retorna um vetor de 384 dimensões
  return []; // Placeholder
}

async function main() {
  const client = new VectorDBClient({
    baseUrl: "http://localhost:8080",
    apiKey: "ferres_sk_...",
  });

  // Cria a coleção
  await client.createCollection({
    name: "documents",
    dimension: 384,
    distance: DistanceMetric.Cosine,
  });

  // Indexa documentos
  const documents = [
    "Rust é uma linguagem de programação",
    "Python é popular para machine learning",
    "Vector databases são úteis para RAG",
  ];

  const points = [];
  for (let i = 0; i < documents.length; i++) {
    const embedding = await generateEmbedding(documents[i]);
    points.push({
      id: `doc-${i}`,
      vector: embedding,
      metadata: { text: documents[i] },
    });
  }

  await client.upsertPoints("documents", points);

  // Busca semântica
  const queryEmbedding = await generateEmbedding("linguagem de programação");
  const results = await client.search("documents", {
    vector: queryEmbedding,
    limit: 3,
  });

  console.log("Documentos mais similares:");
  for (const result of results) {
    console.log(
      `  - ${result.metadata.text} (similaridade: ${result.score.toFixed(4)})`,
    );
  }
}

main().catch(console.error);

Exemplo com Filtros

import { VectorDBClient } from "@ferres-db/typescript-sdk";

const client = new VectorDBClient({
  baseUrl: "http://localhost:8080",
  apiKey: "ferres_sk_...",
});

// Busca com filtro de metadata
const results = await client.search("documents", {
  vector: queryVector,
  limit: 10,
  filter: {
    category: "tech", // Apenas documentos com category='tech'
  },
});

Exemplo com Retry e Tratamento de Erros

import {
  VectorDBClient,
  CollectionNotFoundError,
  CollectionAlreadyExistsError,
  InvalidDimensionError,
} from "@ferres-db/typescript-sdk";

const client = new VectorDBClient({
  baseUrl: "http://localhost:8080",
  apiKey: "ferres_sk_...",
  maxRetries: 5, // Número máximo de tentativas
  retryDelay: 1000, // Delay inicial em ms (exponential backoff)
});

try {
  await client.createCollection({
    name: "my-collection",
    dimension: 384,
    distance: DistanceMetric.Cosine,
  });
} catch (error) {
  if (error instanceof CollectionAlreadyExistsError) {
    console.log("Coleção já existe");
  } else if (error instanceof InvalidDimensionError) {
    console.error("Dimensão inválida:", error.message);
  } else {
    console.error("Erro desconhecido:", error);
  }
}

📚 API Reference

VectorDBClient

Constructor

new VectorDBClient(options: VectorDBClientOptions)

Opções:

  • baseUrl (string, obrigatório): URL base do servidor FerresDB (ex: 'http://localhost:8080')
  • apiKey (string, opcional): Chave de API para autenticação. Recomendado para todas as rotas de dados; o SDK envia Authorization: Bearer <apiKey>.
  • timeout (number, opcional): Timeout das requisições em ms (padrão: 30000)
  • maxRetries (number, opcional): Número máximo de tentativas em caso de erro (padrão: 3)
  • retryDelay (number, opcional): Delay inicial para retry em ms (padrão: 1000)

Métodos

createCollection(config: CollectionConfig): Promise<Collection>

Cria uma nova coleção.

Parâmetros:

  • config.name (string): Nome da coleção (apenas letras, números, hífens e underscores)
  • config.dimension (number): Dimensão dos vetores (1-4096)
  • config.distance (DistanceMetric): Métrica de distância
  • config.enable_bm25 (boolean, opcional): Habilita índice BM25 para busca híbrida (padrão: false)
  • config.bm25_text_field (string, opcional): Chave em metadata usada como texto para BM25 (padrão: "text")

Retorna: Coleção criada

Erros:

  • CollectionAlreadyExistsError: Se a coleção já existe
  • InvalidDimensionError: Se a dimensão é inválida
  • InvalidPayloadError: Se o payload é inválido
listCollections(): Promise<Collection[]>

Lista todas as coleções.

Retorna: Array de coleções

deleteCollection(name: string): Promise<void>

Remove uma coleção.

Parâmetros:

  • name (string): Nome da coleção

Erros:

  • CollectionNotFoundError: Se a coleção não existe
upsertPoints(collection: string, points: Point[]): Promise<UpsertResult>

Insere ou atualiza pontos em uma coleção. Automaticamente faz batching se houver mais de 1000 pontos.

Parâmetros:

  • collection (string): Nome da coleção
  • points (Point[]): Array de pontos para inserir/atualizar

Retorna: Resultado com número de pontos inseridos e lista de falhas

Erros:

  • CollectionNotFoundError: Se a coleção não existe
  • InvalidDimensionError: Se as dimensões dos vetores não correspondem
deletePoints(collection: string, ids: string[]): Promise<void>

Remove pontos de uma coleção pelos IDs.

Parâmetros:

  • collection (string): Nome da coleção
  • ids (string[]): Array de IDs dos pontos a remover

Erros:

  • CollectionNotFoundError: Se a coleção não existe
  • InvalidPayloadError: Se o array de IDs está vazio
search(collection: string, query: SearchQuery): Promise<SearchResult[]>

Busca pontos similares a um vetor de consulta.

Parâmetros:

  • collection (string): Nome da coleção
  • query.vector (number[]): Vetor de consulta
  • query.limit (number): Número máximo de resultados
  • query.filter (object, opcional): Filtro de metadata (equality matching)

Retorna: Array de resultados ordenados por similaridade

Erros:

  • CollectionNotFoundError: Se a coleção não existe
  • InvalidDimensionError: Se a dimensão do vetor não corresponde
listKeys(): Promise<ApiKeyInfo[]>

Lista as API keys (metadados, sem o valor bruto). Requer API key com perfil Editor/Admin.

Retorna: Array de ApiKeyInfo (id, name, key_prefix, created_at)

createKey(name: string): Promise<CreateKeyResponse>

Cria uma nova API key. O valor bruto (key) é retornado apenas uma vez; armazene-o com segurança.

Parâmetros: name (string): Nome de exibição da chave

Retorna: CreateKeyResponse (id, name, key, key_prefix, created_at)

Erros: InvalidPayloadError se o nome estiver vazio

deleteKey(id: number): Promise<void>

Remove uma API key pelo id (retornado por listKeys ou createKey).

Tipos

DistanceMetric

enum DistanceMetric {
  Cosine = "Cosine",
  DotProduct = "DotProduct",
  Euclidean = "Euclidean",
}

Point

interface Point {
  id: string;
  vector: number[];
  metadata: Record<string, unknown>;
}

Collection

interface Collection {
  name: string;
  dimension: number;
  distance: DistanceMetric;
  created_at?: number;
}

SearchResult

interface SearchResult {
  id: string;
  score: number;
  metadata: Record<string, unknown>;
}

UpsertResult

interface UpsertResult {
  upserted: number;
  failed: Array<{
    id: string;
    reason: string;
  }>;
}

ApiKeyInfo

interface ApiKeyInfo {
  id: number;
  name: string;
  key_prefix: string;
  created_at: number;
}

CreateKeyResponse

interface CreateKeyResponse {
  id: number;
  name: string;
  key: string; // valor bruto — retornado apenas na criação
  key_prefix: string;
  created_at: number;
}

Erros

Todos os erros herdam de VectorDBError:

  • CollectionNotFoundError: Coleção não encontrada (404)
  • CollectionAlreadyExistsError: Coleção já existe (409)
  • InvalidDimensionError: Dimensão inválida (400)
  • InvalidPayloadError: Payload inválido (400)
  • InternalError: Erro interno do servidor (500)
  • ConnectionError: Erro de conexão

🔧 Desenvolvimento

Build

pnpm install
pnpm build

Testes

pnpm test
pnpm test:watch
pnpm test:coverage

Type Checking

pnpm typecheck

📝 Notas

  • Autenticação: use apiKey nas opções para rotas de dados; o SDK envia Authorization: Bearer <apiKey> em todas as requisições.
  • O SDK usa Axios para requisições HTTP com interceptors para tratamento de erros
  • Validação runtime com Zod para garantir tipos corretos
  • Retry automático com exponential backoff para erros de servidor (5xx) e conexão
  • Suporte para ESM e CJS exports
  • Batching automático para operações de upsert com mais de 1000 pontos

gRPC API

O FerresDB também oferece uma API gRPC nativa (porta 50051 por padrão) como alternativa à API REST. Este SDK usa a API REST; para usar gRPC diretamente, gere stubs de cliente a partir do arquivo proto/ferresdb.proto no repositório do servidor (requer --features grpc no build do server).

Para gerar stubs gRPC em TypeScript, use o pacote @grpc/proto-loader ou protoc com o plugin grpc_tools_node_protoc_ts.

📄 Licença

MIT