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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@rachelallyson/stratum-event-counter-plugin

v1.0.11

Published

A Stratum plugin for event counting and file logging.

Downloads

38

Readme

@rachelallyson/stratum-event-counter-plugin

A development and testing plugin for Stratum that tracks event counts and provides a real-time dashboard.

Quick Start

1. Install the Plugin

npm install @rachelallyson/stratum-event-counter-plugin

2. Start the Dashboard Server

# Start on default port (41321)
npx @rachelallyson/stratum-event-counter-plugin

# Or start on a custom port
EVENT_COUNTER_PORT=3000 npx @rachelallyson/stratum-event-counter-plugin

3. Add the Plugin to Your App

import { StratumService } from "@capitalone/stratum-observability";
import { EventCounterPluginFactory } from "@rachelallyson/stratum-event-counter-plugin";

// Create your event catalog
const eventCatalog = {
  "user-login": { description: "User logs in" },
  "user-logout": { description: "User logs out" },
  "page-view": { description: "User views a page" }
};

// Create the plugin
const plugin = EventCounterPluginFactory({
  catalog: eventCatalog,
  dashboardUrl: 'http://localhost:41321' // Match your dashboard port
});

// Register with Stratum
const stratumService = new StratumService({
  plugins: [plugin],
  catalog: eventCatalog,
  productName: 'myApp',
  productVersion: '1.0.0'
});

// Publish events
stratumService.publish('user-login');

4. View the Dashboard

Open your browser to http://localhost:41321 (or your custom port) to see:

  • Event counts and usage statistics
  • First and last usage timestamps
  • Search and filtering capabilities
  • Export to CSV/JSON
  • Automatic cleanup of old run files
  • Manual cleanup controls

5. Testing Integration (Optional)

For coordinated event tracking during tests, use the test utilities:

// For Node.js tests (Jest, Vitest)
import { startTestRun, endTestRun } from '@rachelallyson/stratum-event-counter-plugin/test-utils';

// For browser tests (Cypress, Playwright)  
import { startTestRun, endTestRun } from '@rachelallyson/stratum-event-counter-plugin/test-utils-browser';

beforeEach(async () => {
  await startTestRun({ prefix: 'my-test' });
});

afterEach(async () => {
  await endTestRun();
});

This ensures all events from your app during testing are tracked under coordinated run IDs.

Configuration Options

Plugin Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | dashboardUrl | string | 'http://localhost:41321' | URL where dashboard server is running | | catalog | object | {} | Your event catalog (required for dashboard) | | enableLogging | boolean | false | Enable debug logging for publisher | | allowedEvents | string[] | 'all' | 'all' | Filter which eventTypes to track. Use 'all' to track any eventType, or provide an array of specific eventTypes (like ['base', 'error']) that match the eventType property in your catalog |

Dashboard Server Environment Variables

| Variable | Type | Default | Description | |----------|------|---------|-------------| | EVENT_COUNTER_PORT | number | 41321 | Dashboard server port | | EVENT_COUNTER_MAX_RUNS | number | 25 | Maximum number of runs to keep (oldest are automatically removed) |

📖 For detailed configuration options and advanced patterns, see Configuration Guide

Event Filtering

The plugin supports filtering which eventTypes to track using the allowedEvents configuration option. This filters events based on the eventType property defined in your Stratum catalog. This is useful for focusing on specific event types during development or testing.

Note: The plugin accesses the eventType from the Stratum BaseEventModel's direct eventType property, which is automatically set from your catalog's eventType definition.

Track All Event Types (Default)

// Track any eventType (default behavior)
const plugin = EventCounterPluginFactory({
  catalog: {
    'user-login': { eventType: 'base', description: 'User logs in', id: 1 },
    'api-error': { eventType: 'error', description: 'API error occurred', id: 2 },
    'debug-info': { eventType: 'debug', description: 'Debug information', id: 3 }
  },
  allowedEvents: 'all' // or omit this option entirely
});

// All these eventTypes will be tracked
stratumService.publish('user-login');  // ✅ Tracked (eventType: 'base')
stratumService.publish('api-error');   // ✅ Tracked (eventType: 'error')  
stratumService.publish('debug-info');  // ✅ Tracked (eventType: 'debug')

