nest-profiler-commander
Types and API of the nest-commander CLI collector.
CommandInfo
Payload of a command profile's entrypoint.data (entrypoint type: 'command'). The module
registers a command entrypoint type, so the profiler renders a dedicated Commands table and a
Command detail tab for these profiles.
Prop
Type
Public exports
import { CommanderCollectorModule } from '@eleven-labs/nest-profiler-commander';
import { CommandProfiler } from '@eleven-labs/nest-profiler-commander';
import { CommandProfilerExplorer } from '@eleven-labs/nest-profiler-commander';
import { CommanderDiscoverSource } from '@eleven-labs/nest-profiler-commander';
import {
COMMAND_ENTRYPOINT_TYPE,
COMMAND_ENTRYPOINT_TYPE_DEF,
} from '@eleven-labs/nest-profiler-commander';
import type { CommanderCollectorModuleOptions } from '@eleven-labs/nest-profiler-commander';
import type { CommandInfo, CommandProfileMeta } from '@eleven-labs/nest-profiler-commander';Setup
CommanderCollectorModule.forRoot() takes no required options. Your CliModule (what cli.ts bootstraps with CommandFactory) stays profiler-free; register the collector in a dev-only CLI bundle, with the core on file storage so the CLI and the HTTP server share profiles:
import { Module } from '@nestjs/common';
import { ProfilerModule } from '@eleven-labs/nest-profiler';
import { CommanderCollectorModule } from '@eleven-labs/nest-profiler-commander';
@Module({
imports: [
ProfilerModule.forRoot({ isGlobal: true, storageType: 'file' }),
CommanderCollectorModule.forRoot(),
],
})
export class ProfilingCliModule {}
ProfilingCliModuleis a dev-only bundle loaded bycli-dev.ts— see Enabling and disabling the profiler. If the profiler is installed as a production dependency behind the runtime gate, wrap the same calls inConditionalModule.registerWhen(..., isProfilerEnabled)inCliModule, which must then importConfigModule.forRoot(). If a command injectsTracerServicedirectly, that runtime gate is required, with itsProfilerNoopModulefallback.
A dev-only CliDevModule composes the two, and cli-dev.ts runs it with the profiler logger:
@Module({ imports: [CliModule, ProfilingCliModule] })
export class CliDevModule {}import { ConsoleLogger } from '@nestjs/common';
import { createProfilerLogger } from '@eleven-labs/nest-profiler';
import { CommandFactory } from 'nest-commander';
import { CliDevModule } from './cli.dev.module';
void CommandFactory.run(CliDevModule, {
logger: createProfilerLogger(new ConsoleLogger('Cli', { logLevels: ['log', 'warn', 'error'] })),
});Production keeps running CliModule from cli.ts. Add CommanderCollectorModule.forRoot() to the HTTP app's profiling bundle too, so the web profiler renders command profiles.
Every provider that extends nest-commander's CommandRunner is wrapped automatically - you do not change your command classes.
There is no forRootAsync by design: the collector has no runtime-resolved options (its only knob, enabled, is a synchronous build-time decision), so it is registered as is in the CLI bundle — or, behind the runtime gate, wrapped in ConditionalModule.registerWhen(...).
Prerequisite: nest-commander installed (a regular dependency of your app), and a cross-process storage adapter if you want to inspect command profiles from the HTTP app's web profiler at /_profiler. The CLI and the server are separate processes, so they must share the backing store - use storageType: 'file' (or a Redis/DB adapter). In-memory storage is per-process and can never surface command profiles in a separate web server; the profiler logs a warning when you profile a command against an in-memory store.
How a command profile is shaped
A command has no HTTP request/response. The profiler synthesises a profile whose entrypoint is
{ type: 'command', data: CommandInfo }:
| Field | Value |
|---|---|
entrypoint.type | command |
entrypoint.data.name | The command name (e.g. content:sync) |
entrypoint.data.arguments | The positional arguments |
entrypoint.data.options | The parsed flags |
entrypoint.data.success | true when the command completed without throwing |
response.statusCode | 200 on success, 500 when the command threw |
A command that failed before run() was entered is shaped the same way: nest-commander evaluates the @Option() value parsers during commander's parse phase, so a parser that throws produces a profile with success: false, empty arguments (positional operands are assigned only after every option has parsed) and, in options, the flags commander had resolved so far plus the raw value of the rejected one. Commander's own argv errors (unknown option, missing required option, invalid choices, or a parser throwing commander's InvalidArgumentError) call process.exit() from inside commander and leave no profile.
The command name, arguments and options are kept on entrypoint.data. No exit code is collected — the profiler wraps run() from inside the process and never sees the code the CLI exits with, so success (and response.statusCode) carries the outcome. Because the command body runs inside the profiler's CLS context, profile-scoped collectors (HTTP client, cache, database, …) capture the work the command performs and contribute their own panels.