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

nx-troubleshooting

v2.0.1

Published

Generic troubleshooting engine for matching errors to solutions

Readme

nx-troubleshooting

Generic troubleshooting engine for matching errors to solutions

npm version License: ISC

nx-troubleshooting is a generic, reusable npm package that provides intelligent error-to-solution matching for any Node.js/TypeScript project. It loads troubleshooting narratives from JSON files, matches errors to relevant solutions based on configurable symptoms, and formats helpful guidance for developers.

Features

  • 🎯 Intelligent Error Matching - Matches errors to solutions using multiple strategies (error name, keywords, symptom evaluation)
  • 🔍 Flexible Probe System - Built-in probes plus extensible custom probes for project-specific checks
  • 📝 Template Variables - Dynamic solution messages with {{variable}} syntax and nested access
  • 📊 Multiple Output Formats - Markdown, JSON, and plain text formatting
  • 🛠️ Generic Probe Toolbox - Additional probes for common scenarios (file system, environment, config types)
  • 🔌 Framework Agnostic - Works with any Node.js/TypeScript project
  • 📦 Zero Dependencies - Only uses Node.js built-ins (plus optional nx-config2 for enhanced features)

Installation

npm install nx-troubleshooting

Quick Start

import { TroubleshootingEngine } from 'nx-troubleshooting';

// Initialize engine
const engine = new TroubleshootingEngine({
  narrativesPath: './metadata/troubleshooting.json'
});

// Load narratives
await engine.loadNarratives();

// Match an error
const error = new Error('Missing connections configuration');
const matches = await engine.matchError(error, {
  error,
  config: { /* your config */ },
  query: { /* your query */ }
});

// Format results
const markdown = engine.formatMatches(matches, 'markdown');
console.log(markdown);

Core Concepts

Troubleshooting Narrative

A troubleshooting narrative is a structured description of a problem and its solution:

{
  id: "missing-connections-config",
  title: "Missing Connections Configuration",
  description: "The application config is missing the required 'connections' object...",
  symptoms: [
    {
      probe: "config-check",
      params: { field: "connections" },
      condition: "result.exists == false"
    }
  ],
  solution: [
    {
      type: "code",
      message: "Add a 'connections' object to your config:",
      code: "{\n  \"connections\": { ... }\n}"
    }
  ]
}

Symptoms

Symptoms define how to detect a problem using probes:

  • Probe: A function that checks a condition (e.g., config-check, file-exists)
  • Params: Parameters passed to the probe
  • Condition: JavaScript expression evaluated against the probe result

Solutions

Solutions provide guidance on how to resolve the issue:

  • Type: Solution type (e.g., collaborate, link, code)
  • Message: Solution message (supports template variables)
  • URL: Optional URL for link type solutions
  • Code: Optional code example for code type solutions

API Reference

TroubleshootingEngine

Main class that handles loading narratives and matching errors.

class TroubleshootingEngine {
  constructor(options?: {
    narrativesPath?: string;           // Path to JSON file or directory
    customProbes?: ProbeRegistry;       // Custom probe functions
    templateVars?: Record<string, any>; // Default template variables
    envPrefix?: string;                 // Environment variable prefix
  });

  // Load narratives from JSON file(s)
  loadNarratives(path?: string): Promise<void>;
  
  // Load narratives from in-memory array
  loadNarrativesFromArray(narratives: TroubleshootingNarrative[]): void;
  
  // Match an error to relevant narratives
  matchError(error: Error, context?: ErrorContext): Promise<TroubleshootingMatch[]>;
  
  // Match based on custom criteria
  match(context: MatchContext): Promise<TroubleshootingMatch[]>;
  
  // Format matched narratives for display
  formatMatches(matches: TroubleshootingMatch[], format?: 'markdown' | 'json' | 'text'): string;
  
  // Get all loaded narratives
  getNarratives(): TroubleshootingNarrative[];
  
  // Get narrative by ID
  getNarrative(id: string): TroubleshootingNarrative | undefined;
  
  // Register a custom probe
  registerProbe(name: string, probe: ProbeFunction): void;
  
  // Get current probe registry
  getProbeRegistry(): ProbeRegistry;
}

Built-in Probes

The package provides several built-in probes:

error-message

Check if error message contains keywords:

{
  probe: "error-message",
  params: { keywords: ["missing", "connection"] },
  condition: "result.matches == true"
}

error-name

Check if error name matches:

{
  probe: "error-name",
  params: { name: "ValidationError" },
  condition: "result.matches == true"
}

config-check

Check if config field exists:

{
  probe: "config-check",
  params: { field: "connections.database", required: true },
  condition: "result.exists == false"
}

file-exists

Check if file exists:

{
  probe: "file-exists",
  params: { path: "./config.json" },
  condition: "result.exists == false"
}

Generic Probe Toolbox

Additional probes available via probeToolbox:

fs-path-status

Check file system path status:

import { probeToolbox } from 'nx-troubleshooting';

engine.registerProbe('fs-path-status', probeToolbox['fs-path-status']);

// Usage in narrative:
{
  probe: "fs-path-status",
  params: { targetPath: "./config.json" },
  condition: "result.exists == false || result.isDirectory == true"
}

env-runtime-info

Get Node.js runtime information:

{
  probe: "env-runtime-info",
  params: {},
  condition: "result.nodeVersion.startsWith('v18') == false"
}

env-var-check

Check environment variable:

{
  probe: "env-var-check",
  params: { name: "DATABASE_URL", requireNonEmpty: true },
  condition: "result.exists == false || result.nonEmpty == false"
}

config-field-type

Check config field type:

{
  probe: "config-field-type",
  params: { field: "port", type: "number" },
  condition: "result.exists == false || result.typeMatches == false"
}

Custom Probes

Register project-specific probes:

const engine = new TroubleshootingEngine({
  customProbes: {
    'mongodb-connect': async (params, context) => {
      try {
        const client = await MongoClient.connect(params.uri);
        await client.close();
        return { ok: true };
      } catch (error) {
        return { ok: false, error: error.message };
      }
    },
    'binding-check': (params, context) => {
      const bindings = context.config?.bindings || [];
      const found = bindings.some(b => b.connection === params.bindingConnection);
      return { found };
    }
  }
});

// Or register after construction:
engine.registerProbe('custom-probe', (params, context) => {
  // Your custom logic
  return { result: 'value' };
});

Template Variables

Solution messages support template variables using {{variable}} syntax:

{
  "message": "Your config is missing '{{query.binding.connection}}'. Available: {{availableConnections}}"
}

Template variables are resolved from:

  1. ErrorContext properties
  2. Custom templateVars passed to constructor
  3. Probe results (via result.*)
  4. Nested object access (e.g., query.binding.connection)

Fallback Values

Use || for fallbacks:

{
  "message": "Port: {{config.port||3000}}"
}

Finding and Creating Troubleshooting Narratives

Where to Find Existing Narratives

  1. Error Logs & Stack Traces

    • Review production error logs
    • Check test failures
    • Analyze user-reported issues
  2. Common Error Patterns

    • Configuration errors
    • Missing dependencies
    • Connection failures
    • Validation errors
  3. Support Tickets

    • Frequently asked questions
    • Common user mistakes
    • Setup issues
  4. Code Review

    • Error handling patterns
    • Validation logic
    • Configuration requirements

How to Create a Troubleshooting Narrative

Step 1: Identify the Problem

Start with a real error scenario:

// Error: "Missing connections configuration"
// Stack trace shows: ConfigError at line 42
// Context: config.connections is undefined

Step 2: Define Symptoms

Think about what conditions indicate this problem:

{
  "symptoms": [
    {
      "probe": "config-check",
      "params": { "field": "connections" },
      "condition": "result.exists == false"
    },
    {
      "probe": "error-message",
      "params": { "keywords": ["missing", "connections", "configuration"] },
      "condition": "result.matches == true"
    }
  ]
}

Step 3: Write the Solution

Provide clear, actionable steps:

{
  "solution": [
    {
      "type": "code",
      "message": "Add a 'connections' object to your configuration file:",
      "code": "{\n  \"connections\": {\n    \"database\": {\n      \"mongo\": [{\n        \"alias\": \"my-mongo\",\n        \"uri\": \"mongodb://localhost:27017\",\n        \"db\": \"mydb\"\n      }]\n    }\n  }\n}"
    },
    {
      "type": "link",
      "message": "See the configuration documentation for more details:",
      "url": "https://docs.example.com/configuration"
    }
  ]
}

Step 4: Complete the Narrative

{
  "id": "missing-connections-config",
  "title": "Missing Connections Configuration",
  "description": "The application configuration is missing the required 'connections' object. This object defines database connections and other external service endpoints.",
  "possibleSolution": "Add a 'connections' object to your config file with at least one database connection.",
  "symptoms": [
    {
      "probe": "config-check",
      "params": { "field": "connections" },
      "condition": "result.exists == false"
    }
  ],
  "solution": [
    {
      "type": "code",
      "message": "Add a 'connections' object to your configuration:",
      "code": "{\n  \"connections\": {\n    \"database\": { ... }\n  }\n}"
    }
  ]
}

Best Practices for Narratives

  1. Use Descriptive IDs

    • Format: kebab-case
    • Example: missing-connections-config, invalid-api-key
  2. Clear Titles

    • Be specific and concise
    • Example: "Missing Connections Configuration" not "Config Error"
  3. Detailed Descriptions

    • Explain what the problem is
    • Include context about when it occurs
    • Example: "The application configuration is missing the required 'connections' object. This typically occurs during initial setup or when the config file is incomplete."
  4. Multiple Symptoms

    • Use multiple probes for better matching
    • Combine error message keywords with config checks
    • Example: Check both error message AND config state
  5. Actionable Solutions

    • Provide step-by-step guidance
    • Include code examples when relevant
    • Link to documentation
    • Use template variables for dynamic content
  6. Test Your Narratives

    const testError = new Error('Missing connections configuration');
    const matches = await engine.matchError(testError, {
      error: testError,
      config: {} // Missing connections
    });
    console.assert(matches.length > 0, 'Narrative should match');
    console.assert(matches[0].confidence > 0.5, 'Should have reasonable confidence');

Example Troubleshooting JSON

See examples/troubleshooting.json for a complete example with multiple narratives demonstrating best practices.

Environment Configuration

The engine supports environment-based configuration via nx-config2:

# Set narratives path
export NX_TROUBLE_NARRATIVES_PATH=./metadata/troubleshooting.json

Or configure programmatically:

const engine = new TroubleshootingEngine({
  envPrefix: 'MY_APP',
  narrativesPath: './troubleshooting.json'
});

Integration Examples

In a Test Framework

async function generateBugReport(error: Error, context: ErrorContext) {
  const engine = new TroubleshootingEngine({
    narrativesPath: './metadata/troubleshooting.json'
  });
  await engine.loadNarratives();
  
  const matches = await engine.matchError(error, context);
  const troubleshooting = engine.formatMatches(matches, 'markdown');
  
  return {
    error: {
      name: error.name,
      message: error.message,
      stack: error.stack
    },
    context,
    troubleshooting
  };
}

In an Express Error Handler

import { TroubleshootingEngine } from 'nx-troubleshooting';

const engine = new TroubleshootingEngine({
  narrativesPath: './troubleshooting.json'
});
await engine.loadNarratives();

app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
  engine.matchError(err, {
    error: err,
    config: app.get('config'),
    query: req.query,
    operation: req.method
  }).then(matches => {
    const troubleshooting = engine.formatMatches(matches, 'markdown');
    res.status(500).json({
      error: err.message,
      troubleshooting
    });
  });
});

With Custom Probes and Template Variables

const engine = new TroubleshootingEngine({
  narrativesPath: './troubleshooting.json',
  customProbes: {
    'database-connection': async (params, context) => {
      // Check database connection
      return { connected: true, latency: 42 };
    }
  },
  templateVars: {
    supportEmail: '[email protected]',
    documentationUrl: 'https://docs.example.com'
  }
});

// Narratives can use {{supportEmail}} and {{documentationUrl}}

Output Formats

Markdown

## 🔧 Troubleshooting Help

### 1. Missing Connections Configuration

The application configuration is missing the required 'connections' object...

**Quick hint**: Add a 'connections' object to your config file

**Suggested steps:**
- (code) Add a 'connections' object to your configuration:

```json
{
  "connections": {
    "database": { ... }
  }
}

### JSON

```json
{
  "matches": [
    {
      "narrative": { /* full narrative */ },
      "confidence": 0.9,
      "matchedSymptoms": [ /* matched symptoms */ ],
      "context": { /* matching context */ }
    }
  ]
}

Text

(1) Missing Connections Configuration [90%]
The application configuration is missing the required 'connections' object...
Hint: Add a 'connections' object to your config file
- code: Add a 'connections' object to your configuration:

Matching Algorithm

The engine matches errors using:

  1. Error Name Matching - Exact match with narrative ID or title (confidence: 1.0)
  2. Keyword Matching - Keywords from error message matched against narrative title/description (confidence: 0.7-0.9)
  3. Symptom Evaluation - All symptoms evaluated, confidence based on match ratio (confidence: 0.5-0.8)
  4. Sorting - Results sorted by confidence (highest first)

TypeScript Support

Full TypeScript definitions are included:

import {
  TroubleshootingEngine,
  TroubleshootingNarrative,
  ErrorContext,
  MatchContext,
  TroubleshootingMatch,
  ProbeFunction,
  ProbeRegistry
} from 'nx-troubleshooting';

Contributing

Contributions are welcome! Please see the contributing guide for details.

License

ISC

Related Packages

  • nx-config2 - Configuration management (used for env config)

Made with ❤️ by nx-intelligence