Track Specific Event Types Only

// Only track specific eventTypes from your catalog
const plugin = EventCounterPluginFactory({
  catalog: {
    'user-login': { eventType: 'base', description: 'User logs in', id: 1 },
    'api-error': { eventType: 'error', description: 'API error occurred', id: 2 },
    'debug-info': { eventType: 'debug', description: 'Debug information', id: 3 },
    'trace-data': { eventType: 'trace', description: 'Trace information', id: 4 }
  },
  allowedEvents: ['base', 'error'] // Only track base and error eventTypes
});

// Only allowed eventTypes will be tracked
stratumService.publish('user-login');  // ✅ Tracked (eventType: 'base')
stratumService.publish('api-error');   // ✅ Tracked (eventType: 'error')
stratumService.publish('debug-info');  // ❌ Not tracked (eventType: 'debug')
stratumService.publish('trace-data');  // ❌ Not tracked (eventType: 'trace')

Use Cases for Event Type Filtering

Development Focus:

// Focus on base application events during feature development
const plugin = EventCounterPluginFactory({
  catalog: eventCatalog,
  allowedEvents: ['base'] // Only track core application events
});

Error Tracking:

// Track only errors and warnings during debugging
const plugin = EventCounterPluginFactory({
  catalog: eventCatalog,  
  allowedEvents: ['error', 'warning'] // Only track error conditions
});

Production Monitoring:

// Track only critical events in production
const plugin = EventCounterPluginFactory({
  catalog: eventCatalog,
  allowedEvents: ['base', 'error', 'performance'] // Essential events only
});

Common Usage Patterns

Development with Custom Port

// Plugin posts to port 3000
const plugin = EventCounterPluginFactory({
  dashboardUrl: 'http://localhost:3000',
  catalog: eventCatalog
});

// Start dashboard on port 3000
// Terminal: EVENT_COUNTER_PORT=3000 npx @rachelallyson/stratum-event-counter-plugin

Browser Testing (Cypress/Playwright)

// Plugin posts to test server
const plugin = EventCounterPluginFactory({
  dashboardUrl: 'http://localhost:3001',
  catalog: eventCatalog
});

// Test server runs dashboard on port 3001
// Your test framework controls the test server

Default Configuration

// Uses default dashboard URL (http://localhost:41321)
const plugin = EventCounterPluginFactory({
  catalog: eventCatalog
});

// Start dashboard with default port
// Terminal: npx @rachelallyson/stratum-event-counter-plugin

Testing with Automatic Coordination

// App configuration (no run ID management needed)
const plugin = EventCounterPluginFactory({
  dashboardUrl: 'http://localhost:41321',
  catalog: eventCatalog
});

// Test setup - coordinates with app automatically
import { startTestRun, endTestRun } from '@rachelallyson/stratum-event-counter-plugin/test-utils';

beforeEach(async () => {
  await startTestRun({ prefix: 'test' });
});

// All app events during tests automatically use the test run ID
// No manual coordination required!

Event Catalog Format

Your event catalog should be an object where each key is an event name:

{
  "user-login": {
    "description": "User logs in to the application"
  },
  "user-logout": {
    "description": "User logs out of the application"
  },
  "page-view": {
    "description": "User views a page"
  }
}

Data Management

The plugin automatically manages data files to prevent the data folder from getting cluttered:

Automatic Cleanup

  • Startup cleanup: Old run files are automatically removed when the server starts
  • Runtime cleanup: When posting new events, if the number of runs exceeds EVENT_COUNTER_MAX_RUNS, the oldest runs are removed
  • Catalog cleanup: When a run is removed, its corresponding catalog file is also removed

Manual Cleanup

  • Dashboard button: Use the "Cleanup Old Runs" button in the dashboard
  • API endpoint: Call POST /api/cleanup to manually trigger cleanup
  • Status check: Call GET /api/cleanup to check if cleanup is needed

File Organization

  • Per-run storage: Each run gets its own stats and catalog files
  • Default run: The default run uses event-stats.json and event-catalog.json
  • Named runs: Other runs use event-stats-{runId}.json and event-catalog-{runId}.json

Test Integration

The plugin provides comprehensive test utilities for coordinating run IDs across your tests and application, enabling seamless event tracking during test execution.

