npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vitals-node

v1.1.3

Published

Multi-framework health monitoring & system metrics for NestJS, Express, and Bun

Readme

vitals-node

npm version License: MIT TypeScript

Multi-framework health monitoring and AI agent integration for Node.js. Supports NestJS, Express, and Bun with zero-config setup.


Features

  • Multi-framework — NestJS, Express, Bun
  • Mode systemmonitor (health/metrics) · agent (AI integration) · both
  • Real-time dashboard — Charts, dark mode, route panel
  • System metrics — CPU, Memory, Disk monitoring
  • Route discovery — Auto-detect all registered API routes
  • AI schema analysis — Claude or Ollama reads source code and infers request schemas
    • Works across all frameworks: NestJS decorator lookup, Express/Bun method-call lookup
    • DTO resolution — follows this.service.method(body) chains to resolve any-typed parameters
    • "any" type for fields that genuinely cannot be determined
  • Per-route table detection — identifies which DB tables each route reads/writes via static regex or LLM (tableDetection: 'static' | 'llm' | 'auto'); follows service delegation chains
  • Auth detection — Scans @UseGuards, global guards, @Public() per route; LLM classifies auth type
  • Auth-aware call_apicookies parameter for session-based auth flows
  • DB schema exposure — reads Prisma/Drizzle/TypeORM schema; auto-registers get_db_schema agent tool; included in registry payload
  • Registry payload — Includes version, environment, authSummary, dbSchema, and per-route tables auto-computed
  • Manual registry push — POST route list + schemas to a central server on demand
  • Alert notifications — LINE, Email, Telegram
  • Prometheus export — Ready for Grafana/Prometheus
  • Prisma integration — Database query monitoring + auto-generate agent tools
  • Env auto-config — Zero code change via VITALS_* environment variables
  • TypeScript first — Full type safety

Installation

npm install vitals-node

Quick Start

NestJS

import { Module } from '@nestjs/common';
import { VitalsPulseModule } from 'vitals-node';

@Module({
  imports: [
    VitalsPulseModule.forRoot({
      mode: 'both',
      agent: { enabled: true, apiKey: process.env.VITALS_AGENT_API_KEY }
    })
  ]
})
export class AppModule {}

With mode: 'both' NestJS registers two controllers automatically:

  • HealthController — mounts at /health
  • AgentsController — mounts at /agents

Express

import express from 'express';
import { expressPulse } from 'vitals-node/express';

const app = express();
app.use(express.json());

app.use('/health', expressPulse({ app, mode: 'monitor' }));
app.use('/agents', expressPulse({ app, mode: 'agent', agent: { apiKey: process.env.VITALS_AGENT_API_KEY } }));

app.listen(3000);

Bun

import { bunPulse } from 'vitals-node/bun';

const pulse = bunPulse({ mode: 'both' });

Bun.serve({
  port: 3000,
  fetch(req) {
    const url = new URL(req.url);
    if (url.pathname.startsWith('/health')) return pulse.handler(req);
    return new Response('OK');
  }
});

Mode System

| Mode | What it enables | Metrics interval | |---|---|---| | monitor | health, metrics, dashboard, prometheus, alerts | runs | | agent | route discovery, AI tools, registry push, call_api | skipped (saves resources) | | both | all features (default) | runs |

In NestJS mode: 'both' creates two separate controllers: HealthController at /health and AgentsController at /agents. In Express/Bun you mount each middleware at the path you choose.


Endpoints

Monitor endpoints

Available when mode: 'monitor' or 'both' (mounted at your chosen base path, e.g. /health):

| Endpoint | Description | |---|---| | GET /health | Liveness probe | | GET /health/detailed | Full system metrics + health checks | | GET /health/dashboard | Real-time HTML dashboard | | GET /health/metrics | Prometheus format | | GET /health/prometheus | Prometheus format (alias) | | GET /health/history | Metrics history | | GET /health/alerts | Alert history | | POST /health/test-alerts | Test notification channels |

Monitor endpoints (additional)

| Endpoint | Description | |---|---| | GET /health/raw | Raw system metrics (JSON) |

Agent endpoints

Available when mode: 'agent' or 'both'. NestJS uses /agents/*; Express/Bun use the path you mount with mode: 'agent':

| Endpoint | Description | |---|---| | GET /agents/routes | All discovered routes with inferred schemas and auth requirements | | GET /agents/tools | Agent tool schemas (Anthropic format) | | GET /agents/schema/status | Schema analysis progress snapshot | | GET /agents/schema/stream | Live SSE stream of schema analysis progress | | POST /agents/invoke | Invoke an agent tool { name, input } | | POST /agents/registry/push | Manually push registry to a webhook |

All agent endpoints require Authorization: Bearer <apiKey> when agent.apiKey is set.

In Express/Bun with mode: 'both', agent endpoints are nested under the monitor base path: /health/agent/tools, /health/agent/schema/status, /health/agent/schema/stream, /health/agent/invoke, /health/agent/registry/push.


NestJS Controllers

VitalsPulseModule.forRoot() registers controllers based on mode:

mode: 'monitor' → HealthController  at /health
mode: 'agent'   → AgentsController at /agents
mode: 'both'    → both controllers (default)

You can import the controllers directly for custom configuration:

import { HealthController, AgentsController, PULSE_MONITOR } from 'vitals-node';

Environment Variables

Target projects only need VITALS_AGENT_API_KEY — all other config is passed in request bodies.

| Variable | Description | |---|---| | VITALS_MODE | monitor · agent · both | | VITALS_PATH | Base path override | | VITALS_AGENT_ENABLED | true to enable agent endpoints | | VITALS_AGENT_API_KEY | Bearer token for /agents/* protection |


Manual Registry Push

Registry push is triggered on demand via POST /agents/registry/push. No config is stored in the target project — all parameters come from the request body.

POST /agents/registry/push
Authorization: Bearer <apiKey>

{
  "webhook": "https://central-server.com/register",  // optional — omit to get data in response only
  "groupId": "my-company",                           // optional — group multiple services together
  "projectId": "my-service",
  "projectPath": "/api",                             // optional — override auto-detected base path
  "tags": "crm,billing",                             // optional — help AI categorize this service
  "apiKey": "central-server-bearer-token",
  "baseUrl": "https://my-service.example.com",
  "schemaAnalysis": {                                 // optional — run AI schema analysis before push
    "provider": "anthropic",
    "apiKey": "sk-ant-xxx",
    "model": "claude-haiku-4-5-20251001"
  }
}

Response always includes the full payload (same data sent to webhook):

{
  "success": true,
  "groupId": "my-company",
  "projectId": "my-service",
  "baseUrl": "https://my-service.example.com",
  "projectPath": "/api",
  "tags": "crm,billing",
  "version": "2.3.1",
  "environment": "production",
  "authSummary": {
    "types": ["cookie", "none"],
    "cookieNames": ["session"],
    "loginPaths": ["/api/auth/login"],
    "publicRoutes": 2,
    "protectedRoutes": 6
  },
  "routes": [
    {
      "method": "GET",
      "path": "/api/orders",
      "tables": ["Order", "OrderItem"],
      "schema": { "query": { "status": { "type": "string", "required": false } } },
      "auth": { "guards": ["CookieAuthGuard"], "isPublic": false, "requirements": { "type": "cookie", "cookieName": "session", "description": "..." } }
    }
  ],
  "agentTools": [...],
  "dbSchema": [
    {
      "orm": "prisma",
      "tables": [
        { "name": "Order", "columns": [{ "name": "id", "type": "String", "nullable": false, "isPrimary": true }] }
      ],
      "readAt": 1748247600000
    }
  ],
  "registeredAt": 1748247600000
}

Auto-populated fields (no config needed):

  • version — read from the project's package.json
  • environment — from NODE_ENV
  • authSummary — computed from per-route auth.requirements detected by guard scanning
  • dbSchema — included when dbSchema is configured at startup (Prisma/Drizzle/TypeORM)
  • routes[].tables — included when schemaAnalysis.tableDetection is set
  • handler is stripped from routes before push — it is an internal implementation detail

If webhook is omitted the push is skipped but the response still contains the full payload — useful for inspecting what would be sent.


AI Schema Analysis

Pass schemaAnalysis in the POST /agents/registry/push body to run schema inference before pushing. No API keys are stored in the target project.

Using Anthropic Claude

{
  "schemaAnalysis": {
    "provider": "anthropic",
    "apiKey": "sk-ant-xxx",
    "model": "claude-haiku-4-5-20251001",
    "concurrency": 5,
    "timeout": 30000,
    "tableDetection": "auto"
  }
}

Using Ollama (local LLM)

{
  "schemaAnalysis": {
    "provider": "ollama",
    "baseUrl": "http://localhost:11434",
    "model": "llama3.2",
    "concurrency": 1,
    "timeout": 120000,
    "tableDetection": "static"
  }
}

How it works

  1. Routes are discovered from the running app
  2. Handler source is located per framework:
    • NestJS — searches @Get('segment') / @Post('segment') decorators (handler names are empty at runtime)
    • Express — uses function name if available; falls back to .get('/path', handler) call-site lookup for anonymous handlers
    • Bun (Elysia/Hono) — matches .post('/path', handler) call sites; captures inline Elysia schema definitions automatically
  3. Source files are loaded once into a cache and reused across all routes
  4. Handler body is extracted using brace-counting (not a fixed line limit) to capture the full function
  5. DTO resolution — when a parameter is typed as any, vitals follows the service call chain:
    • Detects this.someService.method(body) → finds method(dto: CreateUserDto) in @Injectable files → finds class CreateUserDto { ... } → appends to LLM context
  6. LLM returns body / params / query schema as JSON; fields that cannot be determined use type "any"
  7. Schemas are merged into /agents/routes and included in the push payload

Field types

| Type | When used | |---|---| | string number boolean object array | LLM determined the type from source | | any | Type is any and no DTO chain was resolvable — check description for hints |

Example schema output

{
  "method": "POST",
  "path": "/credits/adjust",
  "tables": ["CreditTransaction", "User"],
  "schema": {
    "description": "Adjust credit balance for a user account",
    "body": {
      "userId":  { "type": "string", "description": "Target user ID",                "required": true  },
      "amount":  { "type": "number", "description": "Amount — positive adds, negative deducts", "required": true  },
      "reason":  { "type": "string", "description": "Reason for adjustment",         "required": false }
    }
  }
}

Schema Analysis Progress

When POST /agents/registry/push with schemaAnalysis is called, schema inference runs in the background. Poll the progress or stream it in real time.

Snapshot

GET /agents/schema/status
Authorization: Bearer <apiKey>
{
  "status": "running",
  "total": 12,
  "completed": 5,
  "staticCount": 3,
  "llmCount": 2,
  "currentRoute": "POST /api/orders",
  "startedAt": 1750161600000,
  "eta": 4200
}

Live SSE stream

GET /agents/schema/stream
Authorization: Bearer <apiKey>

Server-Sent Events — one data: frame every ~300 ms until status is "done" or "error", then the connection closes automatically.

const es = new EventSource('/agents/schema/stream', {
  headers: { Authorization: `Bearer ${apiKey}` }
});
es.onmessage = ({ data }) => console.log(JSON.parse(data));

Progress fields

| Field | Description | |---|---| | status | idle · running · done · error | | total | Total routes to process | | completed | Routes processed so far | | staticCount | Routes resolved by static regex (no LLM call) | | llmCount | Routes sent to the LLM | | currentRoute | Route currently being processed | | startedAt | Unix ms when analysis started | | finishedAt | Unix ms when analysis finished (once done) | | elapsedMs | Wall-clock ms elapsed | | eta | Estimated ms remaining (only while running) |


Per-Route Table Detection

When tableDetection is set in schemaAnalysis, vitals detects which database tables each route reads or writes and adds a tables: string[] field to every route entry.

Modes

| Mode | Behaviour | |---|---| | 'static' | Regex scan only — no LLM cost, runs instantly | | 'llm' | Always asks the LLM — more accurate for complex patterns | | 'auto' | Static first; if nothing found, falls back to LLM |

What is detected

Prismathis.prisma.user.findMany(), prisma.order.create(), etc.

Drizzledb.select().from(orders), db.insert(users).values(...), db.update(products)

TypeORMgetRepository(Entity), @InjectRepository(Entity), Repository<Entity>

Service following

If a handler delegates to a service (this.orderService.create(dto)), vitals finds the service class in the source files and scans that method body too — one level deep:

// Handler → delegates
async create(@Body() dto: CreateOrderDto) {
  return this.orderService.create(dto);   // ← vitals follows this
}

// OrderService.create → vitals scans this for DB calls
async create(dto: CreateOrderDto) {
  const order = await this.prisma.order.create({ data: dto });   // → "Order" detected
  await this.prisma.orderItem.createMany({ data: dto.items });   // → "OrderItem" detected
  return order;
}

Names are normalized to PascalCase (prisma.orderItem"OrderItem").


DB Schema Exposure

Configure dbSchema at startup to read your ORM schema and expose it as an agent tool:

import { PrismaClient, Prisma } from '@prisma/client';

VitalsPulseModule.forRoot({
  mode: 'both',
  dbSchema: {
    prisma: { client: prisma, dmmf: Prisma.dmmf }
    // drizzle: { schema: drizzleSchema }
    // typeorm: { dataSource: AppDataSource }
  }
});

This automatically:

  1. Registers a get_db_schema agent tool the AI can call
  2. Includes the full table/column schema in the registry push payload under dbSchema

get_db_schema tool

POST /agents/invoke
{ "name": "get_db_schema", "input": { "orm": "prisma", "table": "order" } }

| Parameter | Required | Description | |---|---|---| | orm | no | Filter: prisma · drizzle · typeorm. Omit to return all. | | table | no | Case-insensitive partial match on table name. Omit to return all tables. |

Supported ORMs

| ORM | Config key | How schema is read | |---|---|---| | Prisma | prisma.client | Via Prisma.dmmf (pass dmmf for reliability) | | Drizzle | drizzle.schema | import * as schema from './db/schema' | | TypeORM | typeorm.dataSource | Initialized DataSource instance |

Multiple ORMs can be configured at once — each appears as a separate entry in dbSchema.


Auth Detection

When schemaAnalysis is active, vitals automatically scans source files for auth guards per route. No extra config required.

What is detected

  • @UseGuards(GuardClass) at method and class level
  • Global guards registered via APP_GUARD or app.useGlobalGuards()
  • @Public() / @IsPublic() / @SkipAuth() opt-out decorators
  • Passport strategy source (resolved by strategy key string, not class name convention)

Auth requirements in routes

{
  "method": "GET",
  "path": "/api/orders",
  "auth": {
    "guards": ["CookieAuthGuard"],
    "isPublic": false,
    "requirements": {
      "type": "cookie",
      "cookieName": "session",
      "description": "Requires valid session cookie issued by POST /api/auth/login"
    }
  }
}

Auth types: bearer · cookie · apikey · none · custom

Auth summary in registry payload

The registry payload includes a service-level summary so AI agents know the auth pattern at a glance:

"authSummary": {
  "types": ["cookie", "none"],
  "cookieNames": ["session"],
  "loginPaths": ["/api/auth/login"],
  "publicRoutes": 2,
  "protectedRoutes": 6
}

call_api Built-in Tool

When vitals starts, it auto-registers a call_api tool that lets the AI invoke any route on the service directly.

POST /agents/invoke
Authorization: Bearer <apiKey>

{
  "name": "call_api",
  "input": {
    "method": "POST",
    "path": "/api/auth/login",
    "body": { "email": "[email protected]", "password": "secret" }
  }
}

→ { "result": { "status": 200, "ok": true, "body": { "token": "..." } } }

Parameters

| Parameter | Type | Required | Description | |---|---|---|---| | method | string | yes | GET POST PUT PATCH DELETE | | path | string | yes | API path e.g. /api/users/123 | | body | object | no | Request body for POST/PUT/PATCH | | headers | object | no | Extra request headers e.g. { "Authorization": "Bearer <token>" } | | cookies | object | no | Cookies to send e.g. { "session": "<value>" } — use when route auth.requirements.type is "cookie" | | query | object | no | Query string params |

Handling cookie-protected routes

Check auth.requirements on the route first, then use the cookies parameter:

{
  "name": "call_api",
  "input": {
    "method": "GET",
    "path": "/api/orders",
    "cookies": { "session": "<session_value>" }
  }
}

Typical flow for cookie auth:

1. call_api POST /api/auth/login { email, password }
   → response Set-Cookie: session=abc123

2. call_api GET /api/orders
   cookies: { "session": "abc123" }
   → protected route accessed successfully

The tool description instructs Claude to check auth.requirements from GET /agents/routes before calling, so the AI knows which credential type to use.


AI Agent Flow

customer reports problem
  → chat → AI agent (Claude)
    → GET /agents/routes    — discover APIs, schemas, and auth requirements
    → GET /agents/tools     — discover invokable diagnostic tools
    → POST /agents/invoke   — call the right tool or API to fix the problem
  → response to customer

Example: agent fixes a credit mismatch

// AI discovers routes and tools, then calls:
POST /agents/invoke
{ "name": "adjust_credit", "input": { "userId": "U123", "amount": 100 } }
→ { "result": { "success": true, "newBalance": 500 } }

// Or directly calls the API:
POST /agents/invoke
{ "name": "call_api", "input": { "method": "POST", "path": "/credits/adjust", "body": { "userId": "U123", "amount": 100 } } }
→ { "result": { "status": 200, "ok": true, "body": { "success": true } } }

Example: agent calls a cookie-protected route

// Step 1 — login
POST /agents/invoke
{ "name": "call_api", "input": { "method": "POST", "path": "/api/auth/login", "body": { "email": "...", "password": "..." } } }
→ Set-Cookie: session=abc123

// Step 2 — call protected route
POST /agents/invoke
{ "name": "call_api", "input": { "method": "GET", "path": "/api/orders", "cookies": { "session": "abc123" } } }
→ { "orders": [...] }

Route Discovery

NestJS

Routes are captured automatically via OnApplicationBootstrap lifecycle hook.

Express

Discovery is lazy — routes registered after the middleware call are still captured.

app.use('/health', expressPulse({ app }));
// All routes registered below are still discovered
app.get('/api/orders', handler);

Fastify

monitor.discoverRoutes(fastifyApp, 'fastify');

Manual Registration

import { createMonitor } from 'vitals-node/core';

const monitor = createMonitor();

monitor.registerRoute({ method: 'GET', path: '/api/orders', handler: 'OrderController.list' });
monitor.registerRoutes([
  { method: 'POST', path: '/api/orders' },
  { method: 'PUT',  path: '/api/orders/:id/status' }
]);

// Manual schema annotation — overrides AI analysis for this route
monitor.annotateRoute('POST', '/api/orders', {
  description: 'Create a new order',
  body: {
    userId: { type: 'string', description: 'User ID', required: true },
    items:  { type: 'array',  description: 'Order items',  required: true }
  }
});

Configuration Reference

interface VitalsConfig {
  mode?: 'monitor' | 'agent' | 'both';  // default: 'both'
  path?: string;                          // default: '/health'
  dashboard?: boolean;                    // default: true
  collectInterval?: number;              // ms (default: 5000)
  timezone?: string;                     // default: 'Asia/Bangkok'
  prometheus?: boolean;                  // default: true

  alerts?: {
    thresholds?: {
      cpu?: number;          // default: 80%
      memory?: number;       // default: 90%
      disk?: number;         // default: 85%
      responseTime?: number; // default: 3000ms
    };
    cooldown?: number;       // ms between alerts (default: 5 min)
    line?:     { token: string; enabled?: boolean };
    email?:    { host: string; port: number; user: string; password: string; from: string; to: string[]; secure?: boolean };
    telegram?: { botToken: string; chatId: string; enabled?: boolean };
  };

  healthChecks?: HealthCheckDefinition[];

  agent?: {
    enabled?: boolean;        // must be true to expose /agent/* endpoints
    apiKey?: string;          // Bearer token protecting agent endpoints
    tools?: AgentToolDefinition[];
  };

  dbSchema?: {
    prisma?:  { client: PrismaClient; dmmf?: typeof Prisma.dmmf };
    drizzle?: { schema: Record<string, unknown> };
    typeorm?: { dataSource: DataSource };
  };
}

schemaAnalysis (including tableDetection) and registry config are passed in the POST /agents/registry/push request body, not in startup config — this keeps secrets out of the target project's environment.

// schemaAnalysis options (in request body)
{
  provider?: 'anthropic' | 'ollama';    // default: 'anthropic'
  apiKey?: string;                       // Anthropic key (or ANTHROPIC_API_KEY env)
  model?: string;                        // default: claude-haiku-4-5-20251001
  sourceDir?: string;                   // path to .ts source files (default: cwd)
  concurrency?: number;                 // parallel LLM calls (default: 5)
  timeout?: number;                     // ms per call (default: 30000)
  guards?: boolean;                     // auth guard scanning (default: true)
  tableDetection?: 'static' | 'llm' | 'auto';  // per-route table detection
}

Custom Health Checks

monitor.addHealthCheck({
  name: 'redis',
  critical: true,
  timeout: 5000,
  check: async () => {
    const start = Date.now();
    try {
      await redis.ping();
      return { name: 'redis', status: 'healthy', responseTime: Date.now() - start };
    } catch (err) {
      return { name: 'redis', status: 'unhealthy', responseTime: Date.now() - start, error: err.message };
    }
  }
});

Agent Tools

Register custom tools that the AI can invoke via POST /agents/invoke:

import { getMonitor } from 'vitals-node/core';

getMonitor().registerAgentTool({
  name: 'adjust_credit',
  description: 'Adjust user credit balance',
  parameters: {
    userId: { type: 'string', description: 'User ID', required: true },
    amount: { type: 'number', description: 'Amount to adjust (+/-)', required: true }
  },
  handler: async ({ userId, amount }) =>
    creditService.adjust(String(userId), Number(amount))
});

Tool schemas follow the Anthropic input_schema format — compatible with Claude tool use directly.


Prisma Integration

import { PrismaClient } from '@prisma/client';
import { prismaMiddleware, createPrismaHealthCheck, createPrismaAgentTools } from 'vitals-node/prisma';
import { getMonitor } from 'vitals-node/core';

const prisma = new PrismaClient();

prisma.$use(prismaMiddleware({ slowQueryThreshold: 1000, logSlowQueries: true }));

const monitor = getMonitor();
monitor.addHealthCheck(createPrismaHealthCheck(prisma));

const tools = createPrismaAgentTools(prisma, {
  dmmf: Prisma.dmmf,
  models: ['User', 'CreditTransaction'],
  sensitiveFields: ['internalNote']
});
monitor.registerAgentTools(tools);

System Metrics

{
  "cpu":     { "usage": 45.5, "cores": 8, "model": "Intel...", "speed": 3.2 },
  "memory":  { "total": 16384, "used": 8192, "free": 8192, "percentage": 50 },
  "disk":    { "total": 512000, "used": 256000, "free": 256000, "percentage": 50 },
  "process": { "uptime": 86400, "pid": 1234, "nodeVersion": "v20.0.0", "memoryUsage": 128, "cpuUsage": 2.5 }
}

Event Handling

const monitor = getMonitor();

monitor.on('metrics:collected', (event) => console.log('Metrics:', event.data));
monitor.on('alert:triggered',   (event) => console.log('Alert!',   event.data));

Available events: metrics:collected · alert:triggered · alert:resolved · health:changed · database:slow-query · database:error


Prometheus / Grafana

scrape_configs:
  - job_name: 'my-app'
    static_configs:
      - targets: ['localhost:3000']
    metrics_path: '/health/metrics'

Alert Configuration

LINE Notify

alerts: { line: { token: 'YOUR_LINE_NOTIFY_TOKEN' } }

Telegram

alerts: { telegram: { botToken: 'BOT_TOKEN', chatId: 'CHAT_ID' } }

Email (SMTP)

alerts: { email: { host: 'smtp.gmail.com', port: 587, user: '...', password: '...', from: '...', to: ['admin@...'] } }

API Reference

NestJS

import { VitalsPulseModule, NestPulseModule } from 'vitals-node';

// in AppModule.imports:
VitalsPulseModule.forRoot(options)  // recommended
NestPulseModule.forRoot(options)    // alias

Express

import { expressPulse, createExpressRouter } from 'vitals-node/express';

app.use('/health', expressPulse(options));       // middleware
app.use('/health', createExpressRouter(options)); // router variant

Bun

import { bunPulse, withBunPulse } from 'vitals-node/bun';

const pulse = bunPulse(options);
// pulse.handler(req) — use in Bun.serve fetch

Bun.serve(withBunPulse({ ...options, fetch(req) { return new Response('OK'); } }));

Core (Standalone)

import { createMonitor, getMonitor } from 'vitals-node/core';

const monitor = createMonitor(options);
await monitor.start();

// Metrics
const metrics  = await monitor.getMetrics();
const health   = await monitor.getHealth();
const detailed = await monitor.getDetailedHealth();

// Routes
monitor.discoverRoutes(app, 'express');
monitor.registerRoute({ method: 'GET', path: '/api/orders' });
monitor.annotateRoute('POST', '/api/orders', schema);
await monitor.analyzeRouteSchemas(schemaAnalysisConfig);
const registry = monitor.getRoutes();

// Registry push
const payload = await monitor.buildRegistryPayload({ groupId, projectId, projectPath, tags, baseUrl });
await monitor.pushRegistryTo({ url: webhook, groupId, projectId, projectPath, tags, apiKey, baseUrl });

// Agent tools
monitor.registerAgentTool(tool);
monitor.registerAgentTools(tools);
monitor.getAgentToolSchemas();
await monitor.invokeAgentTool(name, input);
monitor.enableCallApi('http://localhost:3000');  // register call_api built-in tool

monitor.stop();

Requirements

  • Node.js 18+ or Bun 1.0+
  • TypeScript 5+ (recommended)

License

MIT