Releases: mathematic-inc/smapped-traces
v0.1.2
smapped-traces v0.1.2 🗺️
We're thrilled to ship the first public release of smapped-traces — a source map resolution library built from the ground up for OpenTelemetry. No more staring at minified bundle.js:1:98432 stack traces in your error dashboards. smapped-traces intercepts OTLP span exports on the client, attaches bundler debug IDs to every exception event, and resolves those mangled frames back to your original TypeScript source on the server — all transparently, with zero changes to your OpenTelemetry instrumentation code.
✨ New Features
Client-side span exporter with debug ID enrichment
SourceMappedSpanExporter wraps any OpenTelemetry span pipeline and automatically extracts debug IDs from exception stack traces, attaching them as a exception.stacktrace.debug_ids attribute before export. It starts with fetch for the first request, then switches to navigator.sendBeacon so traces are never dropped during page unload.
import { SourceMappedSpanExporter } from 'smapped-traces/client'
import { BatchSpanProcessor, WebTracerProvider } from '@opentelemetry/sdk-trace-web'
const exporter = new SourceMappedSpanExporter('/api/traces')
const provider = new WebTracerProvider({
spanProcessors: [new BatchSpanProcessor(exporter)],
})
provider.register()Server-side traces handler with source map resolution
createTracesHandler produces a standard (Request) => Promise<Response> handler you can drop into any framework. It deserializes OTLP/protobuf, resolves every exception stack trace against your source map store, replaces the minified trace in-place (preserving the original as exception.stacktrace.original), and forwards the enriched spans to any downstream OTLP exporter.
// app/api/traces/route.ts (Next.js App Router)
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { createTracesHandler } from 'smapped-traces/route'
import { createSqliteStore } from '@smapped-traces/sqlite'
export const POST = createTracesHandler({
exporter: new OTLPTraceExporter({ url: 'http://localhost:4318/v1/traces' }),
store: createSqliteStore('.next/sourcemaps.db'),
})Pluggable source map store interface
All storage backends implement a simple three-method SourceMapStore interface (get, put, optional close), making it trivial to build your own. Four ready-made implementations ship out of the box:
| Package | Backend |
|---|---|
@smapped-traces/sqlite |
Local SQLite (great for single-server / Next.js) |
@smapped-traces/s3 |
AWS S3, Google Cloud Storage, Cloudflare R2 |
smapped-traces/store → createHttpStore |
Fetch from a remote store over HTTP |
smapped-traces/store → createStoreHandler |
Expose any store as an HTTP API |
The HTTP store pair lets you run a dedicated source map microservice and point multiple app instances at it:
// Sidecar service (Bun / Deno / Node)
import { createStoreHandler } from 'smapped-traces/store'
import { createSqliteStore } from '@smapped-traces/sqlite'
const store = createSqliteStore('./sourcemaps.db')
Bun.serve({ port: 8081, fetch: createStoreHandler(store) })
// App server
import { createHttpStore } from 'smapped-traces/store'
const store = createHttpStore('http://localhost:8081')S3-compatible store (@smapped-traces/s3)
One store, three cloud providers. Pass any S3Client — AWS, GCS (with the S3-interop endpoint), or Cloudflare R2 — and smapped-traces handles the rest.
import { S3Client } from '@aws-sdk/client-s3'
import { createS3Store } from '@smapped-traces/s3'
const store = createS3Store({
client: new S3Client({ region: 'us-east-1' }),
bucket: 'my-sourcemaps',
prefix: 'sourcemaps/',
})Next.js build plugin (@smapped-traces/nextjs)
withSourceMaps wraps your next.config.ts, enables Turbopack debug IDs, turns on production browser source maps, and registers a post-build hook that uploads every *.js.map with a debugId field to your store — then deletes the map files so they never ship to users.
// next.config.ts
import { withSourceMaps } from '@smapped-traces/nextjs'
import { createS3Store } from '@smapped-traces/s3'
import { S3Client } from '@aws-sdk/client-s3'
export default withSourceMaps(
{ /* your existing Next.js config */ },
{
// Normalise Turbopack's internal path prefix so source links work in your IDE
replaceTurbopackSourcePrefix: 'file:///',
store: () =>
createS3Store({
client: new S3Client({ region: 'us-east-1' }),
bucket: 'my-sourcemaps',
}),
}
)Standalone source map resolver
Need to resolve stack traces outside the built-in handler? createSourceMapResolver gives you direct access — it maintains an LRU cache of parsed SourceMapConsumer instances so repeated lookups stay fast.
import { createSourceMapResolver } from 'smapped-traces/resolve'
import { createSqliteStore } from '@smapped-traces/sqlite'
const resolver = createSourceMapResolver({
store: createSqliteStore('./sourcemaps.db'),
maxCacheSize: 100,
})
const readable = await resolver.resolveStackTrace(minifiedStack, debugIds)
console.log(readable)⚡ Improvements
- sendBeacon reliability — after the first successful
fetch, the client automatically switches tonavigator.sendBeaconso spans are never lost when the user navigates away or closes the tab. - Graceful degradation — if the server responds with
204 No Content, the exporter disables itself and stops sending, making it easy to turn off collection without redeploying the client. - Safe-by-default store handler —
createStoreHandlerresponds with405 Method Not Allowedfor anything other thanGETandPUT, and always returns400when no debug ID is present in the path. - Automatic Turbopack support —
withSourceMapshandles both flat and sectioned (index map) source map formats, correctly transformingturbopack:///[project]/prefixes in both.
📦 Installation
# Core library
npm install smapped-traces
# Next.js build plugin
npm install @smapped-traces/nextjs
# S3-compatible store
npm install @smapped-traces/s3
# SQLite store
npm install @smapped-traces/sqlite better-sqlite3All packages are pure ESM and ship with full TypeScript declarations.
sqlite-v0.1.1
@smapped-traces/sqlite v0.1.1 🗺️
We're thrilled to introduce @smapped-traces/sqlite — a brand-new, dedicated SQLite store for smapped-traces that makes zero-infrastructure source map resolution a reality. With a single function call you get a fully persistent, production-ready store that lives right next to your build output: no external services, no network round-trips, no extra containers. This release also moves the entire smapped-traces ecosystem to its permanent home under the mathematic-inc organization on GitHub.
✨ New Features
@smapped-traces/sqlite — local SQLite store for source maps
createSqliteStore provides a SourceMapStore backed by better-sqlite3. It creates the database and table lazily on first write, stores source map JSON in SQLite's native binary JSON format (jsonb) for compact, fast retrieval, and closes cleanly when you're done.
import { createSqliteStore } from '@smapped-traces/sqlite'
import { createTracesHandler } from 'smapped-traces/route'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
// Next.js: app/api/traces/route.ts
export const POST = createTracesHandler({
exporter: new OTLPTraceExporter({ url: 'http://localhost:4318/v1/traces' }),
store: createSqliteStore('.next/sourcemaps.db'),
})Pair it with the @smapped-traces/nextjs build plugin and your source maps are collected at build time, stored in the SQLite database, and resolved automatically at runtime — all without leaving your server:
// next.config.ts
import { join } from 'node:path'
import { withSourceMaps } from '@smapped-traces/nextjs'
import { createSqliteStore } from '@smapped-traces/sqlite'
export default withSourceMaps(
{ /* ...your Next.js config... */ },
{
store: (distDir) => createSqliteStore(join(distDir, 'sourcemaps.db')),
}
)Or run a standalone source map microservice with Bun, pairing createStoreHandler from the core with the SQLite backend:
import { createStoreHandler } from 'smapped-traces/store'
import { createSqliteStore } from '@smapped-traces/sqlite'
const store = createSqliteStore('./sourcemaps.db')
Bun.serve({ port: 8081, fetch: createStoreHandler(store) })🐛 Bug Fixes
- Repository migrated to
mathematic-incorganization — all package repository URLs, issue links, and changelogs now point to the correctgithub.com/mathematic-inc/smapped-traceshome. (#6)
📦 Installation
Install the packages that fit your stack:
# Core library (client exporter + server handler + store primitives)
npm install smapped-traces
# Next.js build plugin — collects & uploads source maps at build time
npm install @smapped-traces/nextjs
# SQLite store — zero-infra local source map persistence
npm install @smapped-traces/sqlite
# S3-compatible store — AWS S3, Google Cloud Storage, or Cloudflare R2
npm install @smapped-traces/s3All packages require smapped-traces as a peer dependency. The @smapped-traces/sqlite package additionally requires better-sqlite3:
npm install smapped-traces better-sqlite3s3-v0.1.2
smapped-traces s3-v0.1.2 brings cloud-native source map storage to your OpenTelemetry error pipeline — store and serve your debug artifacts directly from AWS S3, Google Cloud Storage, or Cloudflare R2, all through the same familiar S3 API. This release also plants the project firmly in its new home at mathematic-inc/smapped-traces, with polished READMEs to match. Whether you're running a distributed Next.js app or a standalone OTLP collector, your minified stack traces now have a scalable, production-grade place to call home.
✨ New Features
S3-compatible source map store (@smapped-traces/s3)
The new createS3Store function plugs directly into the smapped-traces store interface and works with any S3-compatible service. Pass in a pre-configured S3Client (from @aws-sdk/client-s3), a bucket name, and an optional key prefix — that's it.
AWS S3:
import { S3Client } from '@aws-sdk/client-s3'
import { createS3Store } from '@smapped-traces/s3'
const store = createS3Store({
client: new S3Client({ region: 'us-east-1' }),
bucket: 'my-sourcemaps',
prefix: 'sourcemaps/',
})Cloudflare R2:
import { S3Client } from '@aws-sdk/client-s3'
import { createS3Store } from '@smapped-traces/s3'
const store = createS3Store({
client: new S3Client({
region: 'auto',
endpoint: 'https://<account-id>.r2.cloudflarestorage.com',
credentials: { accessKeyId: '...', secretAccessKey: '...' },
}),
bucket: 'my-sourcemaps',
})Wire it up to your Next.js build in next.config.ts:
import { withSourceMaps } from '@smapped-traces/nextjs'
import { createS3Store } from '@smapped-traces/s3'
import { S3Client } from '@aws-sdk/client-s3'
export default withSourceMaps(nextConfig, {
store: () => createS3Store({
client: new S3Client({ region: 'us-east-1' }),
bucket: 'my-sourcemaps',
}),
})And use the same store on your server to resolve incoming traces:
// app/api/traces/route.ts
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { createTracesHandler } from 'smapped-traces/route'
import { createS3Store } from '@smapped-traces/s3'
import { S3Client } from '@aws-sdk/client-s3'
export const POST = createTracesHandler({
exporter: new OTLPTraceExporter({ url: 'http://localhost:4318/v1/traces' }),
store: createS3Store({
client: new S3Client({ region: 'us-east-1' }),
bucket: 'my-sourcemaps',
}),
})🐛 Bug Fixes
- Repository migration — the project has moved to
mathematic-inc/smapped-traces. All links, references, and package metadata now point to the new home. (#6) - README updates — outdated documentation has been refreshed across all packages to reflect the current API and project structure.
📦 Installation
Install the packages for your setup:
# Core library (client exporter + server handler + store primitives)
npm install smapped-traces
# Next.js build plugin
npm install @smapped-traces/nextjs
# S3-compatible store (AWS S3 · Google Cloud Storage · Cloudflare R2)
npm install @smapped-traces/s3nextjs-v0.1.2
@smapped-traces/nextjs v0.1.2
Say goodbye to cryptic minified stack traces in your OpenTelemetry errors! This release brings smapped-traces to its new home under the mathematic-inc organization, ships refreshed documentation across all packages, and marks a great checkpoint to highlight everything this library can do — automatically enriching OTLP exception spans with debug IDs at build time and resolving them back to your original TypeScript source on the server, all without touching your existing OpenTelemetry pipeline.
🐛 Bug Fixes
- Repository migrated to
mathematic-inc— all packages, links, and metadata now point togithub.com/mathematic-inc/smapped-traces. Update any bookmarks or dependency configs accordingly. (#6) - Refreshed READMEs — outdated documentation has been corrected across all packages so the examples you copy actually work. (94d0eee)
✨ What smapped-traces Does (The Full Picture)
Client — SourceMappedSpanExporter
Drop in SourceMappedSpanExporter as your OpenTelemetry span exporter. It automatically extracts debug IDs from minified stack traces and attaches them to exception events before forwarding traces to your server endpoint. It uses fetch initially and seamlessly upgrades to sendBeacon for reliable delivery even during page unloads.
import { SourceMappedSpanExporter } from 'smapped-traces/client'
import { BatchSpanProcessor, WebTracerProvider } from '@opentelemetry/sdk-trace-web'
const exporter = new SourceMappedSpanExporter('/api/traces')
const provider = new WebTracerProvider({
spanProcessors: [new BatchSpanProcessor(exporter)],
})
provider.register()Server — createTracesHandler
On the server, createTracesHandler receives the enriched OTLP/protobuf traces, looks up source maps by debug ID, resolves every minified frame back to its original file and line number (preserving the original as .original), then forwards the clean spans to your observability backend.
// app/api/traces/route.ts
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { createTracesHandler } from 'smapped-traces/route'
import { createSqliteStore } from '@smapped-traces/sqlite'
export const POST = createTracesHandler({
exporter: new OTLPTraceExporter({ url: 'http://localhost:4318/v1/traces' }),
store: createSqliteStore('.next/sourcemaps.db'),
})Next.js Build Plugin — withSourceMaps
withSourceMaps hooks into Next.js's post-build step to collect every source map with a debug ID (including Turbopack-generated ones), upload them to your store, and then delete them so they never ship to the browser. The replaceTurbopackSourcePrefix option lets you rewrite Turbopack's internal turbopack:///[project]/ paths to a URL scheme your IDE or error viewer will recognize.
// next.config.ts
import { withSourceMaps } from '@smapped-traces/nextjs'
import { createSqliteStore } from '@smapped-traces/sqlite'
import { join } from 'node:path'
export default withSourceMaps(
{ /* your existing Next.js config */ },
{
replaceTurbopackSourcePrefix: 'file:///',
store: (distDir) => createSqliteStore(join(distDir, 'sourcemaps.db')),
}
)Remote Source Map Store — HTTP pair
For multi-server or serverless deployments, run a standalone store microservice and point your Next.js build at it:
// Store microservice (Bun / Deno / Node)
import { createStoreHandler } from 'smapped-traces/store'
import { createSqliteStore } from '@smapped-traces/sqlite'
Bun.serve({ port: 8081, fetch: createStoreHandler(createSqliteStore('./sourcemaps.db')) })
// next.config.ts — point build uploads at the microservice
import { createHttpStore } from 'smapped-traces/store'
store: () => createHttpStore('https://sourcemaps.internal')S3-Compatible Store — @smapped-traces/s3
Store source maps in the cloud with createS3Store. Works with AWS S3, Google Cloud Storage, and Cloudflare R2 — anything that speaks the S3 API.
import { S3Client } from '@aws-sdk/client-s3'
import { createS3Store } from '@smapped-traces/s3'
const store = createS3Store({
client: new S3Client({ region: 'us-east-1' }),
bucket: 'my-sourcemaps',
prefix: 'sourcemaps/',
})Custom Store — SourceMapStore interface
Have your own storage backend? Implement the two-method SourceMapStore interface and plug it straight in:
import type { SourceMapStore } from 'smapped-traces/store'
const myStore: SourceMapStore = {
async get(debugId) { /* return JSON string or null */ },
async put(debugId, content) { /* persist content */ },
close() { /* optional cleanup */ },
}📦 Installation
Install the packages that fit your setup:
# Core library (client exporter + server handler + store interface)
npm install smapped-traces
# Next.js build plugin
npm install @smapped-traces/nextjs
# SQLite store (great for local dev and single-server deployments)
npm install @smapped-traces/sqlite
# S3-compatible store (AWS S3, Google Cloud Storage, Cloudflare R2)
npm install @smapped-traces/s3Full changelog: nextjs-v0.1.1...nextjs-v0.1.2