{"owner":"illuspas","repo":"Node-Media-Server","hasSkills":true,"totalSkillsCount":1,"totalTokensCount":2452,"categories":["root-instruction"],"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md"],"skills":{"AGENTS.md":"# Agent Guidelines for Node-Media-Server\n\nThis document provides guidelines for agentic coding agents operating in this repository.\n\n## Repository Purpose\n\nNode-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.\n\n### Directory Layout\n- `src/index.js` — library entry point; `bin/app.js` — CLI entry point\n- `src/core/` — shared kernel: `context.js` (global `Context` singleton holding config and sessions), `logger.js`, `avpacket.js`, `avcodec.js`\n- `src/protocol/` — wire-format codecs (rtmp, flv, amf, rtsp, rtp, rtcp, sdp)\n- `src/session/` — per-connection sessions, all extending `base_session.js` (rtmp, flv, record, rtsp)\n- `src/server/` — TCP/HTTP listeners and managers (rtmp_server, http_server, broadcast_server, record_server, relay_manager, notify_server)\n- `src/api/` — express admin API handlers and middleware (JWT auth)\n- `docs/` — protocol and design documentation; read before changing media/protocol code\n\n### Architecture Rules\n- Sessions are created by servers and registered in `Context.sessions`; servers look up/relay streams via `Context`.\n- Protocol parsing (`src/protocol/`) is separate from session state machines (`src/session/`) — keep new wire-format code in `src/protocol/`.\n- Config is loaded once into `Context.config`; never read config ad hoc from files at runtime.\n- 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.\n- 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.\n- 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.\n\n## Build/Lint/Test Commands\n\n### Available Scripts\n```bash\n# Development mode - runs eslint and starts server\nnpm run dev\n\n# Production start (loads bin/config.json)\nnpm start\n\n# Tests: node:test runner, ~72 tests over test/*.test.js\nnpm test\n\n# Single test file\nnode --test test/http2.test.js\n\n# Docker image (node:lts-alpine, multi-stage with webadmin build)\ndocker build -t nms .\n```\n\n### Linting\n```bash\n# Run eslint on all files (flat config, eslint 9; expects 0 errors, ~25 pre-existing jsdoc warnings)\nnpx eslint\n\n# Fix auto-fixable eslint issues\nnpx eslint --fix\n\n# Check specific file\nnpx eslint src/index.js\n```\n\n### Type Checking (informational, not wired into CI)\n`@types/express` and `@types/node` are devDependencies. Spot-check with:\n```bash\nnpx -y -p typescript tsc --noEmit --allowJs --checkJs --skipLibCheck src/api/handlers/records.js\n```\nThere are known pre-existing findings (~73); do not treat new tsc output as a gate.\n\n### Manual Testing\nAutomated tests cover the API middleware chain and HTTP wiring. For media-path changes, also smoke-test end to end:\n\n1. **RTMP Stream Testing**:\n   ```bash\n   # Start server\n   npm start\n\n   # Test with ffmpeg\n   ffmpeg -re -i input.mp4 -c copy -f flv rtmp://localhost:1935/live/stream\n   ffmpeg -i rtmp://localhost:1935/live/stream -c copy output.mp4\n   ```\n\n2. **HTTP-FLV / HTTP2-FLV Testing**:\n   ```bash\n   # HTTP/1.1 pull\n   curl http://localhost:8000/live/stream.flv\n   # HTTP/2 pull (verify ver=2 in output)\n   curl -k --http2 https://localhost:8443/live/stream.flv\n   # WebSocket-FLV: ws://localhost:8000/live/stream.flv / wss://localhost:8443/live/stream.flv\n   ```\n\n3. **API Testing** (API rides on the HTTP ports, not a separate port):\n   ```bash\n   # Health check\n   curl http://localhost:8000/api/v1/health\n\n   # Login\n   curl -X POST http://localhost:8000/api/v1/login \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\"username\":\"admin\",\"password\":\"your_password\"}'\n   ```\n\n## Runtime Gotchas\n\n- **`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.\n- 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.\n- `data/`, `record/`, `logs/`, `.tmp/`, `webadmin/dist` are gitignored runtime/build artifacts; `.tmp/` is the conventional scratch space for agent work.\n- 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.\n- CI (`.github/workflows/npm.yml`) runs on Node 24: `npm ci`, `npm test`; npm publish triggers on `v*` tags via `prepublishOnly` (rebuilds webadmin).\n\n## Code Style Guidelines\n\n### File Headers\nAll files must include copyright header:\n```javascript\n// @ts-check\n//\n//  Created by Chen Mingliang on 24/11/28.\n//  illuspas@msn.com\n//  Copyright (c) 2024 NodeMedia. All rights reserved.\n//\n```\n\n### TypeScript Checking\n- Use `// @ts-check` at the top of all JavaScript files\n- Add JSDoc comments for function parameters and return types\n- Use JSDoc types: `{string}`, `{number}`, `{boolean}`, `{object}`, `{Array<string>}`\n- For express types, use typedef imports (not `{express.Request}`):\n  ```javascript\n  /** @typedef {import(\"express\").Request} Request */\n  /** @typedef {import(\"express\").Response} Response */\n  ```\n  `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}`.\n\n### Code Formatting\n- Use **double quotes** for strings\n- Use **semicolons** at end of statements\n- Use **2 spaces** for indentation\n- Use **camelCase** for variables and functions\n- Use **PascalCase** for classes\n\n### Import/Require Guidelines\n```javascript\n// Node.js modules\nconst fs = require(\"fs\");\nconst net = require(\"net\");\n\n// Relative imports (use .js extension)\nconst logger = require(\"./core/logger.js\");\nconst Context = require(\"../core/context.js\");\nconst BaseSession = require(\"./base_session.js\");\n\n// Express and web modules\nconst express = require(\"express\");\nconst cors = require(\"cors\");\n```\n\n### Function Documentation\n```javascript\n/**\n * Brief description of function\n * @param {string} paramName - Description of parameter\n * @param {number} paramName2 - Description of parameter\n * @returns {boolean} Description of return value\n */\nfunction exampleFunction(paramName, paramName2) {\n  return true;\n}\n\n/**\n * @class\n * @augments BaseClass\n */\nclass ExampleClass extends BaseClass {\n  /**\n   * @param {net.Socket} socket - The socket connection\n   */\n  constructor(socket) {\n    super();\n    this.socket = socket;\n  }\n}\n```\n\n### Variable Naming Conventions\n- **Constants**: `UPPER_SNAKE_CASE`\n- **Classes**: `PascalCase`\n- **Functions/Variables**: `camelCase`\n- **Private properties**: `_prefixWithUnderscore`\n\n```javascript\n// Constants\nconst MAX_BUFFER_SIZE = 1024 * 1024;\nconst DEFAULT_TIMEOUT = 5000;\n\n// Classes\nclass RtmpSession extends BaseSession {\n  constructor(socket) {\n    super();\n    this._privateProperty = value;\n    this.publicProperty = value;\n  }\n}\n```\n\n### Error Handling\n```javascript\n// Use try-catch for async operations\ntry {\n  const result = await someAsyncOperation();\n  res.json({ success: true, data: result });\n} catch (error) {\n  logger.error(`Operation failed: ${error.message}`);\n  res.status(500).json({\n    success: false,\n    error: \"Internal server error\"\n  });\n}\n\n// Use logger for different log levels\nlogger.trace(\"Detailed trace message\");\nlogger.debug(\"Debug information\");\nlogger.info(\"General information\");\nlogger.warn(\"Warning message\");\nlogger.error(\"Error message\");\n```\n\n### Protocol and Session Patterns\n- Each protocol extends `BaseSession`\n- Use composition over inheritance for protocol-specific features\n- Follow established patterns in existing session classes\n\n### JWT and Authentication\n- Use the middleware pattern for authentication\n- Handle JWT errors with proper error handling middleware\n- Always validate token expiration and validity\n\n### Configuration Management\n- Access configuration through `Context.config`\n- Use optional chaining for safe property access\n- Provide sensible defaults for missing configuration\n\n### Security Considerations\n- Never log sensitive information (passwords, tokens)\n- Use scrypt hashing for password storage in the API (`src/api/handlers/password_hash.js`; plaintext is migrated to scrypt on startup)\n- Validate all input parameters\n- Use CORS appropriately for cross-origin requests\n\n### Performance Guidelines\n- Use Maps for session management (not arrays)\n- Implement proper cleanup in close/error handlers\n- Minimize blocking operations in event handlers\n- Use efficient data structures for broadcast management\n\n### API Design\n- Follow REST conventions for API endpoints\n- Use consistent response format:\n  ```javascript\n  {\n    success: true|false,\n    data: {},\n    message: \"Optional message\",\n    error: \"Error details if success=false\"\n  }\n  ```\n- Implement proper HTTP status codes\n- Add comprehensive error handling\n\n### File Organization\n- Keep related functionality in same directory\n- Use clear, descriptive file names\n- Group API handlers by functionality\n- Separate protocol implementations\n\nThis codebase follows a professional Node.js server architecture with emphasis on performance, security, and maintainability. Always test thoroughly after making changes."},"files":{"AGENTS.md":"# Agent Guidelines for Node-Media-Server\n\nThis document provides guidelines for agentic coding agents operating in this repository.\n\n## Repository Purpose\n\nNode-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.\n\n### Directory Layout\n- `src/index.js` — library entry point; `bin/app.js` — CLI entry point\n- `src/core/` — shared kernel: `context.js` (global `Context` singleton holding config and sessions), `logger.js`, `avpacket.js`, `avcodec.js`\n- `src/protocol/` — wire-format codecs (rtmp, flv, amf, rtsp, rtp, rtcp, sdp)\n- `src/session/` — per-connection sessions, all extending `base_session.js` (rtmp, flv, record, rtsp)\n- `src/server/` — TCP/HTTP listeners and managers (rtmp_server, http_server, broadcast_server, record_server, relay_manager, notify_server)\n- `src/api/` — express admin API handlers and middleware (JWT auth)\n- `docs/` — protocol and design documentation; read before changing media/protocol code\n\n### Architecture Rules\n- Sessions are created by servers and registered in `Context.sessions`; servers look up/relay streams via `Context`.\n- Protocol parsing (`src/protocol/`) is separate from session state machines (`src/session/`) — keep new wire-format code in `src/protocol/`.\n- Config is loaded once into `Context.config`; never read config ad hoc from files at runtime.\n- 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.\n- 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.\n- 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.\n\n## Build/Lint/Test Commands\n\n### Available Scripts\n```bash\n# Development mode - runs eslint and starts server\nnpm run dev\n\n# Production start (loads bin/config.json)\nnpm start\n\n# Tests: node:test runner, ~72 tests over test/*.test.js\nnpm test\n\n# Single test file\nnode --test test/http2.test.js\n\n# Docker image (node:lts-alpine, multi-stage with webadmin build)\ndocker build -t nms .\n```\n\n### Linting\n```bash\n# Run eslint on all files (flat config, eslint 9; expects 0 errors, ~25 pre-existing jsdoc warnings)\nnpx eslint\n\n# Fix auto-fixable eslint issues\nnpx eslint --fix\n\n# Check specific file\nnpx eslint src/index.js\n```\n\n### Type Checking (informational, not wired into CI)\n`@types/express` and `@types/node` are devDependencies. Spot-check with:\n```bash\nnpx -y -p typescript tsc --noEmit --allowJs --checkJs --skipLibCheck src/api/handlers/records.js\n```\nThere are known pre-existing findings (~73); do not treat new tsc output as a gate.\n\n### Manual Testing\nAutomated tests cover the API middleware chain and HTTP wiring. For media-path changes, also smoke-test end to end:\n\n1. **RTMP Stream Testing**:\n   ```bash\n   # Start server\n   npm start\n\n   # Test with ffmpeg\n   ffmpeg -re -i input.mp4 -c copy -f flv rtmp://localhost:1935/live/stream\n   ffmpeg -i rtmp://localhost:1935/live/stream -c copy output.mp4\n   ```\n\n2. **HTTP-FLV / HTTP2-FLV Testing**:\n   ```bash\n   # HTTP/1.1 pull\n   curl http://localhost:8000/live/stream.flv\n   # HTTP/2 pull (verify ver=2 in output)\n   curl -k --http2 https://localhost:8443/live/stream.flv\n   # WebSocket-FLV: ws://localhost:8000/live/stream.flv / wss://localhost:8443/live/stream.flv\n   ```\n\n3. **API Testing** (API rides on the HTTP ports, not a separate port):\n   ```bash\n   # Health check\n   curl http://localhost:8000/api/v1/health\n\n   # Login\n   curl -X POST http://localhost:8000/api/v1/login \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\"username\":\"admin\",\"password\":\"your_password\"}'\n   ```\n\n## Runtime Gotchas\n\n- **`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.\n- 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.\n- `data/`, `record/`, `logs/`, `.tmp/`, `webadmin/dist` are gitignored runtime/build artifacts; `.tmp/` is the conventional scratch space for agent work.\n- 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.\n- CI (`.github/workflows/npm.yml`) runs on Node 24: `npm ci`, `npm test`; npm publish triggers on `v*` tags via `prepublishOnly` (rebuilds webadmin).\n\n## Code Style Guidelines\n\n### File Headers\nAll files must include copyright header:\n```javascript\n// @ts-check\n//\n//  Created by Chen Mingliang on 24/11/28.\n//  illuspas@msn.com\n//  Copyright (c) 2024 NodeMedia. All rights reserved.\n//\n```\n\n### TypeScript Checking\n- Use `// @ts-check` at the top of all JavaScript files\n- Add JSDoc comments for function parameters and return types\n- Use JSDoc types: `{string}`, `{number}`, `{boolean}`, `{object}`, `{Array<string>}`\n- For express types, use typedef imports (not `{express.Request}`):\n  ```javascript\n  /** @typedef {import(\"express\").Request} Request */\n  /** @typedef {import(\"express\").Response} Response */\n  ```\n  `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}`.\n\n### Code Formatting\n- Use **double quotes** for strings\n- Use **semicolons** at end of statements\n- Use **2 spaces** for indentation\n- Use **camelCase** for variables and functions\n- Use **PascalCase** for classes\n\n### Import/Require Guidelines\n```javascript\n// Node.js modules\nconst fs = require(\"fs\");\nconst net = require(\"net\");\n\n// Relative imports (use .js extension)\nconst logger = require(\"./core/logger.js\");\nconst Context = require(\"../core/context.js\");\nconst BaseSession = require(\"./base_session.js\");\n\n// Express and web modules\nconst express = require(\"express\");\nconst cors = require(\"cors\");\n```\n\n### Function Documentation\n```javascript\n/**\n * Brief description of function\n * @param {string} paramName - Description of parameter\n * @param {number} paramName2 - Description of parameter\n * @returns {boolean} Description of return value\n */\nfunction exampleFunction(paramName, paramName2) {\n  return true;\n}\n\n/**\n * @class\n * @augments BaseClass\n */\nclass ExampleClass extends BaseClass {\n  /**\n   * @param {net.Socket} socket - The socket connection\n   */\n  constructor(socket) {\n    super();\n    this.socket = socket;\n  }\n}\n```\n\n### Variable Naming Conventions\n- **Constants**: `UPPER_SNAKE_CASE`\n- **Classes**: `PascalCase`\n- **Functions/Variables**: `camelCase`\n- **Private properties**: `_prefixWithUnderscore`\n\n```javascript\n// Constants\nconst MAX_BUFFER_SIZE = 1024 * 1024;\nconst DEFAULT_TIMEOUT = 5000;\n\n// Classes\nclass RtmpSession extends BaseSession {\n  constructor(socket) {\n    super();\n    this._privateProperty = value;\n    this.publicProperty = value;\n  }\n}\n```\n\n### Error Handling\n```javascript\n// Use try-catch for async operations\ntry {\n  const result = await someAsyncOperation();\n  res.json({ success: true, data: result });\n} catch (error) {\n  logger.error(`Operation failed: ${error.message}`);\n  res.status(500).json({\n    success: false,\n    error: \"Internal server error\"\n  });\n}\n\n// Use logger for different log levels\nlogger.trace(\"Detailed trace message\");\nlogger.debug(\"Debug information\");\nlogger.info(\"General information\");\nlogger.warn(\"Warning message\");\nlogger.error(\"Error message\");\n```\n\n### Protocol and Session Patterns\n- Each protocol extends `BaseSession`\n- Use composition over inheritance for protocol-specific features\n- Follow established patterns in existing session classes\n\n### JWT and Authentication\n- Use the middleware pattern for authentication\n- Handle JWT errors with proper error handling middleware\n- Always validate token expiration and validity\n\n### Configuration Management\n- Access configuration through `Context.config`\n- Use optional chaining for safe property access\n- Provide sensible defaults for missing configuration\n\n### Security Considerations\n- Never log sensitive information (passwords, tokens)\n- Use scrypt hashing for password storage in the API (`src/api/handlers/password_hash.js`; plaintext is migrated to scrypt on startup)\n- Validate all input parameters\n- Use CORS appropriately for cross-origin requests\n\n### Performance Guidelines\n- Use Maps for session management (not arrays)\n- Implement proper cleanup in close/error handlers\n- Minimize blocking operations in event handlers\n- Use efficient data structures for broadcast management\n\n### API Design\n- Follow REST conventions for API endpoints\n- Use consistent response format:\n  ```javascript\n  {\n    success: true|false,\n    data: {},\n    message: \"Optional message\",\n    error: \"Error details if success=false\"\n  }\n  ```\n- Implement proper HTTP status codes\n- Add comprehensive error handling\n\n### File Organization\n- Keep related functionality in same directory\n- Use clear, descriptive file names\n- Group API handlers by functionality\n- Separate protocol implementations\n\nThis codebase follows a professional Node.js server architecture with emphasis on performance, security, and maintainability. Always test thoroughly after making changes."},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/illuspas/Node-Media-Server/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# Agent Guidelines for Node-Media-Server\n\nThis document provides guidelines for agentic coding agents operating in this repository.\n\n## Repository Purpose\n\nNode-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.\n\n### Directory Layout\n- `src/index.js` — library entry point; `bin/app.js` — CLI entry point\n- `src/core/` — shared kernel: `context.js` (global `Context` singleton holding config and sessions), `logger.js`, `avpacket.js`, `avcodec.js`\n- `src/protocol/` — wire-format codecs (rtmp, flv, amf, rtsp, rtp, rtcp, sdp)\n- `src/session/` — per-connection sessions, all extending `base_session.js` (rtmp, flv, record, rtsp)\n- `src/server/` — TCP/HTTP listeners and managers (rtmp_server, http_server, broadcast_server, record_server, relay_manager, notify_server)\n- `src/api/` — express admin API handlers and middleware (JWT auth)\n- `docs/` — protocol and design documentation; read before changing media/protocol code\n\n### Architecture Rules\n- Sessions are created by servers and registered in `Context.sessions`; servers look up/relay streams via `Context`.\n- Protocol parsing (`src/protocol/`) is separate from session state machines (`src/session/`) — keep new wire-format code in `src/protocol/`.\n- Config is loaded once into `Context.config`; never read config ad hoc from files at runtime.\n- 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.\n- 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.\n- 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.\n\n## Build/Lint/Test Commands\n\n### Available Scripts\n```bash\n# Development mode - runs eslint and starts server\nnpm run dev\n\n# Production start (loads bin/config.json)\nnpm start\n\n# Tests: node:test runner, ~72 tests over test/*.test.js\nnpm test\n\n# Single test file\nnode --test test/http2.test.js\n\n# Docker image (node:lts-alpine, multi-stage with webadmin build)\ndocker build -t nms .\n```\n\n### Linting\n```bash\n# Run eslint on all files (flat config, eslint 9; expects 0 errors, ~25 pre-existing jsdoc warnings)\nnpx eslint\n\n# Fix auto-fixable eslint issues\nnpx eslint --fix\n\n# Check specific file\nnpx eslint src/index.js\n```\n\n### Type Checking (informational, not wired into CI)\n`@types/express` and `@types/node` are devDependencies. Spot-check with:\n```bash\nnpx -y -p typescript tsc --noEmit --allowJs --checkJs --skipLibCheck src/api/handlers/records.js\n```\nThere are known pre-existing findings (~73); do not treat new tsc output as a gate.\n\n### Manual Testing\nAutomated tests cover the API middleware chain and HTTP wiring. For media-path changes, also smoke-test end to end:\n\n1. **RTMP Stream Testing**:\n   ```bash\n   # Start server\n   npm start\n\n   # Test with ffmpeg\n   ffmpeg -re -i input.mp4 -c copy -f flv rtmp://localhost:1935/live/stream\n   ffmpeg -i rtmp://localhost:1935/live/stream -c copy output.mp4\n   ```\n\n2. **HTTP-FLV / HTTP2-FLV Testing**:\n   ```bash\n   # HTTP/1.1 pull\n   curl http://localhost:8000/live/stream.flv\n   # HTTP/2 pull (verify ver=2 in output)\n   curl -k --http2 https://localhost:8443/live/stream.flv\n   # WebSocket-FLV: ws://localhost:8000/live/stream.flv / wss://localhost:8443/live/stream.flv\n   ```\n\n3. **API Testing** (API rides on the HTTP ports, not a separate port):\n   ```bash\n   # Health check\n   curl http://localhost:8000/api/v1/health\n\n   # Login\n   curl -X POST http://localhost:8000/api/v1/login \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\"username\":\"admin\",\"password\":\"your_password\"}'\n   ```\n\n## Runtime Gotchas\n\n- **`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.\n- 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.\n- `data/`, `record/`, `logs/`, `.tmp/`, `webadmin/dist` are gitignored runtime/build artifacts; `.tmp/` is the conventional scratch space for agent work.\n- 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.\n- CI (`.github/workflows/npm.yml`) runs on Node 24: `npm ci`, `npm test`; npm publish triggers on `v*` tags via `prepublishOnly` (rebuilds webadmin).\n\n## Code Style Guidelines\n\n### File Headers\nAll files must include copyright header:\n```javascript\n// @ts-check\n//\n//  Created by Chen Mingliang on 24/11/28.\n//  illuspas@msn.com\n//  Copyright (c) 2024 NodeMedia. All rights reserved.\n//\n```\n\n### TypeScript Checking\n- Use `// @ts-check` at the top of all JavaScript files\n- Add JSDoc comments for function parameters and return types\n- Use JSDoc types: `{string}`, `{number}`, `{boolean}`, `{object}`, `{Array<string>}`\n- For express types, use typedef imports (not `{express.Request}`):\n  ```javascript\n  /** @typedef {import(\"express\").Request} Request */\n  /** @typedef {import(\"express\").Response} Response */\n  ```\n  `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}`.\n\n### Code Formatting\n- Use **double quotes** for strings\n- Use **semicolons** at end of statements\n- Use **2 spaces** for indentation\n- Use **camelCase** for variables and functions\n- Use **PascalCase** for classes\n\n### Import/Require Guidelines\n```javascript\n// Node.js modules\nconst fs = require(\"fs\");\nconst net = require(\"net\");\n\n// Relative imports (use .js extension)\nconst logger = require(\"./core/logger.js\");\nconst Context = require(\"../core/context.js\");\nconst BaseSession = require(\"./base_session.js\");\n\n// Express and web modules\nconst express = require(\"express\");\nconst cors = require(\"cors\");\n```\n\n### Function Documentation\n```javascript\n/**\n * Brief description of function\n * @param {string} paramName - Description of parameter\n * @param {number} paramName2 - Description of parameter\n * @returns {boolean} Description of return value\n */\nfunction exampleFunction(paramName, paramName2) {\n  return true;\n}\n\n/**\n * @class\n * @augments BaseClass\n */\nclass ExampleClass extends BaseClass {\n  /**\n   * @param {net.Socket} socket - The socket connection\n   */\n  constructor(socket) {\n    super();\n    this.socket = socket;\n  }\n}\n```\n\n### Variable Naming Conventions\n- **Constants**: `UPPER_SNAKE_CASE`\n- **Classes**: `PascalCase`\n- **Functions/Variables**: `camelCase`\n- **Private properties**: `_prefixWithUnderscore`\n\n```javascript\n// Constants\nconst MAX_BUFFER_SIZE = 1024 * 1024;\nconst DEFAULT_TIMEOUT = 5000;\n\n// Classes\nclass RtmpSession extends BaseSession {\n  constructor(socket) {\n    super();\n    this._privateProperty = value;\n    this.publicProperty = value;\n  }\n}\n```\n\n### Error Handling\n```javascript\n// Use try-catch for async operations\ntry {\n  const result = await someAsyncOperation();\n  res.json({ success: true, data: result });\n} catch (error) {\n  logger.error(`Operation failed: ${error.message}`);\n  res.status(500).json({\n    success: false,\n    error: \"Internal server error\"\n  });\n}\n\n// Use logger for different log levels\nlogger.trace(\"Detailed trace message\");\nlogger.debug(\"Debug information\");\nlogger.info(\"General information\");\nlogger.warn(\"Warning message\");\nlogger.error(\"Error message\");\n```\n\n### Protocol and Session Patterns\n- Each protocol extends `BaseSession`\n- Use composition over inheritance for protocol-specific features\n- Follow established patterns in existing session classes\n\n### JWT and Authentication\n- Use the middleware pattern for authentication\n- Handle JWT errors with proper error handling middleware\n- Always validate token expiration and validity\n\n### Configuration Management\n- Access configuration through `Context.config`\n- Use optional chaining for safe property access\n- Provide sensible defaults for missing configuration\n\n### Security Considerations\n- Never log sensitive information (passwords, tokens)\n- Use scrypt hashing for password storage in the API (`src/api/handlers/password_hash.js`; plaintext is migrated to scrypt on startup)\n- Validate all input parameters\n- Use CORS appropriately for cross-origin requests\n\n### Performance Guidelines\n- Use Maps for session management (not arrays)\n- Implement proper cleanup in close/error handlers\n- Minimize blocking operations in event handlers\n- Use efficient data structures for broadcast management\n\n### API Design\n- Follow REST conventions for API endpoints\n- Use consistent response format:\n  ```javascript\n  {\n    success: true|false,\n    data: {},\n    message: \"Optional message\",\n    error: \"Error details if success=false\"\n  }\n  ```\n- Implement proper HTTP status codes\n- Add comprehensive error handling\n\n### File Organization\n- Keep related functionality in same directory\n- Use clear, descriptive file names\n- Group API handlers by functionality\n- Separate protocol implementations\n\nThis codebase follows a professional Node.js server architecture with emphasis on performance, security, and maintainability. Always test thoroughly after making changes.","isInternal":false,"tokens":2452,"sizeBytes":9979}],"systemPromptSnippet":"<yakaai_skills repo=\"illuspas/Node-Media-Server\">\n<!-- File: AGENTS.md (Tokens: ~2452 | Category: root-instruction) -->\n# Agent Guidelines for Node-Media-Server\n\nThis document provides guidelines for agentic coding agents operating in this repository.\n\n## Repository Purpose\n\nNode-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.\n\n### Directory Layout\n- `src/index.js` — library entry point; `bin/app.js` — CLI entry point\n- `src/core/` — shared kernel: `context.js` (global `Context` singleton holding config and sessions), `logger.js`, `avpacket.js`, `avcodec.js`\n- `src/protocol/` — wire-format codecs (rtmp, flv, amf, rtsp, rtp, rtcp, sdp)\n- `src/session/` — per-connection sessions, all extending `base_session.js` (rtmp, flv, record, rtsp)\n- `src/server/` — TCP/HTTP listeners and managers (rtmp_server, http_server, broadcast_server, record_server, relay_manager, notify_server)\n- `src/api/` — express admin API handlers and middleware (JWT auth)\n- `docs/` — protocol and design documentation; read before changing media/protocol code\n\n### Architecture Rules\n- Sessions are created by servers and registered in `Context.sessions`; servers look up/relay streams via `Context`.\n- Protocol parsing (`src/protocol/`) is separate from session state machines (`src/session/`) — keep new wire-format code in `src/protocol/`.\n- Config is loaded once into `Context.config`; never read config ad hoc from files at runtime.\n- 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.\n- 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.\n- 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.\n\n## Build/Lint/Test Commands\n\n### Available Scripts\n```bash\n# Development mode - runs eslint and starts server\nnpm run dev\n\n# Production start (loads bin/config.json)\nnpm start\n\n# Tests: node:test runner, ~72 tests over test/*.test.js\nnpm test\n\n# Single test file\nnode --test test/http2.test.js\n\n# Docker image (node:lts-alpine, multi-stage with webadmin build)\ndocker build -t nms .\n```\n\n### Linting\n```bash\n# Run eslint on all files (flat config, eslint 9; expects 0 errors, ~25 pre-existing jsdoc warnings)\nnpx eslint\n\n# Fix auto-fixable eslint issues\nnpx eslint --fix\n\n# Check specific file\nnpx eslint src/index.js\n```\n\n### Type Checking (informational, not wired into CI)\n`@types/express` and `@types/node` are devDependencies. Spot-check with:\n```bash\nnpx -y -p typescript tsc --noEmit --allowJs --checkJs --skipLibCheck src/api/handlers/records.js\n```\nThere are known pre-existing findings (~73); do not treat new tsc output as a gate.\n\n### Manual Testing\nAutomated tests cover the API middleware chain and HTTP wiring. For media-path changes, also smoke-test end to end:\n\n1. **RTMP Stream Testing**:\n   ```bash\n   # Start server\n   npm start\n\n   # Test with ffmpeg\n   ffmpeg -re -i input.mp4 -c copy -f flv rtmp://localhost:1935/live/stream\n   ffmpeg -i rtmp://localhost:1935/live/stream -c copy output.mp4\n   ```\n\n2. **HTTP-FLV / HTTP2-FLV Testing**:\n   ```bash\n   # HTTP/1.1 pull\n   curl http://localhost:8000/live/stream.flv\n   # HTTP/2 pull (verify ver=2 in output)\n   curl -k --http2 https://localhost:8443/live/stream.flv\n   # WebSocket-FLV: ws://localhost:8000/live/stream.flv / wss://localhost:8443/live/stream.flv\n   ```\n\n3. **API Testing** (API rides on the HTTP ports, not a separate port):\n   ```bash\n   # Health check\n   curl http://localhost:8000/api/v1/health\n\n   # Login\n   curl -X POST http://localhost:8000/api/v1/login \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\"username\":\"admin\",\"password\":\"your_password\"}'\n   ```\n\n## Runtime Gotchas\n\n- **`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.\n- 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.\n- `data/`, `record/`, `logs/`, `.tmp/`, `webadmin/dist` are gitignored runtime/build artifacts; `.tmp/` is the conventional scratch space for agent work.\n- 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.\n- CI (`.github/workflows/npm.yml`) runs on Node 24: `npm ci`, `npm test`; npm publish triggers on `v*` tags via `prepublishOnly` (rebuilds webadmin).\n\n## Code Style Guidelines\n\n### File Headers\nAll files must include copyright header:\n```javascript\n// @ts-check\n//\n//  Created by Chen Mingliang on 24/11/28.\n//  illuspas@msn.com\n//  Copyright (c) 2024 NodeMedia. All rights reserved.\n//\n```\n\n### TypeScript Checking\n- Use `// @ts-check` at the top of all JavaScript files\n- Add JSDoc comments for function parameters and return types\n- Use JSDoc types: `{string}`, `{number}`, `{boolean}`, `{object}`, `{Array<string>}`\n- For express types, use typedef imports (not `{express.Request}`):\n  ```javascript\n  /** @typedef {import(\"express\").Request} Request */\n  /** @typedef {import(\"express\").Response} Response */\n  ```\n  `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}`.\n\n### Code Formatting\n- Use **double quotes** for strings\n- Use **semicolons** at end of statements\n- Use **2 spaces** for indentation\n- Use **camelCase** for variables and functions\n- Use **PascalCase** for classes\n\n### Import/Require Guidelines\n```javascript\n// Node.js modules\nconst fs = require(\"fs\");\nconst net = require(\"net\");\n\n// Relative imports (use .js extension)\nconst logger = require(\"./core/logger.js\");\nconst Context = require(\"../core/context.js\");\nconst BaseSession = require(\"./base_session.js\");\n\n// Express and web modules\nconst express = require(\"express\");\nconst cors = require(\"cors\");\n```\n\n### Function Documentation\n```javascript\n/**\n * Brief description of function\n * @param {string} paramName - Description of parameter\n * @param {number} paramName2 - Description of parameter\n * @returns {boolean} Description of return value\n */\nfunction exampleFunction(paramName, paramName2) {\n  return true;\n}\n\n/**\n * @class\n * @augments BaseClass\n */\nclass ExampleClass extends BaseClass {\n  /**\n   * @param {net.Socket} socket - The socket connection\n   */\n  constructor(socket) {\n    super();\n    this.socket = socket;\n  }\n}\n```\n\n### Variable Naming Conventions\n- **Constants**: `UPPER_SNAKE_CASE`\n- **Classes**: `PascalCase`\n- **Functions/Variables**: `camelCase`\n- **Private properties**: `_prefixWithUnderscore`\n\n```javascript\n// Constants\nconst MAX_BUFFER_SIZE = 1024 * 1024;\nconst DEFAULT_TIMEOUT = 5000;\n\n// Classes\nclass RtmpSession extends BaseSession {\n  constructor(socket) {\n    super();\n    this._privateProperty = value;\n    this.publicProperty = value;\n  }\n}\n```\n\n### Error Handling\n```javascript\n// Use try-catch for async operations\ntry {\n  const result = await someAsyncOperation();\n  res.json({ success: true, data: result });\n} catch (error) {\n  logger.error(`Operation failed: ${error.message}`);\n  res.status(500).json({\n    success: false,\n    error: \"Internal server error\"\n  });\n}\n\n// Use logger for different log levels\nlogger.trace(\"Detailed trace message\");\nlogger.debug(\"Debug information\");\nlogger.info(\"General information\");\nlogger.warn(\"Warning message\");\nlogger.error(\"Error message\");\n```\n\n### Protocol and Session Patterns\n- Each protocol extends `BaseSession`\n- Use composition over inheritance for protocol-specific features\n- Follow established patterns in existing session classes\n\n### JWT and Authentication\n- Use the middleware pattern for authentication\n- Handle JWT errors with proper error handling middleware\n- Always validate token expiration and validity\n\n### Configuration Management\n- Access configuration through `Context.config`\n- Use optional chaining for safe property access\n- Provide sensible defaults for missing configuration\n\n### Security Considerations\n- Never log sensitive information (passwords, tokens)\n- Use scrypt hashing for password storage in the API (`src/api/handlers/password_hash.js`; plaintext is migrated to scrypt on startup)\n- Validate all input parameters\n- Use CORS appropriately for cross-origin requests\n\n### Performance Guidelines\n- Use Maps for session management (not arrays)\n- Implement proper cleanup in close/error handlers\n- Minimize blocking operations in event handlers\n- Use efficient data structures for broadcast management\n\n### API Design\n- Follow REST conventions for API endpoints\n- Use consistent response format:\n  ```javascript\n  {\n    success: true|false,\n    data: {},\n    message: \"Optional message\",\n    error: \"Error details if success=false\"\n  }\n  ```\n- Implement proper HTTP status codes\n- Add comprehensive error handling\n\n### File Organization\n- Keep related functionality in same directory\n- Use clear, descriptive file names\n- Group API handlers by functionality\n- Separate protocol implementations\n\nThis codebase follows a professional Node.js server architecture with emphasis on performance, security, and maintainability. Always test thoroughly after making changes.\n</yakaai_skills>"}