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

@tapizlabs/telemetry

v0.1.1

Published

Framework-agnostic error & event capture SDK for Tapiz products. Captures uncaught errors, batches and ships them to a Tapiz ingest endpoint.

Readme

@tapizlabs/telemetry

Framework-agnostic error & event capture SDK for Tapiz products. The client half of Tapiz's self-hosted error monitoring: it captures uncaught errors in the browser, Node, and Edge runtimes, scrubs PII on the client, groups events by a stable fingerprint, batches them, and ships them to an ingest endpoint.

It does not depend on React, Next, or any UI framework.

Backend: events are received and viewed in Tapiz Sentinel, the self-hosted ingest + dashboard ("Tapiz's Sentry"). The SDK works against any endpoint that accepts the wire contract, but Sentinel is the reference server.

Install

npm install @tapizlabs/telemetry

Requires Node 18+ (uses crypto.randomUUID, fetch). ESM-only.

Quick start

import { init, captureError, captureMessage } from "@tapizlabs/telemetry";

init({
  endpoint: process.env.NEXT_PUBLIC_TELEMETRY_URL!, // https://sentinel.tapiz.site/api/ingest
  project: "boards",                                 // must match the Sentinel project slug
  ingestKey: process.env.NEXT_PUBLIC_TELEMETRY_KEY,  // per-app key from Sentinel
  release: process.env.NEXT_PUBLIC_APP_VERSION,      // optional, for release grouping
  environment: process.env.VERCEL_ENV ?? "production",
  sampleRate: 1,                                     // lower under heavy traffic
});

try {
  riskyThing();
} catch (e) {
  captureError(e, { context: { route: "/board" } });
}

captureMessage("checkout started", { severity: "info" });

init() auto-installs global handlers for the detected runtime (window.onerror + unhandledrejection in the browser; uncaughtException + unhandledRejection in Node). Pass installGlobalHandlers: false to opt out. Calling init() again replaces the client and tears down the previous handlers.

Next.js integration

Four small files wire the SDK into a Next.js (App Router) app. After this, both client and server/edge uncaught errors flow to your endpoint automatically.

1. src/lib/telemetry.ts — single init helper:

import { init } from "@tapizlabs/telemetry";

// No-op when the endpoint is unset (handy for local dev).
export function initTelemetry() {
  const endpoint = process.env.NEXT_PUBLIC_TELEMETRY_URL;
  if (!endpoint) return;
  init({
    endpoint,
    project: "boards",
    ingestKey: process.env.NEXT_PUBLIC_TELEMETRY_KEY,
    release: process.env.NEXT_PUBLIC_APP_VERSION,
    environment: process.env.VERCEL_ENV ?? "development",
  });
}

2. src/instrumentation-client.ts — browser:

import { initTelemetry } from "@/lib/telemetry";
initTelemetry();

3. src/instrumentation.ts — server + edge (register() runs once per runtime):

export async function register() {
  const { initTelemetry } = await import("@/lib/telemetry");
  initTelemetry();
}

4. src/app/global-error.tsx — capture React render crashes, then re-render:

"use client";
import { useEffect } from "react";
import { captureError } from "@tapizlabs/telemetry";

export default function GlobalError({ error }: { error: Error }) {
  useEffect(() => {
    captureError(error);
  }, [error]);
  return (
    <html>
      <body>Something went wrong.</body>
    </html>
  );
}

Environment variables (e.g. Vercel project settings):

NEXT_PUBLIC_TELEMETRY_URL = https://sentinel.tapiz.site/api/ingest
NEXT_PUBLIC_TELEMETRY_KEY = <ingest key from Sentinel>
NEXT_PUBLIC_APP_VERSION   = <optional, for release grouping>

Leaving NEXT_PUBLIC_TELEMETRY_URL unset disables telemetry — convenient locally.

Manual capture

import { captureError, captureMessage, addBreadcrumb } from "@tapizlabs/telemetry";

addBreadcrumb({ category: "ui", message: "opened board" });
try {
  saveBoard();
} catch (e) {
  captureError(e, { context: { boardId } });
}
captureMessage("payment started", { severity: "info" });

Viewing events (Tapiz Sentinel)

The SDK only sends events. To receive, group, and inspect them you run Tapiz Sentinel — a self-hosted Next.js + MySQL ingest service and dashboard. Per consuming app:

  1. Register the project in Sentinel to mint an ingest key:
    PROJECT_SLUG=boards PROJECT_NAME="Tapiz Boards" npm run seed:project
    # → prints TELEMETRY_KEY=...
    The slug must equal the project you pass to init().
  2. Configure the app with NEXT_PUBLIC_TELEMETRY_URL (Sentinel's /api/ingest) and NEXT_PUBLIC_TELEMETRY_KEY (the key from step 1).
  3. Inspect at Sentinel's /admin/issues — grouped issues with stack traces, context, breadcrumbs, first/last seen, and occurrence counts.

Sentinel authenticates the batch via the x-tapiz-key header (sent automatically when ingestKey is set), rate-limits, and deduplicates by (project, fingerprint).

What it does

  • CapturecaptureError(err), captureMessage(msg), plus auto global handlers.
  • Scrub — emails, long digit runs, bearer/JWT-like tokens, secret key=value pairs, and sensitive keys (password, token, email, jmbg, …) are redacted across the entire event (message, stack frames, url, context, breadcrumbs) before anything leaves the process. See scrub.ts.
  • Fingerprint — events group by error type + top in-app stack frames, not by message, so User 4821 not found and User 9 not found are one issue. See fingerprint.ts.
  • Batch — buffered and flushed by size (20) or age (3s), with a sendBeacon flush on page hide so fatal errors aren't lost on unload.
  • Sample / filtersampleRate drops a fraction before work; beforeSend can mutate or drop any event (the privacy scrub still runs after it).

What it deliberately does NOT do

  • No performance tracing, session replay, or release-health.
  • It does not re-queue on a failed flush — an error storm against a down endpoint must not grow memory unbounded. Delivery is best-effort.
  • Source-map remapping happens server-side on ingest; the SDK only tags release so the server can associate maps.

Configuration

init(options) accepts:

| Option | Default | Purpose | | --- | --- | --- | | endpoint (required) | — | Ingest URL, e.g. https://sentinel.tapiz.site/api/ingest. | | project (required) | — | App/project slug; must match the Sentinel project. | | ingestKey | — | Per-app key, sent as the x-tapiz-key header. | | release | — | App version, for release grouping / source-map association. | | environment | "production" | Environment label. | | sampleRate | 1 | 0..1 fraction of events actually sent. | | maxBreadcrumbs | 20 | Max breadcrumbs retained per event. | | beforeSend | — | Last-chance hook to mutate or drop an event (return null to drop). | | installGlobalHandlers | true | Auto-attach runtime error handlers. | | fetchImpl | global fetch | Injectable fetch for non-browser / testing. | | debug | false | Surface internal SDK failures instead of staying silent. |

API

| Export | Purpose | | --- | --- | | init(options) | Create the shared client + install global handlers. | | captureError(err, opts?) | Capture an Error / thrown value. | | captureMessage(msg, opts?) | Capture a message event. | | addBreadcrumb(crumb) | Attach a recent-action trail to later events. | | flush() | Force-send buffered events (await before process exit). | | getClient() | The active TelemetryClient, or null. | | TelemetryClient | Class for isolated/multi-tenant use without the singleton. | | computeFingerprint, parseStack, scrub* | Pure helpers, also used by the ingest service. |

Wire contract

TelemetryEvent / IngestBatch / IngestResponse in types.ts are the contract shared with the ingest service. The SDK POSTs an IngestBatch as JSON to endpoint, with x-tapiz-key set when ingestKey is provided. Any server honoring this contract can act as the backend.

Development

npm install
npm run build
npm run typecheck
npm test

License

MIT © Tapiz Labs