smapped-traces
v0.1.2
Published
Source map resolution for OpenTelemetry errors
Maintainers
Readme
smapped-traces
Source map resolution for OpenTelemetry errors. Resolves minified stack traces back to original source locations using debug IDs.
Installation
npm install smapped-tracesEntry Points
| Path | Exports | Description |
| --- | --- | --- |
| smapped-traces/client | SourceMappedSpanExporter, extractDebugIdsFromStack, getDebugIdsByUrl | Client-side span exporter with debug ID enrichment |
| smapped-traces/route | createTracesHandler, createSourceMapResolver | Request handler that resolves traces and forwards to your OTEL collector |
| smapped-traces/resolve | createSourceMapResolver, formatStackTrace | Standalone source map resolution (no request handling) |
| smapped-traces/store | SourceMapStore, createHttpStore, createStoreHandler | HTTP store client and handler |
Usage
Client Exporter
SourceMappedSpanExporter is a SpanExporter that enriches exception events with debug IDs extracted from bundler-injected globals (_debugIds from Turbopack, __DEBUG_IDS__ from the TC39 spec / webpack), then sends traces as OTLP/protobuf via fetch (with sendBeacon fallback on page unload).
import { SourceMappedSpanExporter } from "smapped-traces/client";
import { SimpleSpanProcessor } from "@opentelemetry/sdk-trace-base";
import { WebTracerProvider } from "@opentelemetry/sdk-trace-web";
const exporter = new SourceMappedSpanExporter("/api/sourcemaps");
const provider = new WebTracerProvider({
spanProcessors: [new SimpleSpanProcessor(exporter)],
});
provider.register();Traces Handler
createTracesHandler returns a (Request) => Promise<Response> handler that accepts OTLP/protobuf traces, resolves exception stack traces using source maps from the provided store, and forwards the resolved spans to your exporter.
// Next.js: app/api/sourcemaps/route.ts
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import { createTracesHandler } from "smapped-traces/route";
import { createSqliteStore } from "@smapped-traces/sqlite";
import { join } from "node:path";
export const POST = createTracesHandler({
exporter: new OTLPTraceExporter({ url: "http://localhost:4318/v1/traces" }),
store: createSqliteStore(join(process.cwd(), ".next/sourcemaps.db")),
});The handler uses standard Web Request/Response, so it works with any runtime:
// Bun
Bun.serve({ port: 8080, fetch: handler });
// Deno
Deno.serve({ port: 8080 }, handler);Source Map Resolver
createSourceMapResolver provides standalone stack trace resolution without a request handler. Useful when you need to resolve traces outside the HTTP request flow (e.g. in a queue consumer or background job).
import { createSourceMapResolver } from "smapped-traces/resolve";
import { createSqliteStore } from "@smapped-traces/sqlite";
const resolver = createSourceMapResolver({
store: createSqliteStore("./sourcemaps.db"),
maxCacheSize: 100, // LRU cache for parsed source maps (default: 50)
});
const resolved = await resolver.resolveStackTrace(minifiedStack, debugIds);
// Clean up when done
resolver.close();Store
Source maps are stored and retrieved through the SourceMapStore interface.
SQLite Store
Install @smapped-traces/sqlite for local or single-server storage:
npm install @smapped-traces/sqliteimport { createSqliteStore } from "@smapped-traces/sqlite";
const store = createSqliteStore("./sourcemaps.db");HTTP Store
Communicates with a remote store handler over HTTP. Pair with createStoreHandler on the server side.
import { createHttpStore } from "smapped-traces/store";
const store = createHttpStore("https://sourcemaps.internal");Store Handler
createStoreHandler exposes a SourceMapStore as a REST API (GET /:debugId, PUT /:debugId). Deploy as a standalone service to share source maps across build and runtime environments.
import { createStoreHandler } from "smapped-traces/store";
import { createSqliteStore } from "@smapped-traces/sqlite";
const store = createSqliteStore("./sourcemaps.db");
Bun.serve({ port: 8081, fetch: createStoreHandler(store) });SourceMapStore Interface
Implement this interface to provide a custom storage backend:
interface SourceMapStore {
/** Retrieves a source map by debug ID. Returns null if not found. */
get(debugId: string): string | null | Promise<string | null>;
/** Stores a source map JSON string by debug ID. */
put(debugId: string, content: string): void | Promise<void>;
/** Releases resources held by the store (optional). */
close?(): void;
}Requirements
- OpenTelemetry SDK v2+ (
@opentelemetry/sdk-trace-base ^2.0.0,@opentelemetry/core ^2.0.0) @opentelemetry/api ^1.9.0
License
Apache-2.0
