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

@futurity/atlas-connector

v0.3.0

Published

Build a Futurity Atlas external connector: protocol wire, server runtime, SQL engine.

Readme

@futurity/atlas-connector

Build a Futurity Atlas external connector: a standalone HTTP service that answers Atlas's queries against your database or API. The SDK owns the wire protocol (Zod schemas), the server runtime (auth, timeouts, NDJSON streaming, error envelope), and a full SQL query engine; you write only the part that talks to your source.

bun create atlas-connector my-connector

The scaffolder asks what backs your source and stamps the matching starter:

  • sql: a SQL database. Extend SqlConnector: declare a catalog, open a pool, write one run(pool, sql, params). Everything else is derived.
  • rest: a REST/ERP API (Anaplan, Workday, Dynamics, ...). Extend AtlasConnector: four methods to write, the rest derived, each marked YOUR CODE HERE with its contract.

Scriptable: bun create atlas-connector my-crm --kind sql --port 4100.

Tenancy

You host one connector; every client connects to it with their own credentials. The capability doc declares a credentialSchema, the exact inputs Atlas shows the person connecting, and each authenticated request carries those values back as credentials, which is the only place your code reads them from. A field is text, password (masked) or textarea (a multi-line box for a pasted key), and required: false marks one a tenant may leave blank, which then arrives with the key absent. Give every field a placeholder and a help string: help is short markdown rendered between the label and the input, and it should name the exact page in the vendor's console the value is copied from and link the vendor's doc for it. Nothing upstream is configured in the connector's environment, so one deployment can serve any number of tenants and an added tenant is a form someone fills in. Connectors must not persist raw credentials; when an upstream requires session reuse, cache only short-lived tokens under a one-way credential digest, as the ESB Core example does.

Quickstart: a SQL database

Three files, the whole connector:

// src/catalog.ts: declare your tables
import { col, defineCatalog } from "@futurity/atlas-connector/sql";

export const catalog = defineCatalog([
  {
    name: "companies",
    description: "Accounts.",
    primaryKey: ["id"],
    foreignKeys: [],
    columns: [
      col("id", "int", "number", { unique: true }),
      col("name", "text", "string"),
      col("created_at", "datetime", "datetime"),
    ],
  },
]);
// src/connector.ts: a pool per tenant, and one way to run a statement
import { SQL } from "bun";
import type { Credentials } from "@futurity/atlas-connector";
import { postgres, SqlConnector, type Row } from "@futurity/atlas-connector/sql";
import { catalog } from "./catalog";

export class MyConnector extends SqlConnector<SQL> {
  readonly slug = "my-crm";
  readonly catalog = catalog;
  readonly schema = "public";
  override readonly flavor = postgres();

  protected override async openPool(credentials: Credentials): Promise<SQL> {
    return new SQL(credentials.databaseUrl);
  }

  protected override async closePool(pool: SQL): Promise<void> {
    await pool.close();
  }

  async run(pool: SQL, sql: string, params: unknown[]): Promise<Row[]> {
    return (await pool.unsafe(sql, params)) as Row[];
  }
}
// src/index.ts: boot it
import { serve } from "@futurity/atlas-connector";
import { MyConnector } from "./connector";

serve(new MyConnector(), { token: process.env.ATLAS_CONNECTOR_TOKEN ?? "", port: 4100 });

There is nothing to obtain for ATLAS_CONNECTOR_TOKEN: you mint it (openssl rand -hex 24), set it on the connector, and paste the same value into the Token field when registering the source in Atlas.

SqlConnector implements every protocol method over run(): check (SELECT 1), discovery, streaming queries, size, count, cardinality, linkHitRate, and GROUP BY pushdown. Pools are cached per credential set, and an evicted pool closes only once the last request holding it is done. The capability doc, including the default databaseUrl credential, is derived from the catalog and flavor, so the connector can never advertise an operator its builders won't render.

Quickstart: a REST / ERP API

Extend AtlasConnector. Three methods carry everything the source alone knows:

| method | you return | | ---------------- | ---------------------------------------------------------------------------------- | | check(req) | nothing; throw if req.credentials are wrong, and the tenant reads it | | query(req) | batches of rows (≤5000 each): push what the API filters, applyFilters() the rest | | discovery(req) | the API's entities as { tables, warnings? } |

size(req) is the fourth, and it is strongly recommended: the table's total from the upstream's own metadata in one request (totalResults, result.count, a Lark total, a recordCount), exact: false for an estimate, null for a table that has no total. Leave it out and Atlas has to pull the table to its cap plus one row to learn how big it is.

count, aggregate, cardinality and linkHitRate are optional overrides with no default bodies. A method you do not write is a route serve() never mounts and an entry the capability doc never lists, so Atlas measures the fact itself instead of trusting a number the connector guessed. Write one only where the upstream does the math: a count endpoint, a GROUP BY, a COUNT DISTINCT, a LEFT JOIN.

serve() owns bearer auth, body parsing, timeouts, heartbeats, and the error envelope. The kit meets you halfway: applyFilters evaluates residual filters in memory with exactly the SQL engine's semantics, assertKnownFields turns a filter you cannot answer into a 422 (rows that skipped a filter read as rows that matched it), and cardinalityFromValues / columnTally / linkFromValues turn fetched values into measurement answers.

A REST connector declares one Pushdown map (the same object query() reads to build the upstream request), and defineCapability emits operators, sort, offset and join from it, so an advertised op is always an op you push. The rest of the doc is the vendor block no code can introspect: limits (pageSizeMax, rowsPerTableMax, concurrency, offsetMax), keysEnforced, dateBucket, credentialSchema, slug, dialect. endpoints is never typed by an author: serve() fills it from the methods above at boot. See examples/lark for a metadata-led REST source and examples/esb for a complete fixed-catalog ERP connector with strict envelopes, partial discovery, paging, sorting, and process-local token coordination.

Declare metadata once, then use it for discovery, field lookup, and residual filtering. Static APIs and fields fetched at runtime use the same functions:

import { defineCatalog, discoverFields, field, fieldTypes } from "@futurity/atlas-connector";

const companies = {
  name: "companies",
  columns: [
    field("id", "number", { nullable: false, unique: true }),
    field("code", "string", { nullable: true }),
  ],
};
const catalog = defineCatalog([companies]);
const fields = discoverFields(companies.columns);
const types = fieldTypes(companies.columns);

field defaults to non-nullable, non-unique, and an empty description. Declare uniqueness only when the source guarantees it; sampled distinct values are not a constraint. Catalogs preserve provider-specific table and column properties. Lark derives fields from tenant metadata; SQL adds storage spelling with col. Bind filters against your discovered types, never against the fieldTypes a request carries.

Sorting requires collecting every matching row before offset and limit; it does not make a paginated upstream globally sorted. Keep nulls last in both directions. Normalize legitimately missing cells at ingestion, and never mask a missing required field as null.

The protocol

A connector serves one unauthenticated GET, /.well-known/futurity/atlas.json (the capability doc), plus three bearer-guarded POST endpoints every connector has (/check, /discovery, /query) and five served only where the method behind them is overridden (/size, /count, /aggregate, /cardinality, /linkHitRate). /query answers NDJSON and nothing else; there is no drained form. Its first line is always {"served":{"filters":bool,"sort":bool,"window":bool}}, what the upstream applied for that one query, and the rows follow. Every POST body carries credentials and timeoutMs. The Zod schemas in src/wire/schemas.ts (requests, answers, stream lines) and src/wire/atlas-json.ts (the capability doc) are the wire contract, executably. examples/ holds four complete connectors across the SQL and REST/ERP paths. Before registering a connector with Atlas, grade it with the atlas-conform conformance runner.

API reference

@futurity/atlas-connector

Vocabulary (ATLAS_TYPES/AtlasType, AtlasValue, OPS/Op, Filter, UserSort, JoinField, DATE_GRAINS/DateGrain, SourceRow): the shared protocol types. SourceRow is the wire-legal row a connector returns: Record<string, string | number | boolean | null>. AtlasNumeric, AtlasBoolean, AtlasDate, and AtlasDatetime validate a scalar once its catalog type is known.

Wire schemas: every request (CheckRequest, DiscoveryRequest, NativeQueryRequest, NativeQueryStreamRequest, CountRequest, SizeRequest, AggregateRequest, CardinalityRequest, LinkHitRateRequest), Credentials, every answer (CountAnswer, SizeAnswer, CardinalityAnswer, DiscoveryAnswer, ...), StreamLine, WireError, and the result types (DiscoveredTable, EntitySize, TableCardinality, ColumnCardinality, LinkHitRate, ...). CONNECTOR_LIMITS holds the protocol's size and heartbeat bounds. AtlasJson, CapabilityDoc, SourceCapabilitiesWire, ConnectorLimitsWire, CONNECTOR_ENDPOINTS, CredentialField, ATLAS_JSON_PATH describe the capability doc.

AtlasConnector: the class to inherit. Five members are abstract (slug, capabilities, check, query, discovery) and five are optional overrides with no default body: size (strongly recommended), count, aggregate, cardinality, linkHitRate. The ones you write become the doc's endpoints and the routes serve() mounts.

The served plan: query() yields row batches, and may yield one { served } chunk before the first batch (QueryChunk, Served). It is the connector's account of that one request: filters true means every and/or predicate was applied upstream with Atlas's own semantics, so the rows are the matching set and not a superset; sort true means they arrive in the requested order; window true means offset/limit were applied and no row exists past them. Yield nothing and Atlas reads SERVED_NOTHING, a superset it filters, sorts and windows itself. A claim is a promise: never window rows whose filter or order you left to the host, and the serve layer clamps a window claimed over an unserved filter or order back to false. Atlas answers a fully served query straight off the wire: a top-N becomes one request instead of a whole-entity pull.

Catalog: field(name, type, { nullable?, unique?, description? }), defineCatalog(tables) with getTable / getColumn, fieldTypes(fields), and discoverFields(fields). Field derives from the discovery wire contract and Catalog<T> retains table extensions; a duplicate table or field name throws at construction, never at request time. Samples and statistics are the connector's to add: spread a discoverFields result to set samples or sourceColumn.

serve(connector, { token, port?, hostname? }): boots the HTTP server; returns { app, url, stop }. Boot-fails on a token under 32 chars or an invalid capability doc. createApp(connector, { token }) returns the Elysia app for tests and embedding.

Errors and http: ConnectorError plus the constructors badRequest, unauthorized, unknownEntity, unsupported, timeout; parseBody (400 envelope, never 422), withTimeout (408 on expiry), bearerGuard (timing-safe compare), ndjsonStream (heartbeats, {served}/{rows}/{ping}/ {error}/{end:1} framing).

Kit: applyFilters(rows, { and, or? }, fieldTypes?) evaluates filters in memory with the SQL engine's exact semantics (nin keeps nulls, empty in matches nothing, ...), over byteOrderCompare and decimalCompare, which are exported for a connector that orders rows itself. assertKnownFields(req, fields) rejects unknown filter, projection, and sort fields with 422 before fetching rows and returns their validated Set<string> for upstream field selection. windowRows(batches, req) applies offset and limit to already-filtered batches, emits at most 5000 rows per batch, and closes the source iterator on early exit. Sort before windowing when requested; project afterward. Only sorting needs whole-result buffering, and pagination and deadline checks stay with the connector. defineCapability(...) emits the capability doc from a Pushdown map plus the vendor block; pushdownCapabilities is the emitter alone and pushedOps(map, entity, field?) is what query() asks before it builds an upstream request, so the doc and the request cannot drift. cardinalityFromValues and linkFromValues compute measurement answers from fetched values; columnTally is the streaming twin of the first, folding batches into a group map instead of holding the column. ORPHAN_SAMPLE_CAP bounds the orphan spellings a link answer names.

@futurity/atlas-connector/sql

SqlConnector<Pool>: implements every protocol method from openPool(credentials) / run(pool, sql, params) / closePool(pool) plus a catalog, schema, and flavor. Pools are cached per credential set (LRU, 16 tenants) and an evicted pool closes only after the last request holding it returns. Optional streamBatches override for drivers with real cursors; keysEnforced = true only when every declared key is a real db constraint. capabilities() derives the doc; override credentialSchema when the driver takes separate parts instead of one url, keeping a placeholder and a help string on each part.

Catalog: defineCatalog(tables), col(name, wire, type, opts?), and the Catalog/Table/Column/WireKind types. defineCatalog is re-exported from the core catalog, and Column extends core Field with SQL storage metadata.

SqlFlavor: the dialect seam (placeholders, ident quoting, date rendering, collation pins). It ships postgres(); other dialects land here.

Builders: buildSelect, buildCount, buildAggregate, buildWhere, renderRows, renderAggregateRows, projectExpression, renderValue, Binder, plus the measurement/discovery SQL (size, cardinality, linkHitRate) and sqlCapability. Protocol law (null ordering, empty-in, LIKE escaping, 2^53 fencing, decline-vs-wrong-answer for aggregates) is hardcoded; only spellings go through the flavor.

License

MIT