Quick Setup for Testing

npm install @rachelallyson/stratum-event-counter-plugin

For Node.js environments (Jest, Vitest, etc.):

import { startTestRun, endTestRun } from '@rachelallyson/stratum-event-counter-plugin/test-utils';

describe('My Tests', () => {
  beforeEach(async () => {
    await startTestRun({ prefix: 'jest' });
  });

  afterEach(async () => {
    await endTestRun();
  });

  it('should track events automatically', async () => {
    // Your app events are automatically tracked with the test run ID
    await myApp.doSomething(); // Events published here are coordinated
  });
});

For browser environments (Cypress, Playwright, etc.):

import { startTestRun, endTestRun } from '@rachelallyson/stratum-event-counter-plugin/test-utils-browser';

describe('My Tests', () => {
  beforeEach(async () => {
    await startTestRun({ prefix: 'cypress' });
  });

  afterEach(async () => {
    await endTestRun();
  });
});

Cross-Process Run Coordination

The plugin automatically coordinates run IDs between your tests and application:

  • Set active run ID from your tests using test utilities
  • App events automatically use the active run ID - no manual coordination needed
  • No run ID passing required in your application code
  • Each test run gets isolated data automatically
// Your application code - no changes needed!
const plugin = EventCounterPluginFactory({
  dashboardUrl: 'http://localhost:41321',
  catalog: eventCatalog
});

// Events automatically use the active run ID set by tests
stratumService.publish('user-login'); // Tracked under test run ID

Testing Framework Examples

Cypress Global Run ID (all tests share same ID):

// cypress.config.ts
import { defineConfig } from 'cypress';

export default defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      let currentRunId = null;

      on('before:run', async () => {
        const { startTestRun } = await import('@rachelallyson/stratum-event-counter-plugin/test-utils');
        currentRunId = await startTestRun({ prefix: 'cypress' });
      });

      on('after:run', async () => {
        if (currentRunId) {
          const { endTestRun } = await import('@rachelallyson/stratum-event-counter-plugin/test-utils');
          await endTestRun();
        }
      });
    }
  }
});

Jest/Vitest Setup:

// jest.setup.js or vitest.setup.js
import { startTestRun, endTestRun } from '@rachelallyson/stratum-event-counter-plugin/test-utils';

beforeEach(async () => {
  await startTestRun({ prefix: 'jest' });
});

afterEach(async () => {
  await endTestRun();
});

Playwright Setup:

// playwright.config.js
import { test } from '@playwright/test';
import { startTestRun, endTestRun } from '@rachelallyson/stratum-event-counter-plugin/test-utils-browser';

test.beforeEach(async () => {
  await startTestRun({ prefix: 'playwright' });
});

test.afterEach(async () => {
  await endTestRun();
});

Available Test Utility Functions

Simple Functions (Recommended):

// Start a test run (generates ID, sets it active, resets stats)
const runId = await startTestRun({
  prefix: 'my-test',     // Optional: prefix for run ID (default: 'test')
  resetStats: true,      // Optional: reset stats (default: true)
  dashboardUrl: 'http://localhost:41321'  // Optional: dashboard URL
});

// End the test run (clears active run ID)
await endTestRun();

Manual Functions (Advanced):

// Generate a run ID
const runId = generateRunId('my-prefix');

// Set active run ID (all events without explicit run ID will use this)
await setActiveRunId(runId);

// Get current active run ID
const currentRunId = await getActiveRunId(); // returns string or null

// Reset stats for a run
await resetRunStats(runId);

// Clear active run ID
await clearActiveRunId();

API Endpoints

The dashboard server provides these endpoints:

Core Dashboard

  • GET / - Dashboard HTML

Event Statistics

  • GET /api/events-stats - Get event statistics (uses active run ID if no statsId provided)
  • POST /api/events-stats - Update event statistics (uses active run ID if no statsId provided)
  • PUT /api/events-stats - Reset event statistics

Run Coordination

  • GET /api/active-run-id - Get current active run ID
  • POST /api/active-run-id - Set active run ID for cross-process coordination
  • DELETE /api/active-run-id - Clear active run ID

Catalog Management

  • GET /api/catalog - Get event catalog for a run
  • POST /api/catalog - Update event catalog for a run

