nestjs-profiler 1.0.26 → 1.0.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,112 +4,174 @@
4
4
  <img src="https://raw.githubusercontent.com/MohammedRaslan/Nest-JS-Profiler/refs/heads/main/libs/nestjs-profiler/src/assets/logo.png" width="400" alt="NestJS Profiler Logo" />
5
5
  </p>
6
6
 
7
- A NestJS module for profiling HTTP requests, database queries, cache operations, outbound HTTP calls, application logs, package health, code quality, and event tracking. Inspired by Symfony Profiler, it provides a web-based dashboard to inspect everything that happens inside a request — from DB queries to downstream API calls — in real time.
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/nestjs-profiler"><img src="https://img.shields.io/npm/v/nestjs-profiler.svg" alt="npm version" /></a>
9
+ <a href="https://www.npmjs.com/package/nestjs-profiler"><img src="https://img.shields.io/npm/dm/nestjs-profiler.svg" alt="npm downloads" /></a>
10
+ <img src="https://img.shields.io/badge/node-%3E%3D16-brightgreen" alt="node version" />
11
+ <img src="https://img.shields.io/badge/license-MIT-blue" alt="license" />
12
+ </p>
8
13
 
9
- ## Features
14
+ > A drop-in debugging dashboard for NestJS. Inspect HTTP requests, database queries, outbound calls, logs, events, scheduled jobs, and code health — all from one browser tab, with zero instrumentation required.
10
15
 
11
- - **HTTP Request Tracing** — Tracks method, URL, controller handler, duration, status code, headers, and request body.
12
- - **Database Profiling**
13
- - **PostgreSQL** — Captures all queries via `pg` (compatible with TypeORM, MikroORM, raw pg). Supports **Auto-Explain** to run `EXPLAIN` or `EXPLAIN ANALYZE` on slow queries automatically.
14
- - **MongoDB** — Profiles MongoDB commands and queries.
15
- - **MySQL** — Profiles MySQL queries.
16
- - **N+1 Detection** — Automatically flags repeated identical queries within the same request.
17
- - **Slow Query Tagging** — Tags queries exceeding 100ms.
18
- - **Sequential Scan Detection** — Tags queries using a Seq Scan from the explain plan.
19
- - **Outbound HTTP Tracking** — Captures every outbound `http`/`https` call made during a request: URL, method, status code, duration, and headers. Works automatically with axios, node-fetch, and any library built on Node's `http`/`https` modules. Enabled by default — no configuration required.
20
- - **Cache Profiling** — Tracks cache operations (get, set, del, reset) and hit/miss ratio when using `@nestjs/cache-manager`.
21
- - **Log Profiling** — Captures application logs associated with each request context.
22
- - **Live Logs Terminal** — Real-time streaming log viewer at `/__profiler/view/logs/live` via Server-Sent Events. Supports level filtering, search, pause/resume, and auto-scroll.
23
- - **Summary Dashboard** — Aggregate statistics: avg/p95 duration, error rate, cache hit rate, top slow endpoints, top slow queries, and recent errors.
24
- - **Entity Explorer** — Lists all registered TypeORM/MikroORM entities and their columns.
25
- - **Route Explorer** — Lists all registered routes with their controllers, handlers, HTTP methods, and full path. Each route expands to show path parameters, query parameters, request headers, and body DTOs — including the DTO class name, all decorated properties, and their TypeScript types. Source file paths are shown with a one-click copy button.
26
- - **Dashboard Authentication** — Optional login wall protecting all `/__profiler` routes. When enabled, an HMAC-signed token is stored in the browser's `localStorage` with a 24-hour TTL. Credentials are defined in `ProfilerModule.forRoot()` — no separate auth server required.
27
- - **Package Health** — Runs `npm audit` and `npm outdated` to surface known vulnerabilities and stale dependencies. Results are cached for 5 minutes. Works with npm, yarn, and pnpm. If the registry is unreachable, outdated packages are still shown with an inline warning.
28
- - **Code Quality** — Runs ESLint and TypeScript compiler checks (`tsc --noEmit`) against your source code. Issues are displayed grouped by file or by rule, with direct links to ESLint rule docs and TypeScript error references. Auto-fixable issues are flagged. File paths are copyable with one click.
29
- - **Event Tracking** — Automatically intercepts every `EventEmitter2` emission and builds a cascading tree showing which service fired each event, which listeners handled it (with individual timings), and any child events emitted from inside a listener. No instrumentation required — works automatically when `@nestjs/event-emitter` is installed.
30
- - **Web UI** — Built-in dashboard at `/__profiler` with no external dependencies.
31
- - **Zero Hard Dependencies** — Core functionality works out of the box; database drivers are optional peer dependencies.
16
+ ---
32
17
 
