JavaScript & TypeScript

The reference BugWatch SDK: one package for Node services, browsers, edge runtimes and every major JS framework, with first-class TypeScript types.

Requirementslink

  • Node 20.19+ for server use; evergreen browsers; ships dual ESM and CommonJS builds
  • Edge runtimes (Cloudflare Workers, Vercel Edge) use the core client and must not import ./node (no AsyncLocalStorage there); Bun and Deno get core plus the Hono adapter
  • All framework and logger peers are optional. Minimums: express 4, fastify 4, koa 2, hono 4, hapi 20, nest 9, react 16.8, vue 3, pino 8, winston 3, bunyan 1.8, log4js 6, @opentelemetry/api 1.4

1 - Installlink

npm install @newinstance/bugwatch

The credential is the project DSN key (sk_test_… or sk_live_…, one per environment) from the dashboard project's Settings under DSN keys.

2 - Initialiselink

Server (Node):

import { BugWatch } from "@newinstance/bugwatch";
import { installNodeErrorHandlers } from "@newinstance/bugwatch/node";

const client = BugWatch.init({
  projectKey: process.env.BUGWATCH_KEY!,
  release: process.env.APP_VERSION,
});
installNodeErrorHandlers(client);

init is idempotent (a singleton on globalThis, safe under hot reload) and returns the existing client on repeat calls; captures before init are no-ops that still return a generated id. installNodeErrorHandlers is idempotent and returns an uninstall function; installAsyncScope + runWithContext give per-unit isolation to non-framework code (queues, workers).

Browser (never ship the key):

import { createClient } from "@newinstance/bugwatch";
import { installBrowserErrorHandlers } from "@newinstance/bugwatch/browser";

const client = createClient({ sessionUrl: "/bugwatch/session" });
installBrowserErrorHandlers(client);

Your backend exposes the mint endpoint: Express has a ready-made bugWatchBrowserSessionHandler; anything else calls mintBrowserSession which returns { token, expiresAt }. The transport refreshes the token 30 seconds before expiry and on a 401.

3 - Configurationlink

OptionDefaultWhat it does
projectKey / sessionUrl-Server credential, or the browser mint endpoint
release / environment- / from keyLabels on every event
enabled / debugtrue / falseMaster switch; debug prints delivery diagnostics including the server's reason string after the HTTP status
sampleRate1Applied before beforeSend; keep-all-errors sampling belongs in beforeSend
captureUnhandledErrors / captureUnhandledRejectionstrueGlobal handlers, chained not replaced
sensitiveFieldsbuilt-in listExtra redaction keys
beforeSend-May be async; return null to drop, or mutate and return the event
consoleonLocal echo of the native logger: false or `{ enabled, level, format: "auto"
batchSize / flushInterval50 / 5000 msDelivery batching; flushInterval: 0 disables the timer (manual flush only)
maxQueueSize1000Overflow drops the oldest queued events
requestTimeout15000 msPer-request timeout
retry3 attempts, 200 ms to 5 sExponential backoff
traceContextProvider-Auto-attach traceId and spanId (OTel below)

4 - Capture APIlink

const id = BugWatch.captureException(err, { tags: { route: "/checkout" } });
BugWatch.captureMessage("Payment settled", 30);
BugWatch.captureLog({ level: "warn", message: "Slow query", tags: { db: "orders" } });
BugWatch.setUser({ id: "u_123", email: "ada@example.com" });
BugWatch.setTag("tenant", "acme");
BugWatch.setContext("payment", { provider: "paystack" });
BugWatch.setRelease("checkout@2.4.1");
await BugWatch.flush();
await BugWatch.close();
  • Levels are Pino-compatible numerics 10 to 60 (the LEVELS map is exported); captureLog takes one object.
  • The per-capture hint accepts level, tags, user, traceId, spanId.
  • Call await BugWatch.close() on SIGTERM so the queue drains before exit.

5 - Framework adapterslink

Every adapter accepts a getUser option, resolved lazily at capture time, which replaces the auth-middleware pattern entirely; an explicit setRequestUser still wins. Adapters never swallow errors: they capture, then rethrow or call next(err).

StackSubpathEntry points and notes
Express./expressRequest handler first, error handler last; bugWatchBrowserSessionHandler for the mint route
Fastify / Koa / Hono / Hapi./fastify etc.bugWatchFastify, bugWatchKoa, bugWatchHono (pass opts.context to read Hono's c), createBugWatchHapiPlugin (identity read at onPreResponse)
NestJS./nestBugWatchExceptionFilter, bugWatchNestMiddleware
Next.js and serverless./nextwithBugWatchRouteHandler opens a per-request scope and flushes before return; the same wrapper pattern serves Lambda, Vercel and Netlify functions
React / Vue./react, ./vueBugWatchErrorBoundary (captures render errors with component stack; renders nothing without a fallback), createBugWatchVuePlugin (preserves an existing errorHandler)

6 - Logger integrationslink

LoggerFactory
NativecreateLogger() with child(bindings), zero deps, echoed locally per the console option
PinocreateBugWatchPinoDestination (only scalar fields become tags; objects and arrays are dropped)
WinstoncreateBugWatchWinstonTransport (error 50, warn 40, info 30, verbose and debug 20, silly 10)
Bunyan / log4jscreateBugWatchBunyanStream, bugWatchLog4jsAppender
consolecaptureConsole(client, { levels }), returns a restore()

7 - Testinglink

import { InMemoryTransport } from "@newinstance/bugwatch/testing";
const transport = new InMemoryTransport();
const client = new BugWatchClient(opts, { transport });
transport.events; transport.find(pred); transport.reset();

8 - Readable stack traceslink

Node stacks are readable as-is. React Native bundles resolve through the source map you upload in CI (see Mobile → React Native). For minified web bundles, server-side source-map resolution is not available yet: keep source maps deployed next to your bundles so browser devtools resolve frames.

Production checklistlink

  • await BugWatch.close() on SIGTERM; installNodeErrorHandlers at boot.
  • Keep the DSN key out of the repo and rotate it from the dashboard on exposure.
  • Browsers get sessionUrl, never projectKey.

Troubleshootinglink

  • 401 Invalid or inactive API key or 400 This API key is not a BugWatch project key: you are using an org key; use the project DSN key from Settings under DSN keys.
  • Events missing from a short-lived script: the batch timer never fired; call await BugWatch.flush().
  • Pino fields missing as tags: only string, number, boolean and bigint values map to tags.

Wire endpoints used: POST /api/v1/bugwatch/ingest (NDJSON, up to 5000 events per request), POST /api/v1/bugwatch/browser-session, POST /api/v1/bugwatch/ingest/browser.

JavaScript & TypeScript — NewInstance Documentation