Run Management

  • GET /api/runs - List available runs
  • GET /api/cleanup - Get cleanup status
  • POST /api/cleanup - Manually trigger cleanup of old runs

Development

# Install dependencies
npm install

# Build the project
npm run build

# Start dashboard server
npm run server

# Run in development mode
npm run dev

# Run tests
npm test

Testing

# Unit tests
npm run test:unit

# E2E tests
npm run test:e2e

# Watch mode
npm run test:watch

Production Considerations

Note: This plugin is designed for development and testing. For production:

  1. Use standard plugin integration without dashboard features
  2. Consider separate monitoring solutions for production observability
  3. The dashboard server is not intended for production deployment

Troubleshooting

Dashboard Not Loading

  1. Check the port: Make sure your plugin's dashboardUrl matches the dashboard server port
  2. Start the server: Ensure the dashboard server is running via CLI
  3. Check for conflicts: Make sure the port isn't used by another application

Events Not Appearing

  1. Check logging: Enable enableLogging: true to see debug output
  2. Verify URL: Ensure dashboardUrl points to the correct server
  3. Check network: Verify the plugin can reach the dashboard server

Port Conflicts

  1. Use different ports: Set EVENT_COUNTER_PORT to an available port
  2. Update plugin config: Change dashboardUrl to match the new port
  3. Check running processes: Make sure no other service is using the port

Test Integration Issues

  1. Fetch not available: For Node.js < 18, install npm install node-fetch
  2. Test utilities not found: Ensure you're using the correct import path:
    • Node.js: from '@rachelallyson/stratum-event-counter-plugin/test-utils'
    • Browser: from '@rachelallyson/stratum-event-counter-plugin/test-utils-browser'
  3. Run ID not coordinating: Make sure the dashboard server is running before starting tests
  4. Events not tracked: Verify your app's dashboardUrl matches the test dashboard server

Philosophy

For detailed information about the plugin's design principles and architectural decisions, see PHILOSOPHY.md.

Debugging Event Type Filtering

If eventType filtering isn't working in your live app, enable logging to debug:

const plugin = EventCounterPluginFactory({
  catalog: yourCatalog,
  allowedEvents: ['authentication', 'business'], // Your desired filter
  enableLogging: true // Enable debug logging
});

Check the browser console for messages like:

[EventCounterPublisher] shouldPublishEvent called with: BaseEventModel {...}
[EventCounterPublisher] event.eventType: authentication
[EventCounterPublisher] allowedEvents setting: ['authentication', 'business']
[EventCounterPublisher] EventType 'authentication' allowed: true

Common Issues

  1. eventType not found: Check that your catalog has eventType defined
  2. shouldPublishEvent not called: Verify the plugin is registered with Stratum
  3. Wrong eventType values: Ensure allowedEvents matches your catalog's eventType values

Test Your Setup

// Minimal test setup
const testCatalog = {
  'test-event': { eventType: 'business', description: 'Test event', id: 1 }
};

const plugin = EventCounterPluginFactory({
  catalog: testCatalog,
  allowedEvents: ['business'],
  enableLogging: true
});

// This should trigger filtering logic
stratumService.publish('test-event');

Building Rich Catalogs with Multiple Event Types

The plugin supports any eventTypes you define in your Stratum catalog. Here's an example of a comprehensive catalog with many different eventTypes:

// Example catalog with various eventTypes for different purposes
const comprehensiveCatalog = {
  // User interaction events
  'user-login': { eventType: 'authentication', description: 'User successfully logs in', id: 1 },
  'user-logout': { eventType: 'authentication', description: 'User logs out', id: 2 },
  'password-reset': { eventType: 'authentication', description: 'User requests password reset', id: 3 },
  
  // Business logic events  
  'order-created': { eventType: 'business', description: 'New order is created', id: 10 },
  'payment-processed': { eventType: 'business', description: 'Payment successfully processed', id: 11 },
  'invoice-generated': { eventType: 'business', description: 'Invoice generated for order', id: 12 },
  
  // System performance events
  'api-response-time': { eventType: 'performance', description: 'API response time measurement', id: 20 },
  'database-query': { eventType: 'performance', description: 'Database query execution', id: 21 },
  'cache-hit': { eventType: 'performance', description: 'Cache hit occurred', id: 22 },
  
  // Error and warning events
  'api-error': { eventType: 'error', description: 'API request failed', id: 30 },
  'validation-error': { eventType: 'error', description: 'Data validation failed', id: 31 },
  'timeout-warning': { eventType: 'warning', description: 'Operation timeout warning', id: 32 },
  
  // Debug and diagnostic events
  'debug-trace': { eventType: 'debug', description: 'Debug trace information', id: 40 },
  'state-change': { eventType: 'debug', description: 'Application state change', id: 41 },
  'config-loaded': { eventType: 'debug', description: 'Configuration loaded', id: 42 },
  
  // Analytics and tracking
  'page-view': { eventType: 'analytics', description: 'Page view tracked', id: 50 },
  'button-click': { eventType: 'analytics', description: 'Button click tracked', id: 51 },
  'feature-usage': { eventType: 'analytics', description: 'Feature usage tracked', id: 52 },
  
  // Security events
  'security-alert': { eventType: 'security', description: 'Security alert triggered', id: 60 },
  'failed-login': { eventType: 'security', description: 'Failed login attempt', id: 61 },
  'suspicious-activity': { eventType: 'security', description: 'Suspicious activity detected', id: 62 }
};

// Configure plugin to track specific eventTypes
const plugin = EventCounterPluginFactory({
  catalog: comprehensiveCatalog,
  allowedEvents: ['business', 'error', 'security'] // Only track critical eventTypes
});

Filtering Examples with Multiple Event Types

// Track all business and authentication events
const businessPlugin = EventCounterPluginFactory({
  catalog: comprehensiveCatalog,
  allowedEvents: ['business', 'authentication']
});

// Track only error and security events for monitoring
const monitoringPlugin = EventCounterPluginFactory({
  catalog: comprehensiveCatalog,
  allowedEvents: ['error', 'warning', 'security']
});

// Track performance and debug events for optimization
const performancePlugin = EventCounterPluginFactory({
  catalog: comprehensiveCatalog,
  allowedEvents: ['performance', 'debug']
});

// Track user-facing events for analytics
const analyticsPlugin = EventCounterPluginFactory({
  catalog: comprehensiveCatalog,
  allowedEvents: ['analytics', 'authentication', 'business']
});

// Development mode - track everything
const developmentPlugin = EventCounterPluginFactory({
  catalog: comprehensiveCatalog,
  allowedEvents: 'all'
});

Dynamic Event Type Selection

// Environment-based eventType filtering
const getEventTypesForEnvironment = (env) => {
  switch (env) {
    case 'production':
      return ['business', 'error', 'security']; // Critical events only
    case 'staging':
      return ['business', 'error', 'warning', 'performance']; // Add performance monitoring
    case 'development':
      return 'all'; // Track everything during development
    case 'testing':
      return ['business', 'error']; // Focus on core functionality
    default:
      return ['error']; // Minimal fallback
  }
};

const plugin = EventCounterPluginFactory({
  catalog: comprehensiveCatalog,
  allowedEvents: getEventTypesForEnvironment(process.env.NODE_ENV)
});

Custom Event Types for Your Domain

// E-commerce specific eventTypes
const ecommerceCatalog = {
  'product-viewed': { eventType: 'product', description: 'Product page viewed', id: 1 },
  'cart-updated': { eventType: 'cart', description: 'Shopping cart updated', id: 2 },
  'checkout-started': { eventType: 'checkout', description: 'Checkout process started', id: 3 },
  'payment-failed': { eventType: 'payment', description: 'Payment processing failed', id: 4 },
  'order-shipped': { eventType: 'fulfillment', description: 'Order shipped to customer', id: 5 }
};

// SaaS application eventTypes
const saasCatalog = {
  'feature-enabled': { eventType: 'feature', description: 'Feature flag enabled', id: 1 },
  'subscription-upgraded': { eventType: 'subscription', description: 'User upgraded subscription', id: 2 },
  'api-key-generated': { eventType: 'integration', description: 'API key generated', id: 3 },
  'usage-limit-reached': { eventType: 'billing', description: 'Usage limit reached', id: 4 },
  'webhook-sent': { eventType: 'notification', description: 'Webhook notification sent', id: 5 }
};