Node-Media-Server Agent Skills & AI Rules

GitHub

A Node.js implementation of RTMP/HTTP-FLV Media Server

6,241 stars JavaScript JavaScript 9 files ยท ~34,152 tokens #av1#flv#h264#hevc#livestream#media-server#nodejs#rtmp
RAW Rules
1 Discovered Rules โ€ข ~2,452 Estimated Tokens
Quick:
Loading skill content...

AI Agent Protocol & Instructions

AGENTS.md root-instruction ~2,452 tokens
Raw
# Agent Guidelines for Node-Media-Server

This document provides guidelines for agentic coding agents operating in this repository.

## Repository Purpose

Node-Media-Server is a Node.js implementation of an RTMP media server (v4.x), supporting RTMP publish/play, HTTP-FLV, WebSocket-FLV, RTSP/WHIP, recording, relay, and a REST admin API. Requires Node.js >= 20.

### Directory Layout
- `src/index.js` โ€” library entry point; `bin/app.js` โ€” CLI entry point
- `src/core/` โ€” shared kernel: `context.js` (global `Context` singleton holding config and sessions), `logger.js`, `avpacket.js`, `avcodec.js`
- `src/protocol/` โ€” wire-format codecs (rtmp, flv, amf, rtsp, rtp, rtcp, sdp)
- `src/session/` โ€” per-connection sessions, all extending `base_session.js` (rtmp, flv, record, rtsp)
- `src/server/` โ€” TCP/HTTP listeners and managers (rtmp_server, http_server, broadcast_server, record_server, relay_manager, notify_server)
- `src/api/` โ€” express admin API handlers and middleware (JWT auth)
- `docs/` โ€” protocol and design documentation; read before changing media/protocol code

### Architecture Rules
- Sessions are created by servers and registered in `Context.sessions`; servers look up/relay streams via `Context`.
- Protocol parsing (`src/protocol/`) is separate from session state machines (`src/session/`) โ€” keep new wire-format code in `src/protocol/`.
- Config is loaded once into `Context.config`; never read config ad hoc from files at runtime.
- HTTP layer (v4.4.0+): one Express 5 app wrapped by npm `http2-express` (`http2Express(express)` in `src/server/http_server.js`) is shared by two listeners: `http.createServer` (HTTP/1.1 + ws) and `http2.createSecureServer({ allowHTTP1: true })` (h2/h1 + wss). The old vendored shim `src/vendor/http2-express/` is gone โ€” never reintroduce it.
- Express 5 uses path-to-regexp v8: routes must avoid Express 4 legacy syntax (`*` wildcards, optional `:x?` params, regex routes). The FLV catch-all `app.all("/:app/:name.flv", ...)` and `test/http2.test.js` guard this wiring; run both when touching HTTP code.
- FLV sessions (`src/session/flv_session.js`) serve HTTP-FLV and WebSocket-FLV from the same class (`res instanceof WebSocket` branch); the write path is raw `res.write`/`res.end`, framework-independent.

## Build/Lint/Test Commands

### Available Scripts
```bash
# Development mode - runs eslint and starts server
npm run dev

# Production start (loads bin/config.json)
npm start

# Tests: node:test runner, ~72 tests over test/*.test.js
npm test

# Single test file
node --test test/http2.test.js

# Docker image (node:lts-alpine, multi-stage with webadmin build)
docker build -t nms .
```

### Linting
```bash
# Run eslint on all files (flat config, eslint 9; expects 0 errors, ~25 pre-existing jsdoc warnings)
npx eslint

# Fix auto-fixable eslint issues
npx eslint --fix

# Check specific file
npx eslint src/index.js
```

### Type Checking (informational, not wired into CI)
`@types/express` and `@types/node` are devDependencies. Spot-check with:
```bash
npx -y -p typescript tsc --noEmit --allowJs --checkJs --skipLibCheck src/api/handlers/records.js
```
There are known pre-existing findings (~73); do not treat new tsc output as a gate.

### Manual Testing
Automated tests cover the API middleware chain and HTTP wiring. For media-path changes, also smoke-test end to end:

1. **RTMP Stream Testing**:
   ```bash
   # Start server
   npm start

   # Test with ffmpeg
   ffmpeg -re -i input.mp4 -c copy -f flv rtmp://localhost:1935/live/stream
   ffmpeg -i rtmp://localhost:1935/live/stream -c copy output.mp4
   ```

2. **HTTP-FLV / HTTP2-FLV Testing**:
   ```bash
   # HTTP/1.1 pull
   curl http://localhost:8000/live/stream.flv
   # HTTP/2 pull (verify ver=2 in output)
   curl -k --http2 https://localhost:8443/live/stream.flv
   # WebSocket-FLV: ws://localhost:8000/live/stream.flv / wss://localhost:8443/live/stream.flv
   ```

3. **API Testing** (API rides on the HTTP ports, not a separate port):
   ```bash
   # Health check
   curl http://localhost:8000/api/v1/health

   # Login
   curl -X POST http://localhost:8000/api/v1/login \
     -H "Content-Type: application/json" \
     -d '{"username":"admin","password":"your_password"}'
   ```

## Runtime Gotchas