33
- ## Installation
18
+ > ⚠️ **Development use only.** The profiler adds request overhead and exposes internal application data. Always set `enabled: process.env.NODE_ENV !== 'production'`.
19
+
20
+ ---
21
+
22
+ ## Quick Start
23
+
24
+ **1. Install**
34
25
 
35
26
  ```bash
36
27
  npm install nestjs-profiler
37
28
  ```
38
29
 
39
- ### Peer Dependencies (Optional)
30
+ **2. Register in your AppModule**
40
31
 
41
- Install only the dependencies relevant to your project:
32
+ ```typescript
33
+ import { ProfilerModule } from 'nestjs-profiler';
34
+
35
+ @Module({
36
+ imports: [
37
+ ProfilerModule.forRoot({
38
+ enabled: process.env.NODE_ENV !== 'production',
39
+ }),
40
+ ],
41
+ })
42
+ export class AppModule {}
43
+ ```
44
+
45
+ **3. Initialize in main.ts**
46
+
47
+ ```typescript
48
+ import { ProfilerModule } from 'nestjs-profiler';
49
+
50
+ async function bootstrap() {
51
+ const app = await NestFactory.create(AppModule);
52
+ ProfilerModule.initialize(app); // enables Route Explorer, Entity Explorer, Scheduled Jobs
53
+ await app.listen(3000);
54
+ }
55
+ ```
56
+
57
+ ---
58
+
59
+ ### Global Prefix (Required if you use global route prefix)
60
+
61
+ If your app uses a global route prefix, exclude the profiler:
62
+
63
+ ```typescript
64
+ app.setGlobalPrefix('api', {
65
+ exclude: [{ path: '__profiler/(.*)', method: RequestMethod.ALL }],
66
+ });
67
+ ```
68
+
69
+ Open `http://localhost:3000/__profiler` — the dashboard is live.
70
+
71
+ ---
72
+
73
+ ## Features
74
+
75
+ ### Request Profiling
76
+ - Traces every HTTP request: method, URL, handler, status code, duration, headers, and body
77
+ - Summary dashboard with avg/p95 duration, error rate, cache hit rate, top slow endpoints, and recent errors
78
+ - Full detail view per request including all associated queries, cache ops, logs, and outbound calls
79
+
80
+ ### Database
81
+ - **PostgreSQL** — captures all queries via `pg`, compatible with TypeORM, MikroORM, and raw pg
82
+ - **MongoDB** — profiles all MongoDB commands
83
+ - **MySQL** — profiles MySQL queries via `mysql2`
84
+ - **N+1 Detection** — flags repeated identical queries within the same request
85
+ - **Slow Query Tagging** — highlights queries over 100ms
86
+ - **Sequential Scan Detection** — flags full table scans from the query explain plan
87
+ - **Auto-Explain** — automatically runs `EXPLAIN` or `EXPLAIN ANALYZE` on slow queries (opt-in)
88
+
89
+ ### Outbound HTTP
90
+ Automatically captures every `http`/`https` call your app makes — including axios, node-fetch, and any library built on Node's core modules. Records method, URL, status code, duration, headers (with Authorization and Cookie values redacted), and errors. No configuration required.
91
+
92
+ ### Cache
93
+ Tracks `get`, `set`, `del`, and `reset` operations with hit/miss ratio when using `@nestjs/cache-manager`.
94
+
95
+ ### Logs
96
+ - Captures application logs per request context
97
+ - **Live Logs Terminal** — real-time streaming viewer via Server-Sent Events, with level filtering, search, pause/resume, and auto-scroll
98
+
99
+ ### Code Analysis
100
+ - **Package Health** — runs `npm audit` and `npm outdated` to surface vulnerabilities and stale dependencies, sorted by severity
101
+ - **Code Quality** — runs ESLint and `tsc --noEmit` against your source. Issues shown by file or by rule, with links to rule docs and TypeScript error references. Auto-fixable issues are flagged
102
+
103
+ ### Application Intelligence
104
+ - **Route Explorer** — every registered route grouped by controller, with path/query/header params, body DTOs, property types, and source file paths
105
+ - **Entity Explorer** — all registered TypeORM/MikroORM entities with their columns
106
+ - **Event Tracking** — intercepts every `EventEmitter2` emission and renders a cascading tree: which service fired it, which listeners handled it, individual timings, child events, and errors. Requires `@nestjs/event-emitter`
107
+ - **Scheduled Jobs** — live view of all `@Cron`, `@Interval`, and `@Timeout` jobs from `@nestjs/schedule`, with countdowns, last run times, cycle progress, and handler details. Requires `@nestjs/schedule`
108
+
109
+ ### Security
110
+ - **Dashboard Authentication** — optional login wall with HMAC-SHA256 tokens stored in `localStorage`, 24-hour TTL. No separate auth server needed
111
+
112
+ ---
113
+
114
+ ## Installation
42
115
 
