Inspector Package

npm downloads

The @hazeljs/inspector package provides a framework-aware runtime inspector for HazelJS applications. With one line of code and zero instrumentation, it exposes your entire app—routes, cron jobs, agents, flows, circuit breakers, and more—in a unified dashboard at /__hazel.

Purpose

Understanding a complex application often requires grepping through code, tracing imports, and maintaining stale documentation. The Inspector solves this by:

  • Zero Instrumentation: Discovers everything from framework metadata and decorators—no manual registration
  • Framework-Aware: Speaks HazelJS natively. Knows @Controller, @Cron, @Agent, @Flow, @RAG, and more
  • One Dashboard: Routes, modules, jobs, agents, AI functions, RAG pipelines, GraphQL, gRPC, Kafka, flows—all in one place
  • Development-First: Disabled in production by default; explicit opt-in required for production use

Architecture

The Inspector uses a plugin-based architecture. Each HazelJS package (cron, agent, rag, etc.) has an optional inspector plugin that runs only when that package is installed:

graph TD
  A["InspectorModule.forRoot()"] --> B["HazelInspectorRegistry"]
  B --> C["Plugin System"]
  C --> D["Core Plugin<br/>(Routes, Modules, Providers)"]
  C --> E["Cron Plugin"]
  C --> F["Agent Plugin"]
  C --> G["RAG Plugin"]
  C --> H["Flow Plugin"]
  C --> I["... 15+ Plugins"]
  B --> J["HazelInspectorService"]
  J --> K["Snapshot API<br/>(JSON + UI)"]
  
  style A fill:#8b5cf6,stroke:#a78bfa,stroke-width:2px,color:#fff
  style B fill:#3b82f6,stroke:#60a5fa,stroke-width:2px,color:#fff
  style J fill:#3b82f6,stroke:#60a5fa,stroke-width:2px,color:#fff
  style K fill:#10b981,stroke:#34d399,stroke-width:2px,color:#fff

Key Components

  1. InspectorModule — Registers the inspector with your app and configures base path, UI, and security
  2. HazelInspectorRegistry — Plugin registry; each plugin inspects a specific category (routes, cron, agents, etc.)
  3. HazelInspectorService — Aggregates plugin output into a snapshot, serves JSON API and UI
  4. InspectorRuntime — Global registry for Gateway, Discovery, and Resilience instances (optional integration)

What You Can Inspect

CategoryWhat You Get
FrameworkRoutes (method, path, guards, interceptors), modules (imports, providers), providers, decorators
ScheduledCron jobs with expressions, next run times, enabled status
QueuesQueue processors, consumer names, job names
AIAgents (tools, model), AI functions, RAG pipelines, prompts, ML models
APIsGraphQL resolvers, gRPC methods, Kafka consumers
WorkflowsFlows with visual diagrams, data pipelines
ServerlessLambda-style handlers, memory, timeout
EventsEvent listeners and event names
WebSocketsRealtime gateways, namespaces, @Subscribe handlers
InfrastructureGateway routes, discovery services, circuit breaker states (when registered)

All from decorators. All automatic.

Advantages

1. Zero Friction

InspectorModule.forRoot({ developmentOnly: true })

No middleware. No manual registration. No OpenAPI generation. Add it, run, done.

2. Framework-Aware, Not Generic

Generic APM tools treat your app like a black box. Inspector speaks HazelJS. It knows your decorators and metadata.

3. Optional Dependencies

Plugins only run when the corresponding package is installed. No need to install @hazeljs/agent if you don't use agents—the agent inspector simply won't appear.

4. Security First

  • developmentOnly: true (default) — Inspector is off in production
  • Sensitive data redactionpassword, secret, token, apiKey are redacted from metadata
  • Explicit opt-in — Production use requires developmentOnly: false and enableInspector: true

5. Extensible

Register Gateway and Discovery for service mesh overview. Add custom plugins to expose your own metadata.

Installation

npm install @hazeljs/inspector @hazeljs/core

The Inspector has optional peer dependencies. Install only the packages you use:

# Optional - for cron job inspection
npm install @hazeljs/cron

# Optional - for agent inspection
npm install @hazeljs/agent

# Optional - for RAG inspection
npm install @hazeljs/rag

# ... and so on for queue, websocket, graphql, grpc, kafka, flow, data, serverless, ml, prompts, event-emitter

Quick Start

Basic Setup

import { HazelModule } from '@hazeljs/core';
import { InspectorModule } from '@hazeljs/inspector';

@HazelModule({
  imports: [
    InspectorModule.forRoot({
      developmentOnly: true,
      inspectorBasePath: '/__hazel',
      exposeUi: true,
      exposeJson: true,
    }),
    // ... your other modules
  ],
})
export class AppModule {}

Run and Open

npm run dev

Open http://localhost:3000/__hazel. You're in.

Configuration

InspectorModuleOptions

interface InspectorModuleOptions {
  enableInspector?: boolean;        // Master switch (default: true)
  inspectorBasePath?: string;        // Base path for inspector routes (default: '/__hazel')
  exposeUi?: boolean;              // Serve the dashboard UI (default: true)
  exposeJson?: boolean;            // Expose JSON snapshot API (default: true)
  developmentOnly?: boolean;       // Disable in production (default: true)
  requireAuth?: boolean;           // Require authentication (default: false)
  enabledInspectors?: string[];    // Whitelist specific inspectors (default: [] = all)
  hiddenMetadataKeys?: string[];  // Keys to redact from metadata
  maxSnapshotCacheAgeMs?: number;  // Snapshot cache TTL (default: 5000)
}

Default Redacted Keys

The following metadata keys are redacted by default:

  • password, secret, token
  • apiKey, api_key
  • connectionString, connection_string

Override with hiddenMetadataKeys:

InspectorModule.forRoot({
  hiddenMetadataKeys: ['password', 'secret', 'myCustomSecret'],
})

Production Use

To enable the Inspector in production, you must explicitly opt in:

InspectorModule.forRoot({
  developmentOnly: false,
  enableInspector: true,
  requireAuth: true,  // Recommended: add auth middleware
})

API Endpoints

When the Inspector is enabled, it exposes the following endpoints under inspectorBasePath (default /__hazel):

EndpointMethodDescription
/GETDashboard UI (if exposeUi: true)
/snapshotGETFull JSON snapshot of all inspected entries
/routesGETRoutes only
/modulesGETModules only
/jobsGETCron jobs only
/agentsGETAgents only
/ragGETRAG pipelines only
/promptsGETPrompts only
/graphqlGETGraphQL resolvers
/grpcGETgRPC methods
/kafkaGETKafka consumers
/flowsGETFlows
/eventsGETEvent listeners
/queueGETQueue processors
/websocketGETWebSocket gateways
/rag/:pipeline/search?q=...GETRAG search (when RAG package is used)
/prompts/renderPOSTRender a prompt template (body: { key, variables })

InspectorRuntime

For service mesh and resilience overview, register your Gateway and Discovery instances:

import { InspectorRuntime } from '@hazeljs/inspector';
import { GatewayServer } from '@hazeljs/gateway';
import { DiscoveryClient } from '@hazeljs/discovery';

// After creating your gateway and discovery client:
InspectorRuntime.registerGateway(gateway);
InspectorRuntime.registerDiscovery(discovery);

The Inspector will then display:

  • Gateway Overview — Routes, total calls, success/failure rates, average response time
  • Discovery Overview — Services, instances per service, total instances
  • Resilience Overview — Circuit breaker states (CLOSED/OPEN/HALF-OPEN) when using @hazeljs/resilience

Custom Plugins

Extend the Inspector with custom plugins:

import { HazelInspectorRegistry, type HazelInspectorPlugin, type InspectorContext, type InspectorEntry } from '@hazeljs/inspector';

const myPlugin: HazelInspectorPlugin = {
  name: 'my-custom',
  version: '1.0.0',
  supports: (context) => true,
  inspect: async (context): Promise<InspectorEntry[]> => {
    return [
      {
        id: 'custom:my-entry',
        kind: 'decorator',
        packageName: '@my/package',
        sourceType: 'class',
        className: 'MyClass',
        decoratorName: '@MyDecorator',
      },
    ];
  },
};

// Register in your module's onModuleInit or similar
HazelInspectorRegistry.register(myPlugin);

Plugin Interface

interface HazelInspectorPlugin {
  name: string;
  version?: string;
  supports(context: InspectorContext): boolean;
  inspect(context: InspectorContext): Promise<InspectorEntry[]>;
}

interface InspectorContext {
  moduleType: Type<unknown>;
  container: Container;
  router: Router;
}

Snapshot Structure

The JSON snapshot returned by /snapshot has this shape:

interface InspectorSnapshot {
  collectedAt: string;  // ISO timestamp
  entries: InspectorEntry[];
  summary: Partial<Record<InspectorEntryKind, number>>;
}

Each entry has a kind (route, cron, agent, etc.) and kind-specific fields. See the contracts/types for full type definitions.

Real-World Scenarios

Onboarding — New dev opens /__hazel. Sees every route and module. Understands the app in minutes, not hours.

Debugging — "Which controller handles POST /orders?" Search. "Is that cron job enabled?" Check Jobs. "Circuit breaker state?" Check Resilience.

Refactoring — Before moving a module, see dependencies and consumers. No guesswork.

Documentation — Export snapshot as JSON. Generate docs. Assert in CI that expected routes exist.

Best Practices

  1. Keep developmentOnly: true unless you have a specific need for production inspection
  2. Use requireAuth if you enable the Inspector in production
  3. Register Gateway/Discovery when using service mesh—the overview is invaluable
  4. Export snapshots for CI assertions or automated documentation generation

What's Next?

  • Explore Cron for scheduled jobs the Inspector can display
  • Check out Agent and RAG for AI capabilities
  • Use Gateway and Discovery for service mesh overview in the Inspector
  • See Resilience for circuit breakers visible in the Inspector