nest-profiler-routes
Types and API of the Discover views and their discover-source extension point.
RoutesCollectorModuleOptions
Options passed to RoutesCollectorModule.forRoot().
Prop
Type
What is captured
At application startup every registered route is discovered and grouped by transport, and each group becomes its own Discover sidebar view (?view=discover-<transport>). The package ships a built-in HTTP source; other transport packages contribute their own view when installed:
- HTTP (built-in) — every
@Controllerhandler, with its HTTP method, full path and the inputs read from@Param,@Query,@Headersand@Body. - GraphQL — every query, mutation and subscription field with its argument names (
@eleven-labs/nest-profiler-graphql). - RabbitMQ — the declared topology (connections, exchanges, queues, exchange bindings) followed by every
@RabbitSubscribe/@RabbitRPCconsumer with its full subscription: queue, exchange, routing keys, connection, queue options and error behaviour (@eleven-labs/nest-profiler-rabbitmq). - Commands — every nest-commander
@Command()with its name and--optionflags (@eleven-labs/nest-profiler-commander).
A REST route also shows the guards protecting it — the classes from @UseGuards() on the controller and/or handler (e.g. an authentication guard) — with a lock marking guarded routes. Only route-level guards are reflected; a global APP_GUARD is not attached per handler.
For a REST route, each @Body() DTO is introspected to its top-level decorated properties: the property name, its TypeScript type and, when class-validator is installed, the validation rules. Introspection is top-level only — a property that is itself a DTO surfaces as its class name rather than being expanded.
Public exports
import {
RoutesCollectorModule,
RoutesCollector,
HttpDiscoverSource,
describeHandlerParams,
discoverViewKey,
handlerHasRouteArgs,
readRouteGuards,
DISCOVER_GROUP,
DISCOVER_GROUP_LABEL,
ROUTES_COLLECTOR_OPTIONS,
} from '@eleven-labs/nest-profiler-routes';
import type {
RoutesCollectorModuleOptions,
RoutesCollectorModuleAsyncOptions,
RoutesCollectorData,
} from '@eleven-labs/nest-profiler-routes';The ProfilerDiscoverSource, DiscoverGroup, DiscoverEntry and DiscoverInputs types — the extension point every source implements — are exported from the core package, together with DiscoverInputGroup / DiscoverInputItem, which describe inputs that are not HTTP-shaped (CLI arguments and options, GraphQL field arguments), and DiscoverSection / DiscoverSectionItem, which describe what a transport declared beyond its entries (the RabbitMQ topology, for instance):
import type {
ProfilerDiscoverSource,
DiscoverGroup,
DiscoverEntry,
DiscoverInputs,
DiscoverInputGroup,
DiscoverInputItem,
DiscoverSection,
DiscoverSectionItem,
} from '@eleven-labs/nest-profiler';Setup
import { Module } from '@nestjs/common';
import { ProfilerModule } from '@eleven-labs/nest-profiler';
import { RoutesCollectorModule } from '@eleven-labs/nest-profiler-routes';
@Module({
imports: [ProfilerModule.forRoot({ isGlobal: true }), RoutesCollectorModule.forRoot()],
})
export class ProfilingModule {}
ProfilingModuleis the dev-only bundle loaded bymain-dev.ts— see Enabling and disabling the profiler. If the profiler is installed as a production dependency behind the runtime gate, wrap the same call inConditionalModule.registerWhen(..., isProfilerEnabled).
Contributing a custom discover source
Register a ProfilerDiscoverSource with the core to add your own Discover view — the same mechanism the GraphQL, RabbitMQ and CLI packages use. Each DiscoverGroup returned becomes one view; set itemLabel when its entries are not routes, so the count reads 3 commands rather than 3 routes. Resolve the core via ModuleRef (a dynamic module cannot reliably inject a provider exported by another dynamic module):
import { Injectable, OnApplicationBootstrap } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core';
import { ProfilerCoreService } from '@eleven-labs/nest-profiler';
import type { ProfilerDiscoverSource, DiscoverGroup } from '@eleven-labs/nest-profiler';
@Injectable()
export class MyDiscoverSource implements ProfilerDiscoverSource, OnApplicationBootstrap {
readonly type = 'my-transport';
constructor(private readonly moduleRef: ModuleRef) {}
onApplicationBootstrap(): void {
try {
this.moduleRef.get(ProfilerCoreService, { strict: false }).registerDiscoverSource(this);
} catch {
// profiler not configured — nothing to register with
}
}
collect(): DiscoverGroup {
return { source: 'my-transport', label: 'My transport', itemLabel: 'endpoint', entries: [] };
}
}Declaring more than entries
A transport's static surface is not always a list of entries. Add sections to the group and each becomes a titled block rendered above the entry list — an item carries a name, an optional kind badge, a one-line detail, boolean flags and free-form attributes. This is how the RabbitMQ source shows the exchanges and queues the application declared, including the ones no handler consumes:
collect(): DiscoverGroup {
return {
source: 'my-transport',
label: 'My transport',
itemLabel: 'endpoint',
entries: [],
sections: [
{
label: 'Queues',
itemLabel: 'queue',
items: [
{
name: 'api-tts.narration',
detail: '← articles.events (published.*)',
flags: ['durable'],
attributes: { 'x-dead-letter-exchange': 'tts.dead-letter' },
},
],
},
],
};
}A group whose entries are empty but whose sections hold something still gets its view — a broker an application only publishes to is worth showing.