Bumps every @wrnexus package 0.8.4 -> 0.8.5 and adds the matching update migration. The migration is documentation only: moving off <Table> to <DataTable> and off the @wrnexus/ui main entry to @wrnexus/ui/registry are source changes no codemod can make safely. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@wrnexus/tracking
Error tracking for WrNexus apps: capture exceptions manually or via middleware and fan them out to pluggable sinks.
Part of the WrNexus 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.
Installation
bun add @wrnexus/tracking
Private package — the machine must be authenticated to the
wrnexusnpm org (a read token in~/.npmrc). Requires Bun (Node is not supported).
API
createTracker(options?): Tracker
Creates a tracker. TrackerOptions:
| Option | Type | Description |
|---|---|---|
sinks |
ErrorSink[] |
Initial sinks to fan events out to. Defaults to []. |
now |
() => number |
Clock 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:
| Member | Signature | Description |
|---|---|---|
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) => void |
Registers an additional sink at runtime. |
middleware |
() => Middleware |
Returns a WrNexus 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— theContextandMiddlewaretypes used bytracker.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.