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

@syncropel/error-reporter

v0.1.2

Published

Browser error capture for Syncropel apps. Pluggable transports (Mock / Console / HTTP), privacy-aware sanitization, per-session rate limiting, fingerprint deduplication.

Downloads

299

Readme

@syncropel/error-reporter

Browser error capture for Syncropel apps. Reports errors to a pluggable transport (Mock for tests, Console for dev, HTTP for production) with privacy-aware sanitization, per-session rate limiting, and fingerprint deduplication built in.

Why

Most error trackers add a third-party SaaS dependency, ship your data to vendor servers, and force you to learn one more dashboard. This reporter ships errors as structured records to whatever endpoint you choose — your own backend, a debug log, or an in-memory buffer for tests. Same query surface as the rest of your app data; no separate vendor.

Install

npm install @syncropel/error-reporter
# Peer dependencies:
npm install react @syncropel/config

| Peer | Version | Why | |---|---|---| | react | >=18 | Used internally for the optional React error boundary helpers | | @syncropel/config | ^0.10.0 | Provides the canonical schemas the report bodies pair with |

Quick start

import { Reporter, ConsoleTransport } from '@syncropel/error-reporter';

const reporter = new Reporter({
  transport: new ConsoleTransport(),
  release: process.env.NEXT_PUBLIC_RELEASE_VERSION ?? 'dev',
  enabled: () => process.env.NODE_ENV !== 'test',
  maxSessionEmits: 100,         // cap per session (default 100)
  fingerprintCooldownMs: 60_000, // dedupe window (default 60s)
});

// Wire to window error events
window.addEventListener('error', (event) => {
  reporter.captureWindowError(event);
});

window.addEventListener('unhandledrejection', (event) => {
  reporter.captureUnhandledRejection(event);
});

// Or call directly from your error boundary / route error / fetch-failure path
reporter.report(error, {
  source: 'react-boundary',
  route: '/dashboard',
  component: 'WorkspaceRenderer',
});

Transports

Three reference implementations ship in-tree. All implement the same Transport interface:

interface Transport {
  send(body: ErrorBody): Promise<void>;
}

MockTransport — in-memory buffer. Use in tests. Records are inspectable via transport.records.

ConsoleTransportconsole.error() with formatted output. Use in dev.

HttpTransportPOST to a configured URL with the report body as JSON. Use in production. Constructor accepts { url, headers?, beforeSend? }.

import { HttpTransport } from '@syncropel/error-reporter';

const reporter = new Reporter({
  transport: new HttpTransport({
    url: '/api/observability/errors',
    headers: { Authorization: `Bearer ${token}` },
    beforeSend: (body) => {
      // Hook for last-mile sanitization. Return null to drop.
      return body;
    },
  }),
  release: '...',
});

API surface

import {
  // Main orchestrator
  Reporter,

  // Transports
  Transport,        // interface
  MockTransport,
  ConsoleTransport,
  HttpTransport,

  // Pure helpers
  fingerprint,         // sync hash from name+message+top-frame
  fingerprintAsync,    // SHA-256 fingerprint (preferred)
  normalizeMessage,
  sanitizeMessage,
  sanitizeStack,
  sanitizeFunctionName,
  sanitizeFilePath,
  collectRuntime,
  parseUserAgent,
  getSessionId,
  isOptedOut,
  OPT_OUT_KEY,
  SESSION_KEY,

  // Types
  ErrorBody,           // the report body shape
  ResolvedBody,        // the deploy-time resolution body shape
  ReporterConfig,
  ReportContext,
  Severity,
  CaptureSource,
  StackFrame,
  Runtime,
} from '@syncropel/error-reporter';

Sub-path imports

import { ConsoleTransport } from '@syncropel/error-reporter/transports/console';
import { HttpTransport } from '@syncropel/error-reporter/transports/http';
import { MockTransport } from '@syncropel/error-reporter/transports/mock';

Configuration

interface ReporterConfig {
  transport: Transport;                  // required
  release: string;                       // required; e.g. "1.2.3" or "git-sha"
  enabled?: () => boolean;               // default: always enabled
  maxSessionEmits?: number;              // default: 100
  fingerprintCooldownMs?: number;        // default: 60_000 (1 minute)
}
  • enabled — re-evaluated on every report() call. Use to gate by environment, user opt-out, feature flag, etc.
  • maxSessionEmits — caps emissions per session (sessionStorage-backed). Once exceeded, suppressed_in_window increments and emits stop. Prevents one user with a broken page from flooding your transport.
  • fingerprintCooldownMs — same fingerprint within window is suppressed. Each emit carries suppressed_in_window count of how many were dropped during dedupe.

Privacy + sanitization

  • Stack frames are sanitized: function names + file paths only; no inline closures, no source maps applied client-side
  • sanitizeMessage strips email-like patterns and any bearer ...-style tokens
  • runtime.viewport.{w,h} is rounded to nearest 50px to avoid fingerprinting precision
  • Users can opt out via localStorage.setItem('@syncropel/error-reporter:opt-out', '1') — the Reporter checks isOptedOut() and short-circuits

Report body shape

interface ErrorBody {
  kind: 'syncropel.error.v1';
  fingerprint: string;
  severity: 'error' | 'warning' | 'info';
  name: string;
  message: string;
  stack: StackFrame[];
  source: CaptureSource;
  component?: string;
  route: string;
  runtime: Runtime;
  release: string;
  session_id: string;
  suppressed_in_window?: number;
}

A companion ResolvedBody shape closes an error thread when a deploy ships the fix:

interface ResolvedBody {
  kind: 'syncropel.error.resolved.v1';
  fingerprint: string;
  fixed_in_release: string;
  note?: string;
  resolver: string; // DID of whoever resolved it
}

License

Apache-2.0. See LICENSE.

Contributing

Source lives at syncropic/syncropel-web/packages/error-reporter. Issues + PRs welcome.