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

@breadcrumb-sh/core

v0.2.0

Published

Embeddable LLM tracing for TypeScript apps. Your database, your deployment, your UI.

Readme

@breadcrumb-sh/core

Embeddable LLM tracing for TypeScript apps. Your database, your deployment, your UI.

Breadcrumb captures your LLM calls (tokens, model, cost, cached and reasoning tokens), nests spans into traces, and writes them to your own SQLite or Postgres. You mount a fetch-native handler into your app and render the dashboard from @breadcrumb-sh/react, or build your own UI on the headless API here. Built on OpenTelemetry, with native support for the Vercel AI SDK.

Install

npm i @breadcrumb-sh/core pg              # Postgres
npm i @breadcrumb-sh/core better-sqlite3  # SQLite

pg and better-sqlite3 are optional peer dependencies. Install only the driver for the database you use.

Setup

Create one instance and mount its handler:

// lib/breadcrumb.ts
import { breadcrumb } from "@breadcrumb-sh/core";
import { postgres } from "@breadcrumb-sh/core/adapters";

export const bc = breadcrumb({
  database: postgres(process.env.DATABASE_URL!),
  basePath: "/api/breadcrumb",
  authorize: (req) => isAdmin(req),
  pricing: { "gpt-5": { input: 1.25, output: 10, cachedInput: 0.125 } },
});

Mount bc.handler (a (request: Request) => Promise<Response>) at basePath. It serves the JSON API, not a UI — the dashboard is a separate route rendering <BreadcrumbDashboard>. Framework bridges are provided:

// Next.js: app/api/breadcrumb/[...path]/route.ts
import { toNextHandler } from "@breadcrumb-sh/core/next";
export const { GET, POST, DELETE } = toNextHandler(bc);

// Node / Express
import { toNodeHandler } from "@breadcrumb-sh/core/node";
app.use("/api/breadcrumb", toNodeHandler(bc));

// Anything fetch-native (Hono, SvelteKit, …)
app.all("/api/breadcrumb/*", (c) => bc.handler(c.req.raw));

The schema is created automatically in development (migrations: "auto"). For production, generate migration files with the CLI and set migrations: "manual".

Instrumenting calls

Vercel AI SDK. bc.telemetry() returns settings for experimental_telemetry. Calls made inside a bc.trace() callback nest into the same trace automatically:

import { generateText } from "ai";

const { text } = await generateText({
  model: openai("gpt-5"),
  prompt,
  experimental_telemetry: bc.telemetry({ functionId: "generate-answer", userId, sessionId }),
});

functionId names the call and carries the cost attribution, wherever the call sits in the trace; userId and sessionId group runs by user and conversation.

Your own OpenTelemetry setup. If the app already has a tracer provider (@vercel/otel, NodeSDK, Sentry), register bc.spanProcessor on it and model spans reach breadcrumb without threading bc.telemetry() through every call:

registerOTel({ serviceName: "app", spanProcessors: [bc.spanProcessor] });

It stores only spans breadcrumb can read (ai.*, gen_ai.*, breadcrumb.*) unless shouldExport says otherwise, so a shared provider's HTTP and filesystem spans don't land in the trace table.

Manual tracing. bc.trace(name, attrs?, fn), with nested t.span(...):

await bc.trace("support-reply", { userId }, async (t) => {
  t.set({ input: prompt });
  const docs = await t.span("retrieve", { kind: "retrieval" }, async (s) => {
    const result = await search(prompt);
    s.set({ output: result });
    return result;
  });
  const answer = await callModel(prompt, docs);
  t.set({ output: answer, model: "gpt-5", inputTokens, outputTokens });
});

t.set() accepts model, provider, input/output, token counts (inputTokens, outputTokens, cachedInputTokens, cacheWriteTokens, reasoningTokens), an explicit cost, and metadata. A thrown error marks the span failed and rethrows.

On serverless or edge, call await bc.flush() (or waitUntil(bc.flush())) before the response returns so no spans are lost. Set flushMode: "sync" for those runtimes.

Entry points

| Import | Exports | | --- | --- | | @breadcrumb-sh/core | breadcrumb(), the Breadcrumb type, migration helpers (planMigration, renderMigrationSql, EMPTY_SCHEMA_STATE), and the full domain type contract. | | @breadcrumb-sh/core/adapters | sqlite(fileOrDb), postgres(connectionOrClient). | | @breadcrumb-sh/core/client | createBreadcrumbClient(), a typed browser fetch client mirroring bc.api. | | @breadcrumb-sh/core/kit | Headless UI helpers: traceModel, flowRows, selfTime, hotspots, asMessages, preview, and formatters (fmtCost, fmtTokens, fmtMs, …). | | @breadcrumb-sh/core/node | toNodeHandler() for Node/Express. | | @breadcrumb-sh/core/next | toNextHandler() for the Next.js App Router. |

Building your own dashboard

The server, the browser client, and the React hooks share one contract. Query the server directly from a React Server Component with bc.api (listTraces, listSessions, getTrace, stats, costSummary, …), use the typed client in the browser, or reach for @breadcrumb-sh/react hooks. Render with the headless kit:

import { traceModel, selfTime, asMessages, fmtCost } from "@breadcrumb-sh/core/kit";

const model = traceModel(spans);      // rows, scales, hotspots, totals
model.rows;                            // denoised, depth-indexed, ready to map
model.spots;                           // { errorId, slowestId, costliestId }
selfTime(span, children);              // extent minus what the children covered
const chat = asMessages(span.input);   // parse chat-shaped payloads
fmtCost(0.0042);                       // "$0.0042"

traceModel is what the shipped waterfall renders from, so a UI you build from scratch reads exactly the same numbers rather than reimplementing them.

Configuration

Key breadcrumb() options:

| Option | Default | Purpose | | --- | --- | --- | | database | required | A sqlite() or postgres() adapter. | | basePath | /breadcrumb | Where the handler is mounted, and what the dashboard's api prop points at. | | environment | VERCEL_ENV ?? NODE_ENV ?? development | Stamped on every span. | | authorize | none | Guards the query routes. Your dashboard page is yours to guard. | | ingest | none | { apiKey } enables HTTP ingest endpoints. | | pricing | none | USD per 1M tokens, keyed by model, for cost. | | retention | 90d | Per-environment retention windows. | | redact | none | Scrub or trim each span before storage. | | maxPayloadChars | 16384 | Truncate captured input/output (0 disables). | | flushMode | batch | sync for serverless/edge. | | migrations | auto | manual runs no runtime DDL. |

Breadcrumb ships no default prices. Omit pricing and only costs you set yourself are stored. See the full reference at breadcrumb.sh/docs/configuration.

License

MIT