HazelJS Inspector Package
@hazeljs/inspector provides a zero-instrumentation runtime dashboard for HazelJS at /__hazel — exposing routes, cron jobs, agents, flows, circuit breakers, and more.
Quick Reference
- Purpose:
@hazeljs/inspectorauto-discovers and visualizes your HazelJS application's routes, cron jobs, agents, flows, circuit breakers, and other framework entities in a live dashboard at/__hazel. - When to use: Use
@hazeljs/inspectorin development and staging to understand and debug your application. Optionally expose in production behind authentication. - Key concepts: Runtime introspection,
/__hazeldashboard, zero instrumentation, auto-discovery from framework metadata and decorators. - Dependencies:
@hazeljs/core. - Common patterns: Register
InspectorModule→ visithttp://localhost:3000/__hazel→ browse all registered routes, providers, cron jobs, agents, flows. - Common mistakes: Exposing the inspector dashboard in production without authentication; not registering
InspectorModule(dashboard won't be available).
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
- InspectorModule — Registers the inspector with your app and configures base path, UI, and security
- HazelInspectorRegistry — Plugin registry; each plugin inspects a specific category (routes, cron, agents, etc.)
- HazelInspectorService — Aggregates plugin output into a snapshot, serves JSON API and UI
- InspectorRuntime — Global registry for Gateway, Discovery, and Resilience instances (optional integration)
What You Can Inspect
| Category | What You Get |
|---|---|
| Framework | Routes (method, path, guards, interceptors), modules (imports, providers), providers, decorators |
| Scheduled | Cron jobs with expressions, next run times, enabled status |
| Queues | Queue processors, consumer names, job names |
| AI | Agents (tools, model), AI functions, RAG pipelines, prompts, ML models |
| APIs | GraphQL resolvers, gRPC methods, Kafka consumers |
| Workflows | Flows with visual diagrams, data pipelines |
| Serverless | Lambda-style handlers, memory, timeout |
| Events | Event listeners and event names |
| WebSockets | Realtime gateways, namespaces, @Subscribe handlers |
| Infrastructure | Gateway routes, discovery services, circuit breaker states (when registered) |
All from decorators. All automatic.
Agent OS Visual Timeline
With @hazeljs/agent installed, the Agents panel supports live debugging. Register @Agent classes as @Service() providers and import AgentModule so agents appear in the list and Run / Timeline resolve AgentService.
| Endpoint | Description |
|---|---|
GET /__hazel/agents/:name/stream | SSE stream of timeline steps while the agent runs |
GET /__hazel/agents/:name/timeline | JSON replay of recorded timeline steps |
POST /__hazel/agents/:name/run | Run the agent from the UI |
Click Timeline to load history and subscribe to the live feed, or Run to execute with an optional input and stream steps as they happen. Each step can include state, duration, confidence, tokens, and cost when available.
For durable timelines across restarts, pass timelineStore: new FileTimelineStore(path) in AgentModule.forRoot({ runtime }) (or AgentRuntime config).
curl http://localhost:3000/__hazel/agents/support-desk/timeline
curl -N http://localhost:3000/__hazel/agents/support-desk/stream
Programmatically, prefer runtime.getTimeline({ agentName }) / getTimelineRecorder() from @hazeljs/agent — Inspector reads the same recorder. Full Agent OS map: Agent OS guide.
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 redaction —
password,secret,token,apiKeyare redacted from metadata - Explicit opt-in — Production use requires
developmentOnly: falseandenableInspector: 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,tokenapiKey,api_keyconnectionString,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):
| Endpoint | Method | Description |
|---|---|---|
/ | GET | Dashboard UI (if exposeUi: true) |
/snapshot | GET | Full JSON snapshot of all inspected entries |
/routes | GET | Routes only |
/modules | GET | Modules only |
/jobs | GET | Cron jobs only |
/agents | GET | Agents only |
/rag | GET | RAG pipelines only |
/prompts | GET | Prompts only |
/graphql | GET | GraphQL resolvers |
/grpc | GET | gRPC methods |
/kafka | GET | Kafka consumers |
/flows | GET | Flows |
/events | GET | Event listeners |
/queue | GET | Queue processors |
/websocket | GET | WebSocket gateways |
/rag/:pipeline/search?q=... | GET | RAG search (when RAG package is used) |
/prompts/render | POST | Render 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
- Keep
developmentOnly: trueunless you have a specific need for production inspection - Use
requireAuthif you enable the Inspector in production - Register Gateway/Discovery when using service mesh—the overview is invaluable
- 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
Related Resources
- Cron Package – Scheduled jobs
- Agent Package – AI agents
- RAG Package – Retrieval-augmented generation
- Gateway Package – API gateway
- Discovery Package – Service discovery
- Resilience Package – Circuit breakers and retries
- hazeljs-inspector-dashboard-example – Full dashboard example
Recipes
Recipe: Enable Inspector Dashboard
// File: src/app.module.ts
import { HazelModule } from '@hazeljs/core';
import { InspectorModule } from '@hazeljs/inspector';
@HazelModule({
imports: [
InspectorModule.register({
enabled: process.env.NODE_ENV !== 'production',
path: '/__hazel',
auth: { username: 'admin', password: process.env.INSPECTOR_PASSWORD },
}),
],
})
export class AppModule {}
// Visit http://localhost:3000/__hazel to see routes, cron jobs, agents, and flows
Recipe: Custom Inspector Metadata
// File: src/health/health.controller.ts
import { Controller, Get } from '@hazeljs/core';
import { InspectorMeta } from '@hazeljs/inspector';
@Controller('health')
@InspectorMeta({ category: 'monitoring', description: 'Health check endpoints' })
export class HealthController {
@Get()
@InspectorMeta({ description: 'Returns app health status' })
check() {
return { status: 'ok', timestamp: new Date().toISOString() };
}
}