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

@rnx-kit/reporter

v0.2.0

Published

EXPERIMENTAL - USE WITH CAUTION - reporter

Readme

@rnx-kit/reporter

Build npm version

🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧

THIS TOOL IS EXPERIMENTAL — USE WITH CAUTION

🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧

This is a common package for logging output to the console and/or logfiles, timing tasks and operations, and listening for events for task start, finish, and errors.

It is written as esm, side-effect free, with the functionality separated so that it will only bring in the portions that are used. The core logger and reporter functionality can be used on its own, with additional modules provided for colors and formatting.

All code is self-contained and this has no dependencies.

Core Components

🎯 Logger (createLogger)

A flexible logging system that supports multiple log levels and custom output destinations.

import { createLogger } from "@rnx-kit/reporter";

const logger = createLogger({
  output: "verbose", // or custom OutputWriter
  prefix: { error: "🚨", warn: "⚠️" },
  onError: (args) => console.error("Error occurred:", args),
});

logger.error("Something went wrong");
logger.warn("This is a warning");
logger.log("General information");
logger.verbose("Detailed debugging info:", myCustomObject);
logger.fatalError("Critical error"); // logs and throws

Features:

  • Log Levels: error, warn, log, verbose with hierarchical filtering
  • Custom Prefixes: Add emoji, text, or styling to log messages
  • Error Callbacks: Handle errors with custom logic
  • Multiple Outputs: Console, files, or custom destinations

📊 Reporter (createReporter)

A hierarchical task and performance tracking system built on top of the logger.

import { createReporter } from "@rnx-kit/reporter";

const reporter = createReporter({
  name: "build-system",
  output: "log",
  reportTimers: true,
});

// Hierarchical task execution
await reporter.task("build", async (buildTask) => {
  buildTask.log("Starting build process...");

  // async functions will time and execute asynchronously
  const result1 = await buildTask.task("compile", async (compileTask) => {
    compileTask.log("Compiling TypeScript...");
    // compilation logic
  });

  // sync functions will execute without yielding to the event loop
  const result2 = buildTask.task("bundle", (bundleTask) => {
    bundleTask.log("Creating bundle...");
    // bundling logic
  });
});

// Operation timing
const result = await reporter.measure("file-processing", async () => {
  // time-sensitive operation
  return processFiles();
});

Features:

  • Hierarchical Tasks: Nested task execution with automatic timing
  • Performance Measurement: Track operation durations and call counts
  • Error Tracking: Automatic error collection and reporting
  • Event Publishing: Start/finish/error events via Node.js diagnostics channels

🎨 Formatting & Colors

Rich text formatting with ANSI colors and semantic highlighting.

import { getFormatter, createFormatter } from "@rnx-kit/reporter";

const fmt = getFormatter();

// Basic colors
console.log(fmt.red("Error message"));
console.log(fmt.green("Success message"));
console.log(fmt.blue("Info message"));

// Semantic formatting
console.log(fmt.package("@my-scope/package-name"));
console.log(fmt.duration(1250)); // "1.25s"
console.log(fmt.pad("text", 10, "center")); // "   text   "

// Custom formatter
const customFmt = createFormatter({
  highlight1: fmt.magenta,
  durationValue: fmt.yellowBright,
});

Features:

  • ANSI Colors: Full 16-color and 256-color support
  • Font Styles: Bold, dim, italic, underline, strikethrough
  • Semantic Colors: Package names, durations, highlights, paths
  • Smart Padding: VT control character-aware text alignment
  • Auto-detection: Respects terminal color capabilities

📡 Event System

Type-safe event handling using Node.js diagnostics channels.

import {
  subscribeToStart,
  subscribeToFinish,
  subscribeToError,
} from "@rnx-kit/reporter";

// Listen for task start events
const unsubscribeStart = subscribeToStart((session) => {
  console.log(`Task started: ${session.name} (depth: ${session.depth})`);
});

// Listen for task completion
const unsubscribeFinish = subscribeToFinish((session) => {
  console.log(`Task finished: ${session.name} in ${session.elapsed}ms`);
  console.log(`Operations:`, session.operations);
});

// Listen for errors
const unsubscribeError = subscribeToError((event) => {
  console.log(`Error in ${event.session.name}:`, event.args);
});

// Cleanup when done
unsubscribeStart();
unsubscribeFinish();
unsubscribeError();

Output Destinations

📤 Console Output

Default output to stdout/stderr with proper log level routing.

import { createOutput } from "@rnx-kit/reporter";

// Console output with specific log level
const output = createOutput("warn"); // Only error and warn messages

📁 File Output

Write logs to files with automatic directory creation.

import { openFileWrite } from "@rnx-kit/reporter";

const fileOutput = createOutput(
  "verbose",
  openFileWrite("./logs/app.log", true), // append mode
  openFileWrite("./logs/errors.log", true)
);

🔀 Multiple Outputs

Combine multiple output destinations.

import { mergeOutput, createOutput } from "@rnx-kit/reporter";

const consoleOut = createOutput("warn");
const fileOut = createOutput("verbose", fileWriter);
const combined = mergeOutput(consoleOut, fileOut);

Architecture Principles

🧩 Modular Design

Each component can be used independently:

  • Use just the logger for simple logging needs
  • Add the reporter for task tracking
  • Include formatting for rich output
  • Enable events for monitoring

🎯 Zero Dependencies

Completely self-contained with no external dependencies, using only Node.js built-ins.

📏 Type Safety

Comprehensive TypeScript definitions with full type inference and safety.

🔄 Side-Effect Free

ESM modules with no global state pollution - safe for library use.

Performance Focused

  • Lazy initialization of heavy components
  • Efficient string handling
  • Minimal allocation in hot paths
  • Optional features don't impact performance when unused

Common Patterns

🏗️ Build Tool Integration

const build = createReporter({ name: "webpack-build", reportTimers: true });

await build.task("compile", async (task) => {
  const stats = await task.measure("typescript", () => compileTypeScript());
  const bundle = await task.measure("webpack", () => runWebpack());
  task.log(`Compilation complete: ${stats.files} files, ${bundle.size} bytes`);
});

🧪 Test Runner Integration

const test = createReporter({ name: "test-runner", output: "verbose" });

for (const suite of testSuites) {
  await test.task(suite.name, async (suiteTask) => {
    for (const testCase of suite.tests) {
      try {
        await suiteTask.measure(testCase.name, () => testCase.run());
        suiteTask.log(`✅ ${testCase.name}`);
      } catch (error) {
        suiteTask.error(`❌ ${testCase.name}:`, error);
      }
    }
  });
}

🚀 CLI Application Logging

const app = createCascadingReporter("MY_CLI_APP", {
  level: process.env.VERBOSE ? "verbose" : "log",
  file: process.env.LOG_FILE ? { out: process.env.LOG_FILE } : undefined,
});

if (app) {
  await app.task("main", async (task) => {
    task.log("Application started");
    // CLI logic
  });
}