================ LIBRARY RULES ================ - Use the '@rdcp.dev/server' package (not '@rdcp/server') - Prefer the per-framework Quick verify snippets from the wiki (Express, Fastify, Koa, Next.js) - Follow the RDCP Protocol endpoints exactly; do not invent or modify control routes - Link to the RDCP spec and implementation guide in answers when relevant # RDCP SDK - Runtime Debug Control Protocol The RDCP SDK implements the Runtime Debug Control Protocol (RDCP v1.0), providing standardized HTTP endpoints for immediate operational control over application runtime behavior without deployments. This JavaScript/TypeScript SDK enables production systems to dynamically enable debug logging, adjust trace levels, and modify runtime behavior through authenticated HTTP requests, addressing the infrastructure gap between static configuration management and passive monitoring platforms. RDCP operates at the application control plane level as the first implementation of Operational Infrastructure Control (OIC). Unlike configuration management systems that require deployments or monitoring platforms with limited control capabilities, RDCP provides immediate runtime operational changes through standardized protocols. The SDK is organized as a monorepo with multiple packages: @rdcp.dev/core (protocol constants and schemas), @rdcp.dev/client (type-safe fetch-based client), @rdcp.dev/server (Express/Fastify/Koa adapters), @rdcp.dev/admin-ui and @rdcp.dev/admin-ui-react (admin interface components), and @rdcp.dev/otel-plugin (OpenTelemetry integration). The protocol specification is maintained in a separate rdcp-protocol submodule. Enterprise features include multi-tier authentication (API key, JWT, mTLS), multi-tenant operational isolation, production-grade rate limiting with standard RateLimit headers, comprehensive audit trails, JWKS infrastructure with ETag revalidation, TTL automatic cleanup, and Prometheus metrics integration. ## APIs and Functions ### Client SDK Usage Consume RDCP endpoints from other services with the type-safe client SDK (separate @rdcp.dev/client package). ```typescript import { createRDCPClient } from '@rdcp.dev/client' import { RDCP_HEADERS } from '@rdcp.dev/core' // Initialize client with authentication headers const rdcp = createRDCPClient({ baseUrl: process.env.RDCP_BASE_URL || 'http://localhost:3000', headers: { [RDCP_HEADERS.AUTH_METHOD]: 'api-key', [RDCP_HEADERS.CLIENT_ID]: 'ops-dashboard', 'x-api-key': process.env.RDCP_API_KEY } }) // Discovery - get available endpoints and capabilities const discovery = await rdcp.getDiscovery() console.log('Available categories:', discovery.capabilities.categories) // Status - check current debug state const status = await rdcp.getStatus() console.log('Enabled categories:', Object.keys(status.categories).filter(k => status.categories[k])) // Control - enable debug categories with 15-minute TTL const enableResult = await rdcp.postControl({ action: 'enable', categories: ['DATABASE', 'QUERIES'], options: { temporary: true, duration: '15m' } }) console.log('Changes applied:', enableResult.changes) // Control - disable specific categories await rdcp.postControl({ action: 'disable', categories: ['DATABASE'] }) // Control - reset all categories to disabled await rdcp.postControl({ action: 'reset' }) // Health check const health = await rdcp.getHealth() console.log('System status:', health.status, 'Checks:', health.checks) // Error handling with typed errors try { await rdcp.postControl({ action: 'enable', categories: ['INVALID'] }) } catch (error) { if (error instanceof RDCPClientError) { console.error('RDCP Error:', error.code, error.status, error.message) } } ``` ### Express Middleware Setup Creates RDCP middleware for Express applications with authentication and optional capabilities. ```typescript import express from 'express' import { adapters, auth } from '@rdcp.dev/server' const app = express() app.use(express.json()) // Basic setup with API key authentication const rdcpMiddleware = adapters.express.createRDCPMiddleware({ authenticator: auth.validateRDCPAuth }) app.use(rdcpMiddleware) // Enterprise setup with all capabilities const enterpriseMiddleware = adapters.express.createRDCPMiddleware({ authenticator: auth.validateRDCPAuth, debugConfig: { DATABASE: false, API_ROUTES: false, QUERIES: false, REPORTS: false, CACHE: false }, capabilities: { temporaryControls: true, ttl: { enabled: true, minDurationMs: 1000, maxDurationMs: 3600000, maxActiveTTLs: 100 }, rateLimit: { enabled: true, headers: true, headersMode: 'draft-7', defaultRule: { windowMs: 60000, maxRequests: 100 }, perEndpoint: { control: { windowMs: 60000, maxRequests: 50 } } }, audit: { enabled: true, sink: 'file', file: { path: './logs/rdcp-audit.log', maxBytes: 10485760, maxFiles: 5 }, sampleRate: 1.0, failureMode: 'warn' }, security: { tokenLifecycle: { enabled: true, graceWindowMs: 604800000, jwks: { enabled: true, maxAgeSeconds: 300, emitLastModified: true } } }, metrics: { enabled: true, endpointPath: '/metrics' } } }) app.use(enterpriseMiddleware) app.listen(3000, () => console.log('RDCP server listening on port 3000')) ``` ### Admin UI Integration React-based admin interface for operational control with real-time polling and actions. ```typescript import express from 'express' import { adapters, auth } from '@rdcp.dev/server' import { createAdminUISpec } from '@rdcp.dev/admin-ui' import { renderAdminUI } from '@rdcp.dev/admin-ui-react' const app = express() app.use(express.json()) // Add RDCP middleware const rdcpMiddleware = adapters.express.createRDCPMiddleware({ authenticator: auth.validateRDCPAuth }) app.use(rdcpMiddleware) // Admin UI endpoint app.get('/admin', async (req, res) => { const discovery = await fetch('http://localhost:3000/rdcp/v1/discovery').then(r => r.json()) const spec = createAdminUISpec(discovery) const html = renderAdminUI(spec) res.send(html) }) // Admin UI features: // - Action selector: enable/disable/toggle/reset // - Jittered polling (~1s + 0-300ms), exponential backoff // - Pause during control operations; immediate resume // - Inline toasts for success/error feedback // - Tenant selection and TTL duration input app.listen(3000) ``` ### Debug System Integration Application-side debug logging with RDCP control integration. ```typescript import { debug, enableDebugCategories, disableDebugCategories, getDebugStatus } from '@rdcp.dev/server' // Use debug functions in your application code async function queryDatabase(sql: string, params: unknown[]) { debug.database('Executing query', { sql, params, timestamp: Date.now() }) const result = await db.execute(sql, params) debug.database('Query completed', { rowCount: result.rows.length, durationMs: 5 }) return result } async function handleApiRequest(req: Request, res: Response) { debug.api('Incoming request', { method: req.method, path: req.path, headers: req.headers }) const result = await processRequest(req) debug.api('Request completed', { statusCode: 200, durationMs: 23 }) res.json(result) } function executeCacheOperation(key: string, value: unknown) { debug.cache('Cache write', { key, size: JSON.stringify(value).length }) cache.set(key, value) } // Programmatic control (without HTTP endpoints) enableDebugCategories(['DATABASE', 'API_ROUTES']) console.log('Status:', getDebugStatus()) // Output: { DATABASE: true, API_ROUTES: true, QUERIES: false, REPORTS: false, CACHE: false } disableDebugCategories(['DATABASE']) ``` ### Multi-Tenant Operational Isolation Tenant-specific debug control without cross-tenant interference. ```typescript import express from 'express' import { adapters, auth } from '@rdcp.dev/server' const app = express() app.use(express.json()) const rdcpMiddleware = adapters.express.createRDCPMiddleware({ authenticator: auth.validateRDCPAuth, capabilities: { audit: { enabled: true, sink: 'file' } } }) app.use(rdcpMiddleware) app.listen(3000) // Client request for tenant-specific control // Customer A enables debugging (does not affect Customer B) const response = await fetch('http://localhost:3000/rdcp/v1/control', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-RDCP-Tenant-ID': 'customer-a-123', 'X-RDCP-Auth-Method': 'bearer', 'X-RDCP-Client-ID': 'customer-a-ops', 'Authorization': `Bearer ${jwtTokenWithTenantScope}` }, body: JSON.stringify({ action: 'enable', categories: ['DATABASE', 'API_ROUTES'], options: { temporary: true, duration: '30m' } }) }) const result = await response.json() console.log('Tenant scope:', result.tenant.tenantId) console.log('Applied changes:', result.changes) // Output shows changes only affect customer-a-123 // Customer B's debug state remains unchanged // Tenant isolation ensures complete operational separation ``` ### JWT Authentication with Scopes Standard authentication tier using JWT tokens with scope-based authorization. ```typescript import jwt from 'jsonwebtoken' import { Request } from 'express' // Create JWT authenticator with scope validation const jwtAuthenticator = async (req: Request): Promise => { const token = req.headers['authorization']?.replace('Bearer ', '') if (!token) return false try { const decoded = jwt.verify(token, process.env.JWT_SECRET!) as { sub: string scopes?: string[] tenant?: string } // Global control scope if (decoded.scopes?.includes('rdcp:control')) { return true } // Tenant-specific control scope const tenantId = req.headers['x-rdcp-tenant-id'] as string if (tenantId && decoded.scopes?.includes(`rdcp:control:${tenantId}`)) { return true } return false } catch (error) { console.error('JWT validation failed:', error) return false } } // Use in middleware setup const rdcpMiddleware = adapters.express.createRDCPMiddleware({ authenticator: jwtAuthenticator }) // Generate tokens for clients const globalToken = jwt.sign( { sub: 'ops-team', scopes: ['rdcp:control', 'rdcp:status'] }, process.env.JWT_SECRET!, { expiresIn: '1h', issuer: 'rdcp-auth', audience: 'rdcp-services' } ) const tenantToken = jwt.sign( { sub: 'customer-ops', scopes: ['rdcp:control:customer-123'], tenant: 'customer-123' }, process.env.JWT_SECRET!, { expiresIn: '24h' } ) ``` ### JWKS Fetcher with Caching Enterprise JWKS client with ETag revalidation and TTL caching. ```typescript import { createJwksFetcher } from '@rdcp.dev/server' // In-memory TTL cache with background refresh const jwks = createJwksFetcher({ ttlMs: 60000, // Cache for 60 seconds refreshThresholdMs: 10000 // Preemptive refresh when <10s remain }) const result = await jwks.fetch('https://auth.example.com') console.log('Keys:', result.jwks.keys.length) console.log('From cache:', result.fromCache) console.log('ETag:', result.etag) // File-backed persisted cache (survives restarts) const persistedJwks = createJwksFetcher({ cachePath: '.rdcp-cache', ttlMs: 300000 // 5 minute TTL }) const persistedResult = await persistedJwks.fetch('https://auth.example.com') // ETag-only mode (no TTL, always revalidates with server) const etagJwks = createJwksFetcher() const r1 = await etagJwks.fetch('https://auth.example.com') // Sends If-None-Match header on subsequent requests const r2 = await etagJwks.fetch('https://auth.example.com') // Returns cached body if server responds 304 Not Modified // Filter and find keys import { filterJwksKeys, findJwkByKid } from '@rdcp.dev/server' const rsaKeys = filterJwksKeys(result.jwks, { kty: ['RSA'], use: ['sig'] }) console.log('RSA signing keys:', rsaKeys.length) const specificKey = findJwkByKid(result.jwks, 'key-2024-01', { kty: ['RSA'] }) if (specificKey) { console.log('Found key:', specificKey.kid) } ``` ### Rate Limiting Configuration Token bucket rate limiting with per-endpoint and per-tenant rules. ```typescript import { adapters, auth } from '@rdcp.dev/server' const rdcpMiddleware = adapters.express.createRDCPMiddleware({ authenticator: auth.validateRDCPAuth, capabilities: { rateLimit: { enabled: true, headers: true, headersMode: 'draft-7', // Use IETF draft-7 RateLimit headers defaultRule: { windowMs: 60000, // 60 second window maxRequests: 100 // 100 requests per window }, perEndpoint: { control: { windowMs: 60000, maxRequests: 50 }, status: { windowMs: 60000, maxRequests: 200 }, discovery: { windowMs: 60000, maxRequests: 1000 } }, perTenant: { 'customer-premium': { maxRequests: 500 }, 'customer-basic': { maxRequests: 50 } } } } }) // Rate limit headers in responses (draft-7 mode): // RateLimit: limit=100, remaining=45, reset=55 // RateLimit-Policy: 100;w=60 // Retry-After: 55 (when rate limited) // Rate limit headers in responses (x mode): // X-RateLimit-Limit: 100 // X-RateLimit-Remaining: 45 // X-RateLimit-Reset: 1697654400 // Retry-After: 55 (when rate limited) // Rate limit error response when exceeded: const rateLimitedResponse = { error: { code: 'RDCP_RATE_LIMIT_EXCEEDED', message: 'Control rate limited. Retry after 12000ms', protocol: 'rdcp/1.0', details: { limit: 50, remaining: 0, reset: 1697654400, retryAfterSec: 12, policy: '50;w=60' } }, protocol: 'rdcp/1.0', timestamp: '2024-10-18T15:20:00.000Z' } ``` ### Audit Logging System Comprehensive audit trail with sampling and redaction. ```typescript import { adapters, auth } from '@rdcp.dev/server' // File-based audit sink with rotation const rdcpMiddleware = adapters.express.createRDCPMiddleware({ authenticator: auth.validateRDCPAuth, capabilities: { audit: { enabled: true, sink: 'file', file: { path: './logs/rdcp-audit.log', maxBytes: 10485760, // 10MB per file maxFiles: 5 // Keep 5 rotated files }, sampleRate: 1.0, // Audit 100% of requests (0.1 = 10%) redact: (record) => { // Remove sensitive fields before writing const redacted = { ...record } if (redacted.clientId) redacted.clientId = '***' return redacted }, failureMode: 'warn' // Options: 'ignore' | 'warn' | 'fail' } } }) // Audit record format written to sink: const auditRecord = { event: 'RDCP_AUDIT', timestamp: '2024-10-18T15:30:00.000Z', action: 'enable', categories: ['DATABASE', 'QUERIES'], tenantId: 'customer-123', status: 'success', requestId: 'f47ac10b-58cc-4372-a567-0e02b2c3d479', authMethod: 'bearer', clientId: '***', ip: '192.168.1.100' } // Console sink for development const devMiddleware = adapters.express.createRDCPMiddleware({ authenticator: auth.validateRDCPAuth, capabilities: { audit: { enabled: true, sink: 'console', sampleRate: 0.1 // Sample 10% in development } } }) // Audit failure handling modes: // 'ignore' - Silently continue if audit write fails // 'warn' - Add Warning header to response, include __rdcpWarnings in body // 'fail' - Return RDCP_AUDIT_WRITE_FAILED error, block the operation ``` ### OpenTelemetry Trace Integration Correlate RDCP debug logs with OpenTelemetry traces using the @rdcp.dev/otel-plugin package. ```typescript import { setupRDCPWithOpenTelemetry } from '@rdcp.dev/otel-plugin' import { NodeSDK } from '@opentelemetry/sdk-node' import { trace } from '@opentelemetry/api' import { enableDebugCategories, debug } from '@rdcp.dev/server' // Initialize OpenTelemetry SDK const sdk = new NodeSDK({ serviceName: 'my-service', // Add your exporters, processors, etc. }) await sdk.start() // Enable RDCP ↔ OTel correlation (one line) setupRDCPWithOpenTelemetry({ enableBaggage: true // Include OpenTelemetry baggage in logs }) // Enable debug categories so logs emit enableDebugCategories(['DATABASE', 'API_ROUTES']) // Use RDCP debug functions within OTel spans const tracer = trace.getTracer('my-service') tracer.startActiveSpan('process-order', async (span) => { span.setAttribute('order.id', '12345') debug.api('Processing order', { orderId: '12345' }) await tracer.startActiveSpan('query-database', async (dbSpan) => { debug.database('Fetching order details', { orderId: '12345' }) const order = await db.query('SELECT * FROM orders WHERE id = ?', ['12345']) dbSpan.end() return order }) span.end() }) // Console output includes trace context: // 🔍 [API] [trace:90abcdef] Processing order { orderId: '12345' } // 🔌 [DB] [trace:90abcdef] Fetching order details { orderId: '12345' } // Trace context enables correlation between RDCP logs and OTel traces // in observability backends (Jaeger, Honeycomb, Datadog, etc.) ``` ### Fastify Plugin Integration RDCP integration for Fastify applications. ```typescript import Fastify from 'fastify' import { adapters, auth } from '@rdcp.dev/server' const fastify = Fastify({ logger: true }) // Register RDCP plugin await fastify.register(adapters.fastify.createRDCPPlugin({ authenticator: auth.validateRDCPAuth, capabilities: { rateLimit: { enabled: true, headers: true }, audit: { enabled: true, sink: 'console' } } })) // RDCP endpoints automatically available: // GET /.well-known/rdcp // GET /rdcp/v1/discovery // GET /rdcp/v1/status // GET /rdcp/v1/health // POST /rdcp/v1/control fastify.get('/api/users', async (request, reply) => { debug.api('Fetching users', { query: request.query }) const users = await db.getUsers() return users }) await fastify.listen({ port: 3000 }) ``` ### Koa Middleware Integration RDCP integration for Koa applications. ```typescript import Koa from 'koa' import bodyParser from 'koa-bodyparser' import { adapters, auth } from '@rdcp.dev/server' const app = new Koa() app.use(bodyParser()) // Add RDCP middleware with error boundary const rdcpMiddleware = adapters.koa.createRDCPMiddlewareWithErrorBoundary({ authenticator: auth.validateRDCPAuth, capabilities: { ttl: { enabled: true, maxDurationMs: 3600000 } } }) app.use(rdcpMiddleware) // Application routes app.use(async (ctx) => { if (ctx.path === '/api/data') { debug.api('Processing request', { path: ctx.path }) ctx.body = { data: 'example' } } }) app.listen(3000) ``` ### Protocol Discovery Endpoint Well-known endpoint for RDCP protocol discovery (no authentication required). ```bash # Protocol discovery curl http://localhost:3000/.well-known/rdcp # Response: { "protocol": "rdcp/1.0", "timestamp": "2024-10-18T15:30:00.000Z", "endpoints": { "discovery": "/rdcp/v1/discovery", "control": "/rdcp/v1/control", "status": "/rdcp/v1/status", "health": "/rdcp/v1/health" }, "capabilities": { "authentication": ["basic", "standard", "enterprise"], "isolation": ["global", "process", "namespace", "organization"], "categories": ["DATABASE", "API_ROUTES", "QUERIES", "REPORTS", "CACHE", "AUTH", "INTEGRATIONS"] } } ``` ### Incident Response Workflow Real-world operational control during production incidents. ```bash # 1. Incident detected - enable database debugging with 15-minute TTL curl -X POST http://localhost:3000/rdcp/v1/control \ -H "Content-Type: application/json" \ -H "X-RDCP-Auth-Method: bearer" \ -H "X-RDCP-Client-ID: ops-dashboard" \ -H "Authorization: Bearer ${JWT_TOKEN}" \ -d '{ "action": "enable", "categories": ["DATABASE", "QUERIES"], "options": { "temporary": true, "duration": "15m" } }' # Response: { "protocol": "rdcp/1.0", "timestamp": "2024-10-18T15:30:00.000Z", "action": "enable", "categories": ["DATABASE", "QUERIES"], "status": "success", "changes": [ { "category": "DATABASE", "action": "enabled", "tenantScope": "default", "isolationLevel": "global" }, { "category": "QUERIES", "action": "enabled", "tenantScope": "default", "isolationLevel": "global" } ] } # 2. Debug output immediately visible in application logs # Application now logs all database queries for 15 minutes # 3. Check current status curl -H "X-RDCP-Auth-Method: bearer" \ -H "X-RDCP-Client-ID: ops-dashboard" \ -H "Authorization: Bearer ${JWT_TOKEN}" \ http://localhost:3000/rdcp/v1/status # 4. Root cause identified - disable to reduce log noise curl -X POST http://localhost:3000/rdcp/v1/control \ -H "Content-Type: application/json" \ -H "X-RDCP-Auth-Method: bearer" \ -H "X-RDCP-Client-ID: ops-dashboard" \ -H "Authorization: Bearer ${JWT_TOKEN}" \ -d '{ "action": "disable", "categories": ["DATABASE", "QUERIES"] }' ``` ### Prometheus Metrics Endpoint Expose RDCP runtime metrics in Prometheus format. ```typescript import { adapters, auth } from '@rdcp.dev/server' const rdcpMiddleware = adapters.express.createRDCPMiddleware({ authenticator: auth.validateRDCPAuth, capabilities: { metrics: { enabled: true, endpointPath: '/metrics' } } }) // Metrics endpoint available at /metrics (no authentication required) // Prometheus scrape configuration: // scrape_configs: // - job_name: 'rdcp' // static_configs: // - targets: ['localhost:3000'] // metrics_path: '/metrics' // Exposed metrics: // rdcp_cpu_percent (gauge) - CPU percent per-core normalized // rdcp_memory_rss_bytes (gauge) - Resident set size in bytes // rdcp_event_loop_delay_p99_milliseconds (gauge) - Event loop delay P99 ``` ### Core Package Usage Import protocol constants and shared definitions from @rdcp.dev/core. ```typescript import { PROTOCOL_VERSION, RDCP_PATHS } from '@rdcp.dev/core' import { RDCP_ERROR_CODES, RDCP_HEADERS } from '@rdcp.dev/core' // Use protocol constants console.log('Protocol version:', PROTOCOL_VERSION) console.log('Control endpoint:', RDCP_PATHS.CONTROL) // Access error codes console.log('Invalid category code:', RDCP_ERROR_CODES.INVALID_CATEGORY) // Use standard headers const headers = { [RDCP_HEADERS.AUTH_METHOD]: 'api-key', [RDCP_HEADERS.CLIENT_ID]: 'my-client', [RDCP_HEADERS.TENANT_ID]: 'customer-123' } ``` ## Summary The RDCP SDK provides a production-ready implementation of the Runtime Debug Control Protocol for immediate operational control in Node.js applications. Core use cases include incident response workflows where debug logging must be enabled instantly without deployments, customer-specific debugging in SaaS platforms with tenant isolation guarantees, compliance-required audit trails of all operational changes, and coordinated operational control across microservices through standardized endpoints. The SDK eliminates the deployment cycle delay during incidents, reduces risk of introducing bugs through operational configuration changes, and provides complete visibility into who made what changes when through comprehensive audit logging. The monorepo structure with separate packages (@rdcp.dev/core, @rdcp.dev/client, @rdcp.dev/server, @rdcp.dev/admin-ui, @rdcp.dev/otel-plugin) enables modular integration and clear separation of concerns. Integration patterns span multiple frameworks with consistent behavior across Express, Fastify, and Koa middleware adapters. Authentication tiers scale from API key validation for internal systems to JWT with scope-based authorization for multi-tenant SaaS to mTLS certificate validation for zero-trust architectures. The JWKS infrastructure supports key rotation with ETag-based revalidation, file-backed persistence across restarts, and background refresh to prevent cache expiration during traffic spikes. Rate limiting uses token bucket algorithm with per-endpoint and per-tenant rules, TTL automatic cleanup prevents categories staying enabled indefinitely, and OpenTelemetry integration correlates debug logs with distributed traces. The client SDK (@rdcp.dev/client) provides type-safe consumption of RDCP endpoints with automatic schema validation using Zod, comprehensive error handling, and support for all protocol features including multi-tenant isolation and temporary controls. The admin UI components (@rdcp.dev/admin-ui and @rdcp.dev/admin-ui-react) provide a React-based operational control interface with real-time polling, jittered backoff, and inline feedback. The protocol specification is maintained in a separate rdcp-protocol Git submodule, ensuring consistency across implementations.