npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@rixmerz/flowtrace-browser

v2.2.0

Published

FlowTrace v2 browser capture: HTTP, navigation and error spans shipped to the dashboard collector

Readme

@rixmerz/flowtrace-browser

npm i @rixmerz/flowtrace-browser

Browser capture for FlowTrace v2: HTTP requests, route changes and unhandled errors, emitted as the same schema v2 events every other capture layer produces and shipped to the dashboard collector.

What it does and does not trace

The Node and Python layers instrument every function, by rewriting modules at load time. This one does not, and the reason is structural rather than temporary: the browser has no AsyncLocalStorage. The nearest equivalent is Zone.js, and Angular is actively moving away from it, so building on it would tie this package to a shrinking assumption.

Without ambient async context there is no way to attribute an arbitrary function call to the request that caused it. So this layer records the events whose start and end are well defined and whose handle the caller can hold across the await: HTTP, navigation, errors. Those are also where the questions usually are.

Change detection is deliberately not instrumented. Angular exposes no supported hook, and a CD pass is far too frequent to record per-occurrence without drowning the trace.

Mapping onto schema v2

The schema has no browser concepts and additionalProperties: false, so nothing is invented. Browser work is expressed with the fields that exist:

| Field | Meaning here | |-------|--------------| | module | http | router | error | | class | the resource: URL path, route, or error type | | method | the operation: GET, navigate, the error origin | | args | url, navigation endpoints | | result | {status, ok}, or {} on failure | | error | {type, msg, stack}, exactly as the other layers emit it |

A trace mixing browser and server spans therefore reads uniformly, and trace_tree, trace_find_error and the dashboard work on it unchanged.

URLs are scrubbed of query strings and fragments before being recorded. Traces get shared, and query strings routinely carry tokens.

Setup

import { initFlowtrace } from '@rixmerz/flowtrace-browser';

initFlowtrace({
  endpoint: 'http://localhost:8765/api/trace',
  // Optional: a server-rendered traceparent, so the document request and
  // everything the page then does land in one trace.
  traceparent: document.querySelector('meta[name=traceparent]')?.content,
});

Start the collector with cd flowtrace-dashboard && pnpm start.

Events are batched and flushed on size, on an interval, and on visibilitychange/pagehide via navigator.sendBeacon — which is what keeps the tail of a session from being lost when the tab closes.

Angular

See src/angular.js. The bindings are intentionally thin: all the logic lives in src/api.js and is unit-tested without Angular, so what remains in the Angular file is wiring.

import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { provideAppInitializer, inject, ErrorHandler } from '@angular/core';
import { Router } from '@angular/router';
import { provideFlowtrace, flowtraceInterceptor } from '@rixmerz/flowtrace-browser/angular';

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(withInterceptors([flowtraceInterceptor])),
    provideFlowtrace(
      { endpoint: 'http://localhost:8765/api/trace' },
      { provideAppInitializer, inject, Router, ErrorHandler },
    ),
  ],
};

Angular symbols are passed in rather than imported, so this package stays installable — and testable — with no Angular in the dependency graph. The TypeScript declarations duplicate Angular's shapes structurally for the same reason: flowtraceInterceptor is assignable to HttpInterceptorFn without this package depending on @angular/common/http.

The interceptor attaches traceparent to every outgoing request, so a call from the browser continues into the traced server as one trace. It never overwrites a header the application already set.

rxjs is the one framework import in angular.js, used for tap so the interceptor returns Angular's own Observable with its identity intact — unsubscribe still cancels the request and every HttpEvent still passes through. It is a peer dependency, already present in any Angular app.

Why this one is published and the others are not

Every other capture layer is vendored inside @rixmerz/flowtrace, because the CLI launches the runtime and injects the layer into it. A browser layer cannot work that way: it is a build-time dependency of the application's own bundle, and no globally installed CLI can put a module into someone's vite graph.

Reaching it through the CLI tarball was measured and rejected — it costs a frontend 31 MB of @swc/core, a 2.3 MB Java jar and a package-manager build-script prompt, to import 60 KB of code it can install directly.

Cross-origin: the server must allow the header

traceparent is not a CORS-safelisted request header, so adding it makes a request that used to be simple into a preflighted one. If the browser and the API are on different origins, the API must name it:

Access-Control-Allow-Headers: Content-Type, traceparent

Without that the preflight fails and the request never happens — turning on FlowTrace breaks the call. This is the first thing to check when enabling the browser layer turns working requests into CORS errors.

Tests

make test-browser

Includes an end-to-end test that boots the real dashboard collector and asserts that browser spans land on disk as schema-valid JSONL — the only test covering the seam between the two.