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

@sldm/debug

v0.3.0

Published

Comprehensive debugging utilities for Solidum applications

Readme

@sldm/debug

Comprehensive debugging utilities for Solidum applications

Features

  • 📊 Structured Logging - Log levels, namespaces, and rich context
  • 🎨 Multiple Formatters - Console, JSON, HTML, Markdown, Plain text
  • 📡 Real-time Streaming - SSE and WebSocket support
  • Performance Monitoring - FPS, memory, and custom measurements
  • 🔍 Reactive Debugging - Track signal changes and effects
  • 🌳 Component Tree - Visualize component hierarchy
  • Time Travel - Snapshot and replay state changes
  • 🚀 Debug API - HTTP endpoints for external tools

Installation

pnpm add @sldm/debug

Quick Start

import { logger, debug } from '@sldm/debug';

// Simple logging
logger.info('Application started');
logger.debug('User data', { userId: 123 });
logger.error('Failed to load', error);

// Or use the shorthand
debug.info('Quick log message');

Core Logger

Log Levels

import { createLogger, LogLevelEnum } from '@sldm/debug';

const logger = createLogger({
  level: LogLevelEnum.DEBUG,
  namespace: 'my-app',
  includeTimestamp: true,
  includeStack: false,
});

logger.trace('Detailed trace');
logger.debug('Debug information');
logger.info('General information');
logger.warn('Warning message');
logger.error('Error occurred', error);
logger.fatal('Critical error', error);

Namespaces

const appLogger = createLogger({ namespace: 'app' });
const dbLogger = appLogger.namespace('database');
const apiLogger = appLogger.namespace('api');

dbLogger.info('Connected'); // [app:database] Connected
apiLogger.info('Request'); // [app:api] Request

Performance Timing

// Manual timing
logger.timeStart('load-data');
await loadData();
logger.timeEnd('load-data'); // Logs duration

// Automatic timing
await logger.timeAsync('api-call', async () => {
  return await fetch('/api/data');
});

// Sync timing
const result = logger.measureSync('computation', () => {
  return heavyComputation();
});

Log Streaming

import { logger } from '@sldm/debug';

// Subscribe to log stream
const unsubscribe = logger.subscribe(entry => {
  console.log('New log entry:', entry);
  // Send to external service, etc.
});

// Unsubscribe when done
unsubscribe();

Formatters

Export in Different Formats

import { logger, OutputFormatEnum } from '@sldm/debug';

// Export as JSON
const json = logger.export(OutputFormatEnum.JSON);

// Export as HTML
const html = logger.export(OutputFormatEnum.HTML);

// Export as Markdown
const markdown = logger.export(OutputFormatEnum.MARKDOWN);

// Export as plain text
const plain = logger.export(OutputFormatEnum.PLAIN);

// Save to file or send to server
await fetch('/api/logs', {
  method: 'POST',
  body: json,
});

HTML Formatter

import { HTMLFormatter } from '@sldm/debug/formatters';

const formatter = new HTMLFormatter();
const entries = logger.getEntries();
const html = formatter.formatBatch(entries);

// Write to file or display in iframe
document.getElementById('debug-panel').innerHTML = html;

Performance Monitoring

Performance Monitor

import { PerformanceMonitor } from '@sldm/debug';

const perfMonitor = new PerformanceMonitor();

// Mark points in time
perfMonitor.mark('start-render');
// ... rendering code
perfMonitor.mark('end-render');

// Measure between marks
const measurement = perfMonitor.measure('render', 'start-render', 'end-render');
console.log(`Render took ${measurement.duration}ms`);

// Measure function execution
const data = perfMonitor.measureSync('fetch-data', () => {
  return fetchDataFromAPI();
});

// Measure async
const result = await perfMonitor.measureAsync('async-operation', async () => {
  return await someAsyncOperation();
});

// Get performance summary
const summary = perfMonitor.getSummary();
console.log(`Average: ${summary.average}ms`);
console.log(`Min: ${summary.min}ms, Max: ${summary.max}ms`);

FPS Monitor

import { FPSMonitor } from '@sldm/debug';

const fpsMonitor = new FPSMonitor();
fpsMonitor.start();

setInterval(() => {
  console.log(`FPS: ${fpsMonitor.getFPS()}`);
}, 1000);

// Stop when done
fpsMonitor.stop();

Memory Monitor

import { MemoryMonitor } from '@sldm/debug';

const memMonitor = new MemoryMonitor();
const usage = memMonitor.getUsage();

if (usage) {
  console.log(
    `Memory: ${memMonitor.formatBytes(usage.used)} / ${memMonitor.formatBytes(usage.total)}`
  );
  console.log(`Usage: ${usage.percentage.toFixed(2)}%`);
}

Reactive Debugging

Track Signal Changes

import { ReactiveDebugger } from '@sldm/debug';

const reactiveDebugger = new ReactiveDebugger();

// In your reactive system:
const signal = createSignal(0);

// Track creation
reactiveDebugger.trackCreate('count', signal());

// Track updates
signal.subscribe((newValue, oldValue) => {
  reactiveDebugger.trackUpdate('count', oldValue, newValue);
});

// Get history
const history = reactiveDebugger.getHistory('count');

// Get summary
const summary = reactiveDebugger.getSummary();
console.log(`Total signals: ${summary.totalSignals}`);
console.log(`Total changes: ${summary.totalChanges}`);

Time Travel Debugging

import { TimeTravelDebugger } from '@sldm/debug';

const timeTravel = new TimeTravelDebugger();

// Take snapshots of state
const state = new Map([['count', 0]]);
timeTravel.snapshot(state);

// Make changes
state.set('count', 1);
timeTravel.snapshot(state);

state.set('count', 2);
timeTravel.snapshot(state);

// Travel back
const previousState = timeTravel.undo();
console.log(previousState); // count: 1

// Travel forward
const nextState = timeTravel.redo();
console.log(nextState); // count: 2

// Jump to specific snapshot
const snapshots = timeTravel.getSnapshots();
timeTravel.jumpTo(0); // Go to first snapshot

Component Tree

import { ComponentTree } from '@sldm/debug';

const tree = new ComponentTree();

// Register components
tree.registerComponent('root', 'App', 'component');
tree.registerComponent('header', 'Header', 'component', 'root');
tree.registerComponent('nav', 'Navigation', 'component', 'header');
tree.registerComponent('main', 'Main', 'component', 'root');

// Get ASCII visualization
console.log(tree.toASCII());
// └─ App
//    ├─ Header
//    │  └─ Navigation
//    └─ Main

// Get as Mermaid diagram
console.log(tree.toMermaid());

// Get statistics
const stats = tree.getStatistics();
console.log(`Total components: ${stats.totalNodes}`);
console.log(`Tree depth: ${stats.depth}`);

// Find components
const navs = tree.findByType('navigation');
const headers = tree.findByName('Header');

Debug API

Create API Server

import { createLogger, DebugStream } from '@sldm/debug';
import { createDebugAPI } from '@sldm/debug/server';

const logger = createLogger();
const stream = new DebugStream();
const api = createDebugAPI(logger, stream, {
  port: 9229,
  cors: true,
});

// Use with service worker or server framework
const handler = api.createHandler();

// Example with fetch handler
addEventListener('fetch', event => {
  const url = new URL(event.request.url);
  if (url.pathname.startsWith('/debug')) {
    event.respondWith(handler(event.request));
  }
});

API Endpoints

  • GET /logs - Get all logs (query params: level, namespace, limit)
  • GET /logs/stream - Stream logs via SSE
  • POST /logs/clear - Clear all logs
  • GET /health - Health check

Example API Usage

# Get logs
curl http://localhost:9229/logs?level=2&limit=50

# Stream logs
curl http://localhost:9229/logs/stream

# Clear logs
curl -X POST http://localhost:9229/logs/clear

Advanced Usage

Comprehensive Debug Instance

import { createDebug } from '@sldm/debug';

const debug = await createDebug({
  loggerConfig: {
    level: LogLevelEnum.DEBUG,
    namespace: 'app',
  },
  enablePerformance: true,
  enableReactive: true,
  enableComponentTree: true,
});

// Access all utilities
debug.logger.info('Application started');
debug.performance?.mark('init');
debug.reactive?.trackCreate('state', initialState);
debug.componentTree?.registerComponent('root', 'App', 'component');
debug.fps?.start();

Persistent Logs

const logger = createLogger({
  persistent: true, // Save logs to localStorage
  maxEntries: 1000,
});

// Logs survive page reloads
logger.info('This will be persisted');

TypeScript Support

Full TypeScript support with type definitions:

import type {
  LogEntry,
  LogLevel,
  PerformanceEntry,
  StateChangeEvent,
  ComponentNode,
} from '@sldm/debug';

License

MIT © Matthias Kluth