43
116
  ```bash
44
- # For PostgreSQL
45
- npm install pg
117
+ npm install nestjs-profiler
118
+ ```
46
119
 
47
- # For MongoDB
48
- npm install mongodb
120
+ ### Optional Peer Dependencies
49
121
 
50
- # For MySQL
51
- npm install mysql2
122
+ Install only what your project uses:
52
123
 
53
- # For Cache Profiling
54
- npm install @nestjs/cache-manager cache-manager
124
+ ```bash
125
+ npm install pg # PostgreSQL
126
+ npm install mongodb # MongoDB
127
+ npm install mysql2 # MySQL
128
+ npm install @nestjs/cache-manager cache-manager # Cache profiling
129
+ npm install @nestjs/event-emitter # Event tracking
130
+ npm install @nestjs/schedule # Scheduled jobs
55
131
  ```
56
132
 
133
+ ---
134
+
57
135
  ## Configuration
58
136
 
59
- Import `ProfilerModule` in your root `AppModule`:
137
+ All options are passed to `ProfilerModule.forRoot()`. Only `enabled` is required everything else is opt-in.
60
138
 
61
139
  ```typescript
62
- import { Module } from '@nestjs/common';
63
140
  import { ProfilerModule } from 'nestjs-profiler';
64
141
  import * as pg from 'pg';
65
142
 
66
143
  @Module({
67
144
  imports: [
68
145
  ProfilerModule.forRoot({
69
- // Global enable/disable (default: true)
70
- // Recommended: disable in production
71
146
  enabled: process.env.NODE_ENV !== 'production',
72
147
 
73
- // ── Database ─────────────────────────────────────────────────
74
- // PostgreSQL — pass the pg driver instance
148
+ // PostgreSQL
75
149
  pgDriver: pg,
76
150
  collectQueries: true,
77
-
78
- // Auto-Explain for slow queries
79
151
  explain: {
80
152
  enabled: true,
81
- thresholdMs: 50, // Only explain queries taking > 50ms
82
- analyze: false, // true = EXPLAIN ANALYZE (actually executes!)
153
+ thresholdMs: 100, // explain queries slower than this
154
+ analyze: false, // true = EXPLAIN ANALYZE (executes the query!)
83
155
  },
84
156
 
85
- // MongoDB — pass the mongodb driver instance
157
+ // MongoDB
86
158
  mongoDriver: require('mongodb'),
87
159
  collectMongo: true,
88
160
 
89
- // MySQL — pass the mysql2 driver instance
161
+ // MySQL
90
162
  mysqlDriver: require('mysql2'),
91
163
  collectMysql: true,
92
164
 
93
- // ── Outbound HTTP ─────────────────────────────────────────────
94
- // Tracks all outbound http/https calls made during each request.
95
- // Enabled by default — set false to disable.
165
+ // Outbound HTTP (on by default)
96
166
  collectHttp: true,
97
167
 
98
- // ── Cache ─────────────────────────────────────────────────────
99
- collectCache: true, // requires @nestjs/cache-manager
168
+ // Cache
169
+ collectCache: true,
100
170
 
101
- // ── Logs ──────────────────────────────────────────────────────
171
+ // Logs
102
172
  collectLogs: true,
103
173
 
104
- // ── Storage ───────────────────────────────────────────────────
105
- // Default: in-memory (last 100 requests).
106
- // Pass a custom object implementing ProfilerStorage for persistence.
107
- storage: 'memory',
108
-
109
- // ── Dashboard Auth ────────────────────────────────────────────
110
- // Disabled by default. When enabled, all /__profiler routes
111
- // require login. username + password are both required when
112
- // enabled — a TypeScript type error is raised if either is missing.
174
+ // Auth (off by default)
113
175
  auth: {
114
176
  enabled: true,
115
177
  username: 'admin',
@@ -121,68 +183,65 @@ import * as pg from 'pg';
121
183
  export class AppModule {}
122
184
  ```
123
185
 
124
- ### Default behaviour
186
+ ### Options Reference
125
187
 
126
- | Option | Default | Notes |
188
+ | Option | Default | Description |
127
189
  |---|---|---|
128
- | `enabled` | `true` | Set `false` or tie to `NODE_ENV` |
129
- | `collectHttp` | `true` | Patches `http`/`https` automatically |
130
- | `collectLogs` | `true` | |
131
- | `collectQueries` | `true` | Requires `pgDriver` / `mongoDriver` / `mysqlDriver` |
132
- | `collectCache` | `true` | Requires `@nestjs/cache-manager` |
133
- | `explain.enabled` | `false` | Opt-in only |
134
- | Event Tracking | automatic | Active when `@nestjs/event-emitter` is detected |
135
- | `auth.enabled` | `false` | When `true`, `username` and `password` are required |
136
-
137
- ## Usage
138
-
139
- ### 1. Initialize Explorers (Optional but Recommended)
190
+ | `enabled` | `true` | Master switch. Tie to `NODE_ENV` in production |
191
+ | `collectHttp` | `true` | Outbound HTTP tracking (patches `http`/`https`) |
192
+ | `collectLogs` | `true` | Log capture per request |
193
+ | `collectQueries` | `true` | DB query capture. Requires a driver to be passed |
194
+ | `collectCache` | `true` | Cache op tracking. Requires `@nestjs/cache-manager` |
195
+ | `explain.enabled` | `false` | Auto-Explain for slow queries |
196
+ | `explain.thresholdMs` | `100` | Minimum query duration to trigger explain |
197
+ | `explain.analyze` | `false` | Run `EXPLAIN ANALYZE` instead of `EXPLAIN` |
198
+ | `auth.enabled` | `false` | Enable login wall. `username` and `password` required when `true` |
199
+ | Event Tracking | automatic | Activates when `@nestjs/event-emitter` is detected |
200
+ | Scheduled Jobs | automatic | Activates when `@nestjs/schedule` is detected |
140
201
 
141
- To enable the **Entity Explorer** and **Route Explorer**, call `initialize` in `main.ts` after creating the app:
202
+ ---
142
203
 
143
- ```typescript
144
- import { NestFactory } from '@nestjs/core';
145
- import { AppModule } from './app.module';
146
- import { ProfilerModule } from 'nestjs-profiler';
204
+ ## Dashboard
147
205
 
148
- async function bootstrap() {
149
- const app = await NestFactory.create(AppModule);
206
+ Navigate to `/__profiler` after starting your app.
150
207
 
151
- ProfilerModule.initialize(app);
152
-
153
- await app.listen(3000);
154
- }
155
- bootstrap();
156
- ```
157
-
158
- ### 2. Accessing the Dashboard
159
-
160
- Once configured, start your application. The profiler automatically intercepts all requests.
161
-
162
- Navigate to `http://localhost:3000/__profiler`.
163
-
164
- #### Dashboard Pages
165
-
166
- | Path | Description |
208
+ | Page | Description |
167
209
  |---|---|
168
- | `/__profiler` | Redirects to Summary (default landing page) |
169
210
  | `/__profiler/view/summary` | Aggregate stats: avg/p95 duration, error rate, top slow endpoints |
170
- | `/__profiler/view/requests` | All captured requests |
171
- | `/__profiler/view/queries` | All database queries across requests, sorted by duration |
172
- | `/__profiler/view/http-calls` | All outbound HTTP calls across requests, sorted by duration |
211
+ | `/__profiler/view/requests` | All captured requests with status, duration, and method |
212
+ | `/__profiler/view/queries` | All DB queries across requests, sortable by duration |
213
+ | `/__profiler/view/http-calls` | All outbound HTTP calls, sortable by duration |
173
214
  | `/__profiler/view/logs` | Paginated application logs |
174
- | `/__profiler/view/logs/live` | Live streaming terminal — real-time log output |
215
+ | `/__profiler/view/logs/live` | Real-time streaming log terminal |
175
216
  | `/__profiler/view/cache` | Cache operations with hit/miss breakdown |
176
- | `/__profiler/view/entities` | Registered database entities |
177
- | `/__profiler/view/routes` | All registered application routes |
217
+ | `/__profiler/view/entities` | Registered database entities and their columns |
218
+ | `/__profiler/view/routes` | All registered routes with DTOs and parameter types |
178
219
  | `/__profiler/view/health` | Package vulnerabilities and outdated dependency report |
179
- | `/__profiler/view/code-quality` | ESLint and TypeScript static analysis report |
180
- | `/__profiler/view/events` | Event tracking — cascading tree of all `EventEmitter2` emissions |
220
+ | `/__profiler/view/code-quality` | ESLint and TypeScript static analysis |
221
+ | `/__profiler/view/events` | Event cascade tree for `EventEmitter2` emissions |
222
+ | `/__profiler/view/cron-jobs` | Live scheduled job monitor — cron, intervals, and timeouts |
181
223
  | `/__profiler/:id` | Full detail view for a single request |
182
224
 
183
- ### 3. Dashboard Authentication
225
+ ### JSON API
226
+
227
+ All data is also available as JSON for programmatic use:
228
+
229
+ ```
230
+ GET /__profiler/json # all captured requests
231
+ GET /__profiler/:id/json # single request detail
232
+ GET /__profiler/api/health # package health (5 min cache)
233
+ GET /__profiler/api/health?force=true
234
+ GET /__profiler/api/code-quality # static analysis (5 min cache)
235
+ GET /__profiler/api/code-quality?force=true
236
+ GET /__profiler/api/events # event log (live, not cached)
237
+ GET /__profiler/api/cron-jobs # scheduled job state (live, not cached)
238
+ ```
239
+
240
+ ---
184
241
 
185
- By default the profiler dashboard is open to anyone who can reach the server. For shared or remote environments you can enable a login wall:
242
+ ## Feature Guides
243
+
244
+ ### Dashboard Authentication
186
245
 
187
246
  ```typescript
188
247
  ProfilerModule.forRoot({
@@ -194,177 +253,111 @@ ProfilerModule.forRoot({
194
253
  })
195
254
  ```
196
255
 
197
- TypeScript enforces that `username` and `password` are both present when `enabled: true` setting `enabled: true` without credentials is a compile-time error.
198
-
199
- **How it works:**
256
+ When enabled, all `/__profiler` pages check for a valid token in `localStorage` before rendering. If none is found, the browser redirects to the login page. Tokens use HMAC-SHA256 keyed on the password and expire after 24 hours — changing the password invalidates all active sessions automatically.
200
257
 
201
- When auth is enabled, every `/__profiler` page runs a blocking script before rendering. If no valid token is found in `localStorage`, the browser is immediately redirected to `/__profiler/login`. After a successful login the token is stored in `localStorage.__profiler_auth` and is valid for 24 hours, after which the user is redirected to the login page again.
258
+ TypeScript enforces that `username` and `password` are present when `enabled: true`. Omitting either is a compile-time error.
202
259
 
203
- Token generation uses HMAC-SHA256 keyed on the password, so tokens are invalidated automatically if the password changes.
260
+ > Auth is enforced client-side. It prevents casual access on shared dev/staging environments but is not a security boundary for sensitive data.
204
261
 
205
- | Route | Description |
262
+ | Route | Purpose |
206
263
  |---|---|
207
264
  | `GET /__profiler/login` | Login page |
208
- | `POST /__profiler/api/login` | JSON login endpoint returns `{ token, expiresAt }` |
209
- | `GET /__profiler/logout` | Clears the token and redirects to the login page |
265
+ | `POST /__profiler/api/login` | Validates credentials, returns a session token |
266
+ | `GET /__profiler/logout` | Clears the token and redirects to login |
210
267
 
211
- > **Note:** Auth is enforced client-side via `localStorage`. It is intended to prevent casual access in shared dev/staging environments, not as a security boundary for sensitive data. Do not expose the profiler on a public network regardless of this setting.
268
+ ---
212
269
 
213
- ### 4. Outbound HTTP Tracking
270
+ ### Event Tracking
214
271
 
215
- Outbound HTTP tracking is **enabled by default**. Any `http.request`, `https.request`, `http.get`, or `https.get` call made during a request is automatically captured — including calls made via axios, node-fetch, and similar libraries.
216
-
217
- Each captured call records:
218
-
219
- - Method and full URL
220
- - HTTP vs HTTPS protocol
221
- - Response status code
222
- - Duration in ms
223
- - Request and response headers (Authorization/Cookie values are automatically redacted)
224
- - Error message if the call failed
225
-
226
- You can view outbound calls for a specific request in the request detail view, or browse all calls across all requests at `/__profiler/view/http-calls`.
227
-
228
- To disable:
272
+ Requires `@nestjs/event-emitter`:
229
273
 
230
274
  ```typescript
231
- ProfilerModule.forRoot({ collectHttp: false })
232
- ```
233
-
234
- ### 5. Package Health
235
-
236
- The Health tab runs `npm audit` and `npm outdated` from your project root and displays the results in a searchable UI.
237
-
238
- - **Vulnerabilities** — sorted by severity (critical → high → moderate → low), with fix availability and whether the package is a direct or transitive dependency.
239
- - **Outdated packages** — shows current, wanted, and latest versions with major-update warnings.
240
- - Results are **cached for 5 minutes** server-side. Navigating back to the tab shows the cached result instantly without re-running. Click **Re-run audit** to force a fresh scan.
241
- - If `npm audit` cannot reach the registry (e.g. VPN or proxy), the outdated packages section still renders with an inline warning for the unavailable audit.
242
- - No configuration required — works automatically for npm, yarn, and pnpm projects.
243
-
244
- #### JSON endpoint
245
-
246
- ```
247
- GET /__profiler/api/health # cached result (5 min TTL)
248
- GET /__profiler/api/health?force=true # force fresh scan
249
- ```
250
-
251
- ### 6. Code Quality
252
-
253
- The Code Quality tab runs static analysis tools against your source code and surfaces every issue without AI or external services.
254
-
255
- **ESLint** — uses your project's existing ESLint configuration (`node_modules/.bin/eslint`). Results are shown in two views:
256
-
257
- - **By File** — expandable accordion rows per file. Each issue shows line:column, severity badge, message, fix indicator (⚡ auto-fixable), and a clickable rule badge linking to the ESLint documentation.
258
- - **By Rule** — sorted by severity then count, showing how many files are affected per rule.
275
+ import { EventEmitterModule } from '@nestjs/event-emitter';
259
276
 
260
- **TypeScript** — runs `tsc --noEmit` using your project's `tsconfig.json`. Each error links to `typescript.tv/errors` for explanations.
261
-
262
- **Summary cards** show total issues, errors, warnings, auto-fixable count, and files affected at a glance.
263
-
264
- File paths have a **copy-to-clipboard** button that appears on hover, making it easy to jump to the file in your editor.
265
-
266
- Results are cached for 5 minutes. Click **Re-run** to force a fresh analysis.
267
-
268
- > **Note:** Code Quality only lints the `src/` directory (or project root if `src/` doesn't exist) and automatically ignores `dist/`, `build/`, `coverage/`, and other generated directories.
269
-
270
- #### JSON endpoint
271
-
272
- ```
273
- GET /__profiler/api/code-quality # cached result (5 min TTL)
274
- GET /__profiler/api/code-quality?force=true # force fresh scan
277
+ @Module({
278
+ imports: [EventEmitterModule.forRoot()],
279
+ })
280
+ export class AppModule {}
275
281
  ```
276
282
 
277
- ### 7. Event Tracking
278
-
279
- The Event Tracking tab captures every `EventEmitter2` emission across your application and renders it as a cascading tree — no instrumentation required.
280
-
281
- **What it captures:**
283
+ The profiler intercepts every `emit` and `emitAsync` call automatically. No decorators or instrumentation needed. The dashboard renders a full cascade tree showing the emitter, all listeners with timings, child events, and any listener errors.
282
284
 
283
- - The event name and a JSON preview of the payload
284
- - Which service or function fired the event (resolved from the call stack)
285
- - Each listener that handled the event, with individual execution times and pass/fail status
286
- - Child events emitted from inside a listener, forming a full cascade tree
287
- - The depth of each event in the chain (root = 0, emitted by a listener = 1, etc.)
288
- - Whether the event was fired synchronously (`emit`) or asynchronously (`emitAsync`)
289
- - Any errors thrown by a listener
290
-
291
- **Example chain visualised:**
285
+ **Example what you see in the dashboard:**
292
286
 
293
287
  ```
294
288
  🔔 order.created (async) ⬆ OrderService.createOrder 145ms
295
289
  ✓ onOrderCreated [InventoryListener] 45ms
296
290
  ✓ onOrderCreated [InvoiceListener] 80ms
297
291
  ✓ onOrderCreated [AuditListener] 5ms
298
- └── 🔔 inventory.reserved (async) ⬆ InventoryListener.onOrderCreated 23ms
292
+ └── 🔔 inventory.reserved ⬆ InventoryListener 23ms
299
293
  ✓ onInventoryReserved [NotificationListener] 20ms
300
- onInventoryReserved [AuditListener] 3ms
301
- └── 🔔 invoice.created (async) ⬆ InvoiceListener.onOrderCreated 4ms
294
+ └── 🔔 invoice.created ⬆ InvoiceListener 4ms
302
295
  ✓ onInvoiceCreated [AuditListener] 3ms
303
296
  ```
304
297
 
305
- **Requirements:** `@nestjs/event-emitter` must be installed and `EventEmitterModule.forRoot()` must be imported in your `AppModule`. The profiler detects it automatically — no configuration needed.
306
-
307
- The page has an **Auto-refresh** toggle that polls every 3 seconds, making it easy to watch events flow in real time as you hit your endpoints.
298
+ ---
308
299
 
309
- Results are not cached — each refresh fetches the latest events from the in-memory ring buffer (last 500 events).
300
+ ### Scheduled Jobs
310
301
 
311
- #### JSON endpoint
302
+ Requires `@nestjs/schedule`:
312
303
 
313
- ```
314
- GET /__profiler/api/events # all captured events (flat array, newest first)
304
+ ```bash
305
+ npm install @nestjs/schedule
315
306
  ```
316
307
 
317
- ### 8. Route Explorer
308
+ ```typescript
309
+ import { ScheduleModule } from '@nestjs/schedule';
318
310
 
319
- The Route Explorer (`/__profiler/view/routes`) lists every registered route in your application. Routes are grouped by controller and displayed in an expandable accordion. Call `ProfilerModule.initialize(app)` in `main.ts` to populate it (see section 1).
311
+ @Module({
312
+ imports: [ScheduleModule.forRoot()],
313
+ })
314
+ export class AppModule {}
315
+ ```
320
316
 
321
- **Per-route information:**
317
+ The profiler detects `SchedulerRegistry` at startup via `ProfilerModule.initialize(app)` — no additional configuration needed. The dashboard has three tabs:
322
318
 
323
- Each route row shows the HTTP method badge and the full path (including any global prefix). Expanding a row reveals:
319
+ **Cron Jobs** one card per `@Cron()` method showing the expression with a plain-English translation (e.g. `0 */5 * * * *` → *Every 5 minutes*), a live next-run countdown, last run time, cycle progress bar, handler name, and source file path. An *Upcoming — next 3 hours* strip at the top plots all jobs on a shared timeline.
324
320
 
325
- - **Path parameters** — parameters from the URL pattern (`:id`, `:userId`, etc.), detected either from `@Param('name')` decorators or by scanning the path template directly.
326
- - **Query parameters** — parameters decorated with `@Query()`, with their TypeScript type.
327
- - **Headers** — parameters decorated with `@Headers()`, with their TypeScript type.
328
- - **Request body** — the DTO class name from `@Body()`, with an expanded table of all decorated properties and their types. Properties are discovered via `reflect-metadata` — any class using `class-validator`, `@ApiProperty`, or any other property decorator will have its fields listed automatically.
329
- - **Source file** — the `.ts` file path of the DTO class, with a one-click copy button, making it easy to jump to the type definition from the profiler.
321
+ **Intervals** — one card per `@Interval()` method with an animated frequency ring, the repeat period displayed prominently (e.g. *Every 30s*), and fires-per-minute count.
330
322
 
331
- **Examplewhat gets surfaced:**
323
+ **Timeouts**one card per `@Timeout()` method. Pending jobs show a live countdown in amber; fired jobs turn grey with a *Fired* badge. Both show the configured delay and the handler that will run.
332
324
 
333
- ```
334
- POST /api/v1/orders/:storeId
335
- Path params storeId string
336
- Query params includeVat boolean
337
- Body (DTO) CreateOrderDto
338
- items array
339
- couponCode string
340
- metadata object
341
- src/orders/dto/create-order.dto.ts [copy]
342
- ```
325
+ All tabs auto-refresh every 15 seconds. If `@nestjs/schedule` is not installed, the page shows an install prompt instead of an error.
343
326
 
344
- The explorer performs a best-effort scan using `reflect-metadata`. It works with TypeScript's `emitDecoratorMetadata: true` (standard for NestJS projects) and does not require OpenAPI/Swagger to be installed.
327
+ **Example:**
345
328
 
346
- ### 9. JSON API
329
+ ```typescript
330
+ import { Cron, CronExpression, Interval, Timeout } from '@nestjs/schedule';
347
331
 
348
- Retrieve profile data programmatically:
332
+ @Injectable()
333
+ export class TasksService {
349
334
 
350
- - `GET /__profiler/json` List all captured requests
351
- - `GET /__profiler/:id/json` Details for a specific request
335
+ @Cron(CronExpression.EVERY_MINUTE, { name: 'health-ping' })
336
+ handleHealthPing() { /* ... */ }
352
337
 
353
- ## Global Prefix
338
+ @Cron('0 0 * * *', { name: 'nightly-cleanup' })
339
+ handleNightlyCleanup() { /* ... */ }
354
340
 
355
- If your app uses a global prefix (e.g. `/api`), exclude the profiler routes:
341
+ @Interval('metrics-flush', 30_000)
342
+ handleMetricsFlush() { /* ... */ }
356
343
 
357
- ```typescript
358
- app.setGlobalPrefix('api', {
359
- exclude: [{ path: '__profiler/(.*)', method: RequestMethod.ALL }],
360
- });
344
+ @Timeout('deferred-init', 10_000)
345
+ handleDeferredInit() { /* ... */ }
346
+ }
361
347
  ```
362
348
 
363
- ## Important Notes
349
+ ---
350
+
351
+ ### Route Explorer
352
+
353
+ Populated by `ProfilerModule.initialize(app)`. Lists every route grouped by controller in an expandable accordion. Each route surfaces:
354
+
355
+ - HTTP method and full path (including global prefix)
356
+ - Path parameters, query parameters, and headers with their TypeScript types
357
+ - Body DTO — class name, all decorated properties and types (discovered via `reflect-metadata`)
358
+ - Source file path with a one-click copy button
364
359
 
365
- - The profiler is designed for **development and debugging only**. Do not enable in production it adds request overhead and exposes internal application data.
366
- - The default in-memory storage holds the last 100 requests. Older profiles are evicted automatically.
367
- - Outbound HTTP tracking patches `http`/`https` at the Node.js module level. The patch is applied once on module init and is safe for hot-reload (double-patch is guarded).
360
+ Works with `emitDecoratorMetadata: true` (standard in NestJS). No OpenAPI/Swagger required.
368
361
 
369
362
  ## License
370
363
 
@@ -6,6 +6,7 @@ import { EntityExplorerService } from '../services/entity-explorer.service';
6
6
  import { RouteExplorerService } from '../services/route-explorer.service';
7
7
  import { HealthService } from '../services/health.service';
8
8
  import { CodeQualityService } from '../services/code-quality.service';
9
+ import { CronExplorerService } from '../services/cron-explorer.service';
9
10
  import { ProfilerOptions } from '../common/profiler-options.interface';
10
11
  export declare class ProfilerController {
11
12
  private readonly profilerService;
@@ -15,8 +16,9 @@ export declare class ProfilerController {
15
16
  private readonly routeExplorer;
16
17
  private readonly healthService;
17
18
  private readonly codeQualityService;
19
+ private readonly cronExplorer;
18
20
  private readonly profilerOptions;
19
- constructor(profilerService: ProfilerService, viewService: ViewService, templateBuilder: TemplateBuilderService, entityExplorer: EntityExplorerService, routeExplorer: RouteExplorerService, healthService: HealthService, codeQualityService: CodeQualityService, profilerOptions: ProfilerOptions);
21
+ constructor(profilerService: ProfilerService, viewService: ViewService, templateBuilder: TemplateBuilderService, entityExplorer: EntityExplorerService, routeExplorer: RouteExplorerService, healthService: HealthService, codeQualityService: CodeQualityService, cronExplorer: CronExplorerService, profilerOptions: ProfilerOptions);
20
22
  private get authEnabled();
21
23
  private renderLayout;
22
24
  dashboard(res: Response): Promise<void>;
@@ -52,6 +54,8 @@ export declare class ProfilerController {
52
54
  codeQualityAudit(force?: string): Promise<import("../services/code-quality.service").CodeQualityReport>;
53
55
  eventsPage(res: Response): Promise<void>;
54
56
  eventsApi(): Promise<import("..").EventProfile[]>;
57
+ cronJobsPage(res: Response): Promise<void>;
58
+ cronJobsApi(): Promise<import("../services/cron-explorer.service").CronReport>;
55
59
  liveLogsPage(res: Response): Promise<void>;
56
60
  liveLogsStream(res: Response): void;
57
61
  serveAsset(file: string, res: Response): Promise<void>;