Inspector Package
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
- 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.
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