Skip to main content

@biref/scanner

Scan any database, inspect every relationship in both directions, generate a typed schema, and write Prisma-style fluent queries with fully hydrated nested results.

What it does

@biref/scanner is a headless TypeScript SDK with a four-stage pipeline:

  1. Wire an adapter -- hand the SDK a driver client (pg.Client, mysql2.Connection, or anything structurally compatible)
  2. Scan the data store -- produce a paradigm-neutral DataModel with every entity, field, relationship, constraint, and index
  3. Generate a typed schema file from that scan (biref gen CLI or programmatic API)
  4. Query with a Prisma-style fluent API whose typed proxy knows your schema, executes against your client, and returns hydrated rows with nested includes

Key features

  • Bidirectional relationships -- walks the graph once and attaches both outbound (FK holder) and inbound (FK target) relationships to every entity
  • Zero runtime dependencies -- you bring your own driver; the SDK never imports it
  • Paradigm-neutral domain -- Entity, Field, Reference, Relationship, Constraint, Index work the same for every adapter
  • Full type narrowing -- .select(), .where(), .include() all narrow their types at compile time based on the live schema
  • Codegen CLI -- one command generates a BirefSchema type from a live database

Supported adapters

AdapterDriverNamespace model
PostgrespgSchema (public, auth, etc.)
MySQL / MariaDBmysql2Database

The differentiating feature

Most introspection tools only surface the foreign keys an entity declares. If you scan users you see the columns and the FKs users points at, but not the fact that orders, invoices, and sessions all reference users.id.

@biref/scanner attaches relationships in both directions:

// Who references users?
const incoming = model.inboundRelationshipsOf('public', 'users');
// -> orders, invoices, sessions, api_keys, ...

// The query builder exposes both directions under friendly names.
// .include('orders', ...) on users walks the inbound hop.
// .include('user', ...) on orders walks the outbound hop.