- **`bin/config.json` is mutated at runtime**: on first start, `bin/app.js` generates a random admin password (printed once to stdout) and a JWT secret, then writes them back โ€” running the server dirties the working tree. Back it up before and restore after test runs.
- Login lockout is in-memory (`AuthHandler.failedAttempts`): 5 consecutive failures lock the user+IP pair for 15 minutes; login rate limit is 10/min. Both reset on restart โ€” do lockout/rate-limit tests last in a test session.
- `data/`, `record/`, `logs/`, `.tmp/`, `webadmin/dist` are gitignored runtime/build artifacts; `.tmp/` is the conventional scratch space for agent work.
- The API layer (routes, JWT, rate limit) only activates when `auth.jwt` is configured in `bin/config.json`; TLS needs `key.pem`/`cert.pem` next to it.
- CI (`.github/workflows/npm.yml`) runs on Node 24: `npm ci`, `npm test`; npm publish triggers on `v*` tags via `prepublishOnly` (rebuilds webadmin).

## Code Style Guidelines

### File Headers
All files must include copyright header:
```javascript
// @ts-check
//
//  Created by Chen Mingliang on 24/11/28.
//  [email protected]
//  Copyright (c) 2024 NodeMedia. All rights reserved.
//
```

### TypeScript Checking
- Use `// @ts-check` at the top of all JavaScript files
- Add JSDoc comments for function parameters and return types
- Use JSDoc types: `{string}`, `{number}`, `{boolean}`, `{object}`, `{Array<string>}`
- For express types, use typedef imports (not `{express.Request}`):
  ```javascript
  /** @typedef {import("express").Request} Request */
  /** @typedef {import("express").Response} Response */
  ```
  `jsdoc/no-undefined-types` flags bare `express.*` types. Closure-style function types (`{function(a): b}`) are not parseable by TypeScript โ€” use the arrow form `{(v: any) => string | null}`.

### Code Formatting
- Use **double quotes** for strings
- Use **semicolons** at end of statements
- Use **2 spaces** for indentation
- Use **camelCase** for variables and functions
- Use **PascalCase** for classes

### Import/Require Guidelines
```javascript
// Node.js modules
const fs = require("fs");
const net = require("net");

// Relative imports (use .js extension)
const logger = require("./core/logger.js");
const Context = require("../core/context.js");
const BaseSession = require("./base_session.js");

// Express and web modules
const express = require("express");
const cors = require("cors");
```

### Function Documentation
```javascript
/**
 * Brief description of function
 * @param {string} paramName - Description of parameter
 * @param {number} paramName2 - Description of parameter
 * @returns {boolean} Description of return value
 */
function exampleFunction(paramName, paramName2) {
  return true;
}

/**
 * @class
 * @augments BaseClass
 */
class ExampleClass extends BaseClass {
  /**
   * @param {net.Socket} socket - The socket connection
   */
  constructor(socket) {
    super();
    this.socket = socket;
  }
}
```

### Variable Naming Conventions
- **Constants**: `UPPER_SNAKE_CASE`
- **Classes**: `PascalCase`
- **Functions/Variables**: `camelCase`
- **Private properties**: `_prefixWithUnderscore`

```javascript
// Constants
const MAX_BUFFER_SIZE = 1024 * 1024;
const DEFAULT_TIMEOUT = 5000;

// Classes
class RtmpSession extends BaseSession {
  constructor(socket) {
    super();
    this._privateProperty = value;
    this.publicProperty = value;
  }
}
```

### Error Handling
```javascript
// Use try-catch for async operations
try {
  const result = await someAsyncOperation();
  res.json({ success: true, data: result });
} catch (error) {
  logger.error(`Operation failed: ${error.message}`);
  res.status(500).json({
    success: false,
    error: "Internal server error"
  });
}

// Use logger for different log levels
logger.trace("Detailed trace message");
logger.debug("Debug information");
logger.info("General information");
logger.warn("Warning message");
logger.error("Error message");
```

### Protocol and Session Patterns
- Each protocol extends `BaseSession`
- Use composition over inheritance for protocol-specific features
- Follow established patterns in existing session classes

### JWT and Authentication
- Use the middleware pattern for authentication
- Handle JWT errors with proper error handling middleware
- Always validate token expiration and validity

### Configuration Management
- Access configuration through `Context.config`
- Use optional chaining for safe property access
- Provide sensible defaults for missing configuration

### Security Considerations
- Never log sensitive information (passwords, tokens)
- Use scrypt hashing for password storage in the API (`src/api/handlers/password_hash.js`; plaintext is migrated to scrypt on startup)
- Validate all input parameters
- Use CORS appropriately for cross-origin requests

### Performance Guidelines
- Use Maps for session management (not arrays)
- Implement proper cleanup in close/error handlers
- Minimize blocking operations in event handlers
- Use efficient data structures for broadcast management

### API Design
- Follow REST conventions for API endpoints
- Use consistent response format:
  ```javascript
  {
    success: true|false,
    data: {},
    message: "Optional message",
    error: "Error details if success=false"
  }
  ```
- Implement proper HTTP status codes
- Add comprehensive error handling

### File Organization
- Keep related functionality in same directory
- Use clear, descriptive file names
- Group API handlers by functionality
- Separate protocol implementations

This codebase follows a professional Node.js server architecture with emphasis on performance, security, and maintainability. Always test thoroughly after making changes.