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

dc-browser

v1.0.3

Published

Browser polyfill for Node.js diagnostics_channel

Downloads

52,395

Readme

dc-browser

Browser-compatible polyfill for Node.js's diagnostics_channel API. This package provides the core diagnostics channel functionality that works in browser environments, including integration with AsyncLocalStorage via als-browser.

Features

  • Full diagnostics_channel API compatibility
  • Channel publish/subscribe mechanism
  • TracingChannel for structured tracing
  • Integration with AsyncLocalStorage via bindStore
  • Zero runtime dependencies
  • TypeScript support with full type definitions
  • ESM and CommonJS builds
  • Comprehensive test coverage

Installation

npm install dc-browser
# or
pnpm add dc-browser
# or
yarn add dc-browser

For AsyncLocalStorage integration:

npm install als-browser

Usage

Basic Channel

import { channel } from 'dc-browser';

const requestChannel = channel('http.request');

// Subscribe to messages
requestChannel.subscribe((message, name) => {
  console.log(`Received on ${name}:`, message);
});

// Publish a message
requestChannel.publish({ url: '/api/data', method: 'GET' });

TracingChannel

TracingChannel provides structured tracing with start, end, asyncStart, asyncEnd, and error events:

import { tracingChannel } from 'dc-browser';

const httpChannel = tracingChannel('http.request');

// Subscribe to events
httpChannel.subscribe({
  start: (context) => {
    console.log('Request started:', context);
  },
  end: (context) => {
    console.log('Request ended:', context);
  },
  error: (context) => {
    console.error('Request error:', context.error);
  }
});

// Trace a synchronous operation
const result = httpChannel.traceSync(() => {
  // Your sync code here
  return fetchData();
}, { requestId: 'req-123' });

// Trace a promise-based operation
const data = await httpChannel.tracePromise(async () => {
  // Your async code here
  return await fetch('/api/data');
}, { requestId: 'req-456' });

AsyncLocalStorage Integration

Channels can be bound to AsyncLocalStorage instances to transform events into stored context:

import { channel } from 'dc-browser';
import { AsyncLocalStorage } from 'als-browser';

const requestChannel = channel('http.request');
const requestContext = new AsyncLocalStorage();

// Bind the store to the channel
requestChannel.bindStore(requestContext);

// Now runStores will propagate context to the store
requestChannel.runStores({ requestId: 'req-789' }, () => {
  console.log(requestContext.getStore()); // { requestId: 'req-789' }

  // Context is available in the callback
  doWork();
});

function doWork() {
  const context = requestContext.getStore();
  console.log('Current request:', context.requestId);
}

Transform Function

You can provide a transform function when binding a store to extract/transform the message:

import { channel } from 'dc-browser';
import { AsyncLocalStorage } from 'als-browser';

const requestChannel = channel('http.request');
const userIdStore = new AsyncLocalStorage<string>();

// Extract just the userId from messages
requestChannel.bindStore(
  userIdStore,
  (message) => message.userId
);

requestChannel.runStores({ userId: 'user-123', url: '/api/data' }, () => {
  console.log(userIdStore.getStore()); // 'user-123'
});

Multiple Stores

You can bind multiple AsyncLocalStorage instances to a single channel:

const requestChannel = channel('http.request');
const requestIdStore = new AsyncLocalStorage<string>();
const userIdStore = new AsyncLocalStorage<string>();

requestChannel.bindStore(requestIdStore, (msg) => msg.requestId);
requestChannel.bindStore(userIdStore, (msg) => msg.userId);

requestChannel.runStores({ requestId: 'req-123', userId: 'user-456' }, () => {
  console.log(requestIdStore.getStore()); // 'req-123'
  console.log(userIdStore.getStore());    // 'user-456'
});

Unbinding Stores

const store = new AsyncLocalStorage();
const ch = channel('test');

ch.bindStore(store);
// ... later
ch.unbindStore(store); // Returns true if successfully unbound

API

Module Functions

channel(name: string | symbol): Channel

Get or create a channel by name.

hasSubscribers(name: string | symbol): boolean

Check if a channel has any subscribers.

subscribe(name: string | symbol, callback: Function): void

Subscribe to a channel.

unsubscribe(name: string | symbol, callback: Function): boolean

Unsubscribe from a channel.

tracingChannel(name: string): TracingChannel

Create a TracingChannel for structured tracing.

Channel Class

subscribe(callback: (message: any, name: string) => void): void

Add a subscriber to this channel.

unsubscribe(callback: Function): boolean

Remove a subscriber from this channel.

publish(message: any): void

Publish a message to all subscribers.

bindStore(store: AsyncLocalStorage, transform?: (message: any) => any): void

Bind an AsyncLocalStorage instance to this channel. When runStores is called, the message (optionally transformed) will be set as the store value.

unbindStore(store: AsyncLocalStorage): boolean

Unbind an AsyncLocalStorage instance from this channel.

runStores(context: any, fn: () => any): any

Publish the context and run the function within all bound AsyncLocalStorage contexts.

TracingChannel Class

A TracingChannel manages 5 individual channels:

  • start: Published before operation begins
  • end: Published after operation completes
  • asyncStart: Published when async operation starts resolving
  • asyncEnd: Published when async operation finishes resolving
  • error: Published when operation throws/rejects

subscribe(handlers: ChannelHandlers): void

Subscribe to tracing events.

unsubscribe(handlers: ChannelHandlers): boolean

Unsubscribe from tracing events.

traceSync<T>(fn: Function, context?: any, thisArg?: any, ...args: any[]): T

Trace a synchronous operation.

tracePromise<T>(fn: Function, context?: any, thisArg?: any, ...args: any[]): Promise<T>

Trace a promise-based operation.

traceCallback<T>(fn: Function, position?: number, context?: any, thisArg?: any, ...args: any[]): any

Trace a callback-based operation.

Integration with als-browser

When using bindStore with als-browser, the context will be preserved through:

  1. Synchronous code: Full context propagation within the runStores callback
  2. Patched async APIs: setTimeout, setInterval, requestAnimationFrame (via als-browser auto-patches)
  3. Manual propagation: Use AsyncLocalStorage.bind() or snapshot() for other async operations

Note: Native Promise await boundaries will lose context unless you:

  • Use the patched timer APIs (setTimeout, etc.)
  • Manually bind callbacks with AsyncLocalStorage.bind()
  • Use the capture/restore functions from als-browser

Example: Request Tracing with Context

import { tracingChannel } from 'dc-browser';
import { AsyncLocalStorage } from 'als-browser';

const httpChannel = tracingChannel('http.request');
const requestStore = new AsyncLocalStorage();

// Bind store to start channel for context propagation
httpChannel.start.bindStore(requestStore);

// Subscribe to events
httpChannel.subscribe({
  start: (ctx) => console.log('Started:', ctx.requestId),
  end: (ctx) => console.log('Ended:', ctx.requestId, 'result:', ctx.result),
  error: (ctx) => console.error('Error:', ctx.requestId, ctx.error)
});

// Make a traced request
const response = httpChannel.traceSync(() => {
  // Context is available throughout the operation
  console.log('Current request:', requestStore.getStore()?.requestId);

  return fetch('/api/data');
}, { requestId: 'req-123', url: '/api/data' });

Testing

# Run tests
pnpm test

# Build
pnpm build

License

MIT

Credits

This implementation is based on Node.js's diagnostics_channel API from Node.js core.