W WRNexusJS
Runtime · Package reference

@wrnexus/tracking

Error/event capture, middleware, filtering, and sinks.

v0.8.7Private registryRuntime

Install the package

After WorkRoot approves private registry access, install the release-aligned package:

bun add @wrnexus/tracking@0.8.7

Request preview access. Never put registry tokens in source control.

Error tracking for WRNexusJS apps: capture exceptions manually or via middleware and fan them out to pluggable sinks.

Part of the WRNexusJS framework — an SSR-first, Bun-native full-stack web framework.

Overview

@wrnexus/tracking is a small, server-side error-capture layer. You create a tracker with one or more sinks, then feed it errors — either manually with tracker.capture(err, context) or automatically by mounting tracker.middleware() in your request pipeline. A consoleSink is included; forwarding to Sentry, Datadog, or any other backend is just a matter of writing a tiny sink. Reach for it when you want a single, sink-agnostic place to route application errors. Sinks run best-effort — a throwing sink never breaks the request.

bun add @wrnexus/tracking
Private package — the machine must be authenticated to the wrnexus npm org
(a read token in ~/.npmrc). Requires Bun (Node is not supported).

API

createTracker(options?): Tracker

Creates a tracker. TrackerOptions:

OptionTypeDescription
sinksErrorSink[]Initial sinks to fan events out to. Defaults to [].
now() => numberClock used for event.timestamp (epoch ms). Defaults to Date.now.
beforeSend`(event: ErrorEvent) => ErrorEvent \null`Scrub/enrich an event before it reaches any sink. Return null to drop it.

The returned Tracker:

MemberSignatureDescription
capture(error: unknown, context?: Record<string, unknown>) => Promise<void>Normalizes any thrown value into an Error, builds an ErrorEvent, runs beforeSend, then dispatches to all sinks. Non-Error values are wrapped in an Error named NonError.
addSink(sink: ErrorSink) => voidRegisters an additional sink at runtime.
middleware() => MiddlewareReturns a WRNexusJS Middleware that captures any error thrown downstream, then re-throws it so the framework's error handler still produces the response.

The middleware attaches this context to captured events:

{ method: ctx.req.method, path: ctx.url.pathname, requestId: ctx.locals.requestId }

consoleSink: ErrorSink

A built-in sink that logs a compact one-line message via console.error, e.g. [error] TypeError: cannot read x {"userId":42}.

Types

interface ErrorEvent {
  error: Error;
  context: Record<string, unknown>; // request info, user id, tags…
  timestamp: number; // epoch ms
}

interface ErrorSink {
  name?: string;
  capture(event: ErrorEvent): void | Promise<void>;
}

Usage

Manual capture:

import { createTracker, consoleSink } from "@wrnexus/tracking";

const tracker = createTracker({ sinks: [consoleSink] });

try {
  await doWork();
} catch (err) {
  await tracker.capture(err, { userId: 42, op: "doWork" });
  throw err;
}

As request middleware:

import { createTracker, consoleSink } from "@wrnexus/tracking";

const tracker = createTracker({ sinks: [consoleSink] });

app.use(tracker.middleware()); // captures + re-throws downstream errors

A custom sink with beforeSend scrubbing:

import { createTracker, type ErrorSink } from "@wrnexus/tracking";

const sentrySink: ErrorSink = {
  name: "sentry",
  async capture(event) {
    await Sentry.captureException(event.error, { extra: event.context });
  },
};

const tracker = createTracker({
  sinks: [sentrySink],
  beforeSend(event) {
    delete event.context.password; // scrub secrets
    return event; // return null to drop the event entirely
  },
});

tracker.addSink(anotherSink); // add more sinks later

Requirements / Notes

  • Runs on Bun only (Node is not supported).
  • Peer package: [@wrnexus/core](../core) — the Context and Middleware types
  • used by tracker.middleware() come from there.

  • Sink dispatch is fire-and-forget-safe: all sinks run via Promise.all, and a
  • sink that throws is swallowed so it can never break the app.

Complete TypeScript API

Generated from the exact installed package declarations.

import { Middleware } from '@wrnexus/core';

type TelemetryKind = "error" | "event" | "metric" | "span";
interface TelemetryEnvelope {
    id: string;
    kind: TelemetryKind;
    name: string;
    timestamp: number;
    traceId?: string;
    userId?: string;
    tenantId?: string;
    attributes: Record<string, unknown>;
    payload?: unknown;
}
interface TelemetrySink {
    name?: string;
    send(events: TelemetryEnvelope[]): void | Promise<void>;
}
interface TelemetryPipeline {
    emit(input: Omit<TelemetryEnvelope, "id" | "timestamp"> & Partial<Pick<TelemetryEnvelope, "id" | "timestamp">>): Promise<void>;
    flush(): Promise<void>;
    close(): Promise<void>;
    size(): number;
}
interface TelemetryPipelineOptions {
    sinks: TelemetrySink[];
    batchSize?: number;
    flushIntervalMs?: number;
    maxQueueSize?: number;
    sampleRate?: number;
    beforeSend?: (event: TelemetryEnvelope) => TelemetryEnvelope | null;
    onSinkError?: (error: unknown, sink: TelemetrySink, events: readonly TelemetryEnvelope[]) => void | Promise<void>;
    now?: () => number;
    random?: () => number;
}
declare function createTelemetryPipeline(options: TelemetryPipelineOptions): TelemetryPipeline;
declare const telemetryConsoleSink: TelemetrySink;

/**
 * @wrnexus/tracking — error tracking with pluggable sinks. Capture exceptions
 * manually or via middleware, and fan them out to any sink (console by default;
 * write a small sink to forward to Sentry/Datadog/etc.).
 *
 *   const tracker = createTracker({ sinks: [consoleSink] });
 *   app-middleware: tracker.middleware()   // captures + re-throws request errors
 *   tracker.capture(err, { userId });      // manual
 */

interface ErrorEvent {
    error: Error;
    /** Arbitrary structured context (request info, user id, tags…). */
    context: Record<string, unknown>;
    /** Epoch ms. */
    timestamp: number;
}
interface ErrorSink {
    name?: string;
    capture(event: ErrorEvent): void | Promise<void>;
}
interface Tracker {
    capture(error: unknown, context?: Record<string, unknown>): Promise<void>;
    addSink(sink: ErrorSink): void;
    /** Middleware that captures errors thrown downstream, then re-throws them. */
    middleware(): Middleware;
}
interface TrackerOptions {
    sinks?: ErrorSink[];
    now?: () => number;
    /** Scrub/enrich an event before it hits sinks (return null to drop it). */
    beforeSend?: (event: ErrorEvent) => ErrorEvent | null;
}
/** A sink that logs a compact one-line error to the console. */
declare const consoleSink: ErrorSink;
declare function createTracker(options?: TrackerOptions): Tracker;

export { type ErrorEvent, type ErrorSink, type TelemetryEnvelope, type TelemetryKind, type TelemetryPipeline, type TelemetryPipelineOptions, type TelemetrySink, type Tracker, type TrackerOptions, consoleSink, createTelemetryPipeline, createTracker, telemetryConsoleSink };

Examples

Copy-ready examples from the installed package documentation.

Manual capture

import { createTracker, consoleSink } from "@wrnexus/tracking";

const tracker = createTracker({ sinks: [consoleSink] });

try {
  await doWork();
} catch (err) {
  await tracker.capture(err, { userId: 42, op: "doWork" });
  throw err;
}

As request middleware

import { createTracker, consoleSink } from "@wrnexus/tracking";

const tracker = createTracker({ sinks: [consoleSink] });

app.use(tracker.middleware()); // captures + re-throws downstream errors

A custom sink with beforeSend scrubbing

import { createTracker, type ErrorSink } from "@wrnexus/tracking";

const sentrySink: ErrorSink = {
  name: "sentry",
  async capture(event) {
    await Sentry.captureException(event.error, { extra: event.context });
  },
};

const tracker = createTracker({
  sinks: [sentrySink],
  beforeSend(event) {
    delete event.context.password; // scrub secrets
    return event; // return null to drop the event entirely
  },
});

tracker.addSink(anotherSink); // add more sinks later