| title | Server Configuration Reference [new] |
|---|---|
| description | Complete configuration reference for NeuroLink Server Adapters including CORS, rate limiting, body parsing, logging, and middleware options. |
This document provides a comprehensive reference for all configuration options available in NeuroLink Server Adapters.
In addition to programmatic configuration, NeuroLink provides CLI commands to view and manage server settings.
# Show all configuration
neurolink server config
# Output as JSON
neurolink server config --format json
# Get specific value
neurolink server config --get defaultPort
neurolink server config --get cors.enabled
neurolink server config --get rateLimit.maxRequests# Set configuration values
neurolink server config --set defaultPort=8080
neurolink server config --set defaultFramework=express
neurolink server config --set cors.enabled=true
neurolink server config --set rateLimit.maxRequests=200
# Reset to defaults
neurolink server config --resetCLI configuration is stored at:
- Config file:
~/.neurolink/server-config.json - Server state:
~/.neurolink/server-state.json
| Aspect | CLI Config | Programmatic Config |
|---|---|---|
| Persistence | File-based, survives restarts | In-memory, per-instance |
| Scope | Global defaults | Per-server instance |
| Use Case | Development, quick changes | Production, fine-grained control |
The CLI configuration provides default values that can be overridden programmatically:
// CLI defaults are used when not specified
const server = await createServer(neurolink, {
framework: "hono", // Overrides CLI default
// port uses CLI default if not specified
});The main configuration object for server adapters.
type ServerAdapterConfig = {
port?: number;
host?: string;
basePath?: string;
cors?: CORSConfig;
rateLimit?: RateLimitConfig;
bodyParser?: BodyParserConfig;
logging?: LoggingConfig;
shutdown?: ShutdownConfig;
redaction?: RedactionConfig;
timeout?: number;
enableMetrics?: boolean;
enableSwagger?: boolean;
disableBuiltInHealth?: boolean;
};| Option | Type | Default | Description |
|---|---|---|---|
port |
number |
3000 |
Server port to listen on |
host |
string |
"0.0.0.0" |
Server host/interface to bind |
basePath |
string |
"/api" |
Base path prefix for all routes |
timeout |
number |
30000 |
Request timeout in milliseconds |
enableMetrics |
boolean |
true |
Enable metrics endpoint |
enableSwagger |
boolean |
false |
Enable OpenAPI/Swagger documentation (see below) |
disableBuiltInHealth |
boolean |
false |
Disable built-in health routes |
When enableSwagger is set to true, the server exposes interactive API documentation endpoints:
| Endpoint | Description |
|---|---|
GET {basePath}/openapi.json |
OpenAPI 3.1 specification in JSON format |
GET {basePath}/openapi.yaml |
OpenAPI 3.1 specification in YAML format |
GET {basePath}/docs |
Interactive Swagger UI documentation |
Example URLs (with default basePath /api):
http://localhost:3000/api/openapi.jsonhttp://localhost:3000/api/openapi.yamlhttp://localhost:3000/api/docs
The Swagger UI provides an interactive interface where you can:
- Browse all available API endpoints
- View request/response schemas
- Test API calls directly from the browser
- Download the OpenAPI specification
Security Consideration: In production environments, consider disabling
enableSwaggerto prevent exposing internal API structure. Alternatively, protect the documentation endpoints with authentication middleware.
import { createServer } from "@juspay/neurolink";
const server = await createServer(neurolink, {
config: {
port: 8080,
host: "127.0.0.1",
basePath: "/v1/api",
timeout: 60000,
enableSwagger: true,
},
});type CORSConfig = {
enabled?: boolean;
origins?: string[];
methods?: string[];
headers?: string[];
credentials?: boolean;
maxAge?: number;
};| Option | Type | Default | Description |
|---|---|---|---|
enabled |
boolean |
true |
Enable CORS support |
origins |
string[] |
["*"] |
Allowed origins |
methods |
string[] |
["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"] |
Allowed HTTP methods |
headers |
string[] |
["Content-Type", "Authorization"] |
Allowed headers |
credentials |
boolean |
false |
Allow credentials |
maxAge |
number |
86400 |
Preflight cache max age in seconds |
Security Warning: The default wildcard origin
["*"]allows requests from any domain. In production environments, always specify explicit allowed origins to prevent unauthorized cross-origin requests.
const server = await createServer(neurolink, {
config: {
cors: {
enabled: true,
origins: ["https://myapp.com", "https://staging.myapp.com"],
methods: ["GET", "POST"],
headers: ["Content-Type", "Authorization", "X-Request-ID"],
credentials: true,
maxAge: 3600,
},
},
});type RateLimitConfig = {
enabled?: boolean;
windowMs?: number;
maxRequests?: number;
message?: string;
skipPaths?: string[];
keyGenerator?: (ctx: ServerContext) => string;
};| Option | Type | Default | Description |
|---|---|---|---|
enabled |
boolean |
true |
Enable rate limiting |
windowMs |
number |
900000 (15 min) |
Time window in milliseconds |
maxRequests |
number |
100 |
Maximum requests per window |
message |
string |
"Too many requests..." |
Error message when limit exceeded |
skipPaths |
string[] |
[] |
Paths to exclude from rate limiting |
keyGenerator |
function |
IP-based | Custom function to generate rate limit key |
const server = await createServer(neurolink, {
config: {
rateLimit: {
enabled: true,
windowMs: 60000, // 1 minute
maxRequests: 30,
skipPaths: ["/api/health", "/api/ready", "/api/version"],
keyGenerator: (ctx) => {
// Rate limit by API key instead of IP
return (
ctx.headers["x-api-key"] ||
ctx.headers["x-forwarded-for"] ||
"unknown"
);
},
},
},
});type BodyParserConfig = {
enabled?: boolean;
maxSize?: string;
jsonLimit?: string;
urlEncoded?: boolean;
};| Option | Type | Default | Description |
|---|---|---|---|
enabled |
boolean |
true |
Enable body parsing |
maxSize |
string |
"10mb" |
Maximum body size |
jsonLimit |
string |
"10mb" |
JSON body size limit |
urlEncoded |
boolean |
true |
Enable URL-encoded body parsing |
const server = await createServer(neurolink, {
config: {
bodyParser: {
enabled: true,
maxSize: "50mb",
jsonLimit: "50mb",
urlEncoded: true,
},
},
});type LoggingConfig = {
enabled?: boolean;
level?: "debug" | "info" | "warn" | "error";
includeBody?: boolean;
includeResponse?: boolean;
};| Option | Type | Default | Description |
|---|---|---|---|
enabled |
boolean |
true |
Enable request logging |
level |
string |
"info" |
Log level |
includeBody |
boolean |
false |
Include request body in logs |
includeResponse |
boolean |
false |
Include response body in logs |
const server = await createServer(neurolink, {
config: {
logging: {
enabled: true,
level: "debug",
includeBody: true,
includeResponse: true,
},
},
});type ShutdownConfig = {
gracefulShutdownTimeoutMs?: number;
drainTimeoutMs?: number;
forceClose?: boolean;
};| Option | Type | Default | Description |
|---|---|---|---|
gracefulShutdownTimeoutMs |
number |
30000 |
Maximum time to wait for graceful shutdown (30 sec) |
drainTimeoutMs |
number |
15000 |
Time to drain existing connections (15 sec) |
forceClose |
boolean |
true |
Force close connections after timeout |
const server = await createServer(neurolink, {
config: {
shutdown: {
gracefulShutdownTimeoutMs: 60000, // 60 seconds for long-running requests
drainTimeoutMs: 30000, // 30 seconds to drain connections
forceClose: true, // Force close after timeout
},
},
});The redaction system provides automatic sanitization of sensitive data in logs and responses. This feature is opt-in and must be explicitly enabled.
type RedactionConfig = {
enabled?: boolean;
additionalFields?: string[];
preserveFields?: string[];
redactToolArgs?: boolean;
redactToolResults?: boolean;
placeholder?: string;
};| Option | Type | Default | Description |
|---|---|---|---|
enabled |
boolean |
false |
Enable redaction (opt-in) |
additionalFields |
string[] |
[] |
Extra field names to redact |
preserveFields |
string[] |
[] |
Fields to exclude from redaction |
redactToolArgs |
boolean |
true |
Redact tool arguments (when enabled) |
redactToolResults |
boolean |
true |
Redact tool results (when enabled) |
placeholder |
string |
"[REDACTED]" |
Replacement text for redacted values |
When redaction is enabled, the following fields are redacted by default:
apiKeytokenauthorizationcredentialspasswordsecretrequestargsresult
const server = await createServer(neurolink, {
config: {
redaction: {
enabled: true,
additionalFields: ["ssn", "creditCard", "bankAccount"],
preserveFields: ["request"], // Allow 'request' field to pass through
redactToolArgs: true,
redactToolResults: false, // Keep tool results visible
placeholder: "***",
},
},
});const server = await createServer(neurolink, {
config: {
redaction: {
enabled: true,
// Uses all defaults - redacts apiKey, token, password, etc.
},
},
});import { createAuthMiddleware } from "@juspay/neurolink";
const authMiddleware = createAuthMiddleware({
type: "bearer", // 'bearer' | 'api-key' | 'basic' | 'custom'
validate: async (token, ctx) => {
// Return user info or null
const user = await verifyJWT(token);
return user ? { id: user.id, email: user.email, roles: user.roles } : null;
},
headerName: "Authorization", // Optional: custom header name
skipPaths: ["/api/health", "/api/ready"],
errorMessage: "Invalid authentication token",
});
server.registerMiddleware(authMiddleware);| Type | Header Format | Description |
|---|---|---|
bearer |
Authorization: Bearer <token> |
JWT/OAuth token |
api-key |
X-API-Key: <key> |
API key authentication |
basic |
Authorization: Basic <base64> |
HTTP Basic auth |
custom |
Custom | Use extractToken function |
import {
createRateLimitMiddleware,
createSlidingWindowRateLimitMiddleware,
} from "@juspay/neurolink";
// Fixed window rate limiter
const rateLimiter = createRateLimitMiddleware({
maxRequests: 100,
windowMs: 15 * 60 * 1000,
skipPaths: ["/api/health"],
});
// Sliding window rate limiter (more accurate)
const slidingRateLimiter = createSlidingWindowRateLimitMiddleware({
maxRequests: 100,
windowMs: 15 * 60 * 1000,
subWindows: 10, // Number of sub-windows for smoothing
});
server.registerMiddleware(rateLimiter);import { createCacheMiddleware, InMemoryCacheStore } from "@juspay/neurolink";
const cacheMiddleware = createCacheMiddleware({
ttlMs: 60 * 1000, // 1 minute cache
maxSize: 1000, // Max cached entries
methods: ["GET"], // Only cache GET requests
excludePaths: ["/api/agent/execute", "/api/agent/stream"],
includeQuery: true, // Include query params in cache key
ttlByPath: {
"/api/tools": 5 * 60 * 1000, // 5 minutes for tools
"/api/version": 60 * 60 * 1000, // 1 hour for version
},
});
server.registerMiddleware(cacheMiddleware);The cache middleware adds these headers to responses:
| Header | Description | Example |
|---|---|---|
X-Cache |
Cache status | HIT or MISS |
X-Cache-Age |
Seconds since cached (on HIT) | 45 |
Cache-Control |
Caching directive (on MISS) | max-age=300 |
import {
createRequestValidationMiddleware,
createFieldValidator,
} from "@juspay/neurolink";
// JSON Schema validation
const validationMiddleware = createRequestValidationMiddleware({
body: {
type: "object",
properties: {
input: { type: "string", minLength: 1 },
provider: { type: "string" },
},
required: ["input"],
},
});
// Field-level validation
const fieldValidator = createFieldValidator({
required: ["name", "email"],
types: { name: "string", email: "string", age: "number" },
validators: {
email: (value) => typeof value === "string" && value.includes("@"),
age: (value) => typeof value === "number" && value >= 0,
},
});
server.registerMiddleware(validationMiddleware);import { createRoleMiddleware } from "@juspay/neurolink";
// Require any of the specified roles
const adminMiddleware = createRoleMiddleware({
requiredRoles: ["admin", "superuser"],
requireAll: false, // Any role matches
errorMessage: "Admin access required",
});
// Require all specified roles
const superAdminMiddleware = createRoleMiddleware({
requiredRoles: ["admin", "superuser"],
requireAll: true, // All roles required
});import { ServerAdapterFactory } from "@juspay/neurolink";
const server = await ServerAdapterFactory.createHono(neurolink, {
port: 3000,
// Hono uses @hono/node-server under the hood
});For more details, see the Hono Guide.
const server = await ServerAdapterFactory.createExpress(neurolink, {
port: 3000,
// Express-specific middleware can be added via getFrameworkInstance()
});
const app = server.getFrameworkInstance();
app.use(customExpressMiddleware);For more details, see the Express Guide.
const server = await ServerAdapterFactory.createFastify(neurolink, {
port: 3000,
// Fastify plugins can be registered on the instance
});
const fastify = server.getFrameworkInstance();
await fastify.register(customFastifyPlugin);For more details, see the Fastify Guide.
const server = await ServerAdapterFactory.createKoa(neurolink, {
port: 3000,
// Koa middleware can be added via getFrameworkInstance()
});
const app = server.getFrameworkInstance();
app.use(customKoaMiddleware);For more details, see the Koa Guide.
import {
createServer,
createAuthMiddleware,
createRateLimitMiddleware,
createCacheMiddleware,
} from "@juspay/neurolink";
import { NeuroLink } from "@juspay/neurolink";
const neurolink = new NeuroLink({
defaultProvider: "openai",
});
const server = await createServer(neurolink, {
framework: "hono",
config: {
port: 8080,
host: "0.0.0.0",
basePath: "/v1",
timeout: 120000,
enableSwagger: true,
cors: {
enabled: true,
origins: ["https://app.example.com"],
credentials: true,
},
rateLimit: {
enabled: true,
maxRequests: 1000,
windowMs: 3600000,
},
bodyParser: {
maxSize: "25mb",
},
logging: {
level: "info",
},
},
});
// Add custom middleware
server.registerMiddleware(
createAuthMiddleware({
type: "bearer",
validate: async (token) => verifyToken(token),
skipPaths: ["/v1/health", "/v1/ready"],
}),
);
server.registerMiddleware(
createCacheMiddleware({
ttlMs: 300000,
methods: ["GET"],
}),
);
// Start server
await server.start();
console.log(`Server running on http://localhost:8080`);The server adapters respect these environment variables:
| Variable | Description | Default |
|---|---|---|
PORT |
Server port | 3000 |
HOST |
Server host | 0.0.0.0 |
NODE_ENV |
Environment mode | development |
npm_package_version |
Package version (for health endpoint) | unknown |
Invalid configuration will throw errors at initialization:
// This will throw: "Invalid port number"
const server = await createServer(neurolink, {
config: { port: -1 },
});
// This will throw: "Invalid rate limit configuration"
const server = await createServer(neurolink, {
config: { rateLimit: { maxRequests: -100 } },
});Always validate your configuration in development before deploying to production.
The server adapters expose the following endpoints (all prefixed with basePath, default /api):
| Method | Endpoint | Description |
|---|---|---|
| GET | /health |
Basic health check |
| GET | /ready |
Readiness probe |
| GET | /live |
Liveness probe |
| GET | /version |
Version information |
| Method | Endpoint | Description |
|---|---|---|
| POST | /agent/execute |
Execute agent with input |
| POST | /agent/stream |
Stream agent response |
| Method | Endpoint | Description |
|---|---|---|
| GET | /tools |
List available tools |
| POST | /tools/:name |
Execute a specific tool |
| GET | /tools/:name |
Get tool metadata |
| Method | Endpoint | Description |
|---|---|---|
| GET | /mcp/servers |
List MCP servers |
| POST | /mcp/execute |
Execute MCP tool |
| GET | /mcp/health |
MCP subsystem health check |
| Method | Endpoint | Description |
|---|---|---|
| GET | /memory/sessions |
List memory sessions |
| GET | /memory/sessions/:id |
Get session details |
| DELETE | /memory/sessions/:id |
Delete a session |
| DELETE | /memory/sessions |
Clear all sessions |
| GET | /memory/health |
Memory subsystem health check |
| Method | Endpoint | Description |
|---|---|---|
| GET | /openapi.json |
OpenAPI 3.1 spec (JSON) |
| GET | /openapi.yaml |
OpenAPI 3.1 spec (YAML) |
| GET | /docs |
Swagger UI |
Server adapters implement a comprehensive lifecycle management system that enables graceful startup, connection tracking, and orderly shutdown. Understanding the lifecycle is essential for production deployments.
The server adapter progresses through 9 distinct lifecycle states:
| State | Description |
|---|---|
uninitialized |
Initial state before initialize() is called |
initializing |
Framework and routes are being set up |
initialized |
Setup complete, ready to start |
starting |
Server is binding to port and preparing to listen |
running |
Server is actively accepting and processing requests |
draining |
No new connections accepted, existing ones finishing |
stopping |
Server is closing after connections drained |
stopped |
Server has completely shut down |
error |
An error occurred during any state transition |
┌─────────────────┐
│ uninitialized │◄──────────────────────────────────┐
└────────┬────────┘ │
│ initialize() │
▼ │
┌─────────────────┐ │
│ initializing │ │
└────────┬────────┘ │
│ success │
▼ │
┌─────────────────┐ │
│ initialized │◄──────────────────────────────────┤
└────────┬────────┘ │
│ start() │
▼ │
┌─────────────────┐ │
│ starting │ │
└────────┬────────┘ │
│ bound to port │
▼ │
┌─────────────────┐ │
│ running │ │
└────────┬────────┘ │
│ stop() │
▼ │
┌─────────────────┐ │
│ draining │──── drain timeout ────┐ │
└────────┬────────┘ │ │
│ connections drained │ │
▼ ▼ │
┌─────────────────┐ forceClose() │
│ stopping │◄──────────────────────┘ │
└────────┬────────┘ │
│ server closed │
▼ │
┌─────────────────┐ │
│ stopped │───────────────────────────────────┘
└─────────────────┘ (can restart)
Any state ─────────► ┌─────────────────┐
(on error) │ error │
└─────────────────┘
| Current State | Valid Next States | Trigger |
|---|---|---|
uninitialized |
initializing |
initialize() called |
initializing |
initialized, error |
Setup completes or fails |
initialized |
starting |
start() called |
starting |
running, error |
Port bound or bind fails |
running |
draining |
stop() called |
draining |
stopping |
Connections drained/timeout |
stopping |
stopped, error |
Server closes |
stopped |
initializing |
initialize() for restart |
error |
(terminal, requires new instance) | N/A |
Attempting an operation in an invalid state throws InvalidLifecycleStateError:
import { InvalidLifecycleStateError } from "@juspay/neurolink";
try {
await server.start(); // Called when already running
} catch (error) {
if (error instanceof InvalidLifecycleStateError) {
console.log(`Operation: ${error.operation}`);
console.log(`Current state: ${error.currentState}`);
console.log(`Expected states: ${error.expectedStates.join(", ")}`);
}
}
// Output:
// Operation: start
// Current state: running
// Expected states: initialized, stopped// Get current lifecycle state
const state = server.getLifecycleState();
console.log(`Server state: ${state}`);
// Get full server status including lifecycle
const status = server.getStatus();
console.log({
running: status.running,
lifecycleState: status.lifecycleState,
activeConnections: status.activeConnections,
uptime: status.uptime,
});Server adapters track active connections to enable graceful shutdown. This is essential for ensuring in-flight requests complete before the server stops.
type TrackedConnection = {
/** Unique connection identifier */
id: string;
/** Timestamp when connection was created */
createdAt: number;
/** Underlying socket or connection object */
socket?: unknown;
/** Request ID if associated with a request */
requestId?: string;
/** Whether the connection is currently processing a request */
isActive?: boolean;
};Framework adapters use these methods internally to track connections:
// Track a new connection (called by adapter implementations)
protected trackConnection(
id: string,
socket?: unknown,
requestId?: string
): void;
// Untrack a connection when completed
protected untrackConnection(id: string): void;
// Get count of active connections (public API)
public getActiveConnectionCount(): number;// Check active connections before shutdown
const activeCount = server.getActiveConnectionCount();
console.log(`Active connections: ${activeCount}`);
// Include in health check responses
app.get("/health", (req, res) => {
const status = server.getStatus();
res.json({
status: "ok",
connections: status.activeConnections,
lifecycleState: status.lifecycleState,
});
});Graceful shutdown ensures all in-flight requests complete before the server stops, preventing data loss and providing a better user experience.
When stop() is called, the server follows this sequence:
-
Stop Accepting Connections
- Server stops accepting new connections
- New requests receive connection refused
- State transitions to
draining
-
Drain Existing Connections
- Wait for in-flight requests to complete
- Monitor
activeConnectionscount - Timeout after
drainTimeoutMs
-
Handle Drain Timeout
- If connections remain after
drainTimeoutMs:- If
forceClose: true, forcibly close all connections - If
forceClose: false, throwDrainTimeoutError
- If
- If connections remain after
-
Close Server
- Close the underlying server
- State transitions to
stopping, thenstopped - Overall timeout enforced by
gracefulShutdownTimeoutMs
| Option | Type | Default | Description |
|---|---|---|---|
gracefulShutdownTimeoutMs |
number |
30000 |
Maximum total shutdown duration |
drainTimeoutMs |
number |
15000 |
Maximum time to wait for connections to complete |
forceClose |
boolean |
true |
If true, forcibly closes connections after drainTimeoutMs expires |
import { createServer } from "@juspay/neurolink";
import { ShutdownTimeoutError, DrainTimeoutError } from "@juspay/neurolink";
const server = await createServer(neurolink, {
framework: "hono",
config: {
port: 3000,
shutdown: {
gracefulShutdownTimeoutMs: 30000,
drainTimeoutMs: 15000,
forceClose: true,
},
},
});
await server.initialize();
await server.start();
// Handle shutdown signals
async function shutdown(signal: string): Promise<void> {
console.log(`Received ${signal}, starting graceful shutdown...`);
console.log(`Active connections: ${server.getActiveConnectionCount()}`);
try {
await server.stop();
console.log("Server stopped gracefully");
process.exit(0);
} catch (error) {
if (error instanceof ShutdownTimeoutError) {
console.error(
`Shutdown timed out with ${error.remainingConnections} connections`,
);
} else if (error instanceof DrainTimeoutError) {
console.error(
`Drain timed out with ${error.remainingConnections} connections`,
);
} else {
console.error("Shutdown error:", error);
}
process.exit(1);
}
}
process.on("SIGTERM", () => shutdown("SIGTERM"));
process.on("SIGINT", () => shutdown("SIGINT"));For Kubernetes deployments, configure appropriate timeouts:
const server = await createServer(neurolink, {
framework: "hono",
config: {
port: 3000,
shutdown: {
// Should be less than Kubernetes terminationGracePeriodSeconds
gracefulShutdownTimeoutMs: 25000,
drainTimeoutMs: 20000,
forceClose: true,
},
},
});In your Kubernetes deployment:
spec:
terminationGracePeriodSeconds: 30 # Must be > gracefulShutdownTimeoutMs
containers:
- name: api
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 5"] # Allow load balancer to drain| Error | Description | Handling |
|---|---|---|
ShutdownTimeoutError |
Overall shutdown exceeded gracefulShutdownTimeoutMs |
Force close was attempted if forceClose: true |
DrainTimeoutError |
Drain exceeded drainTimeoutMs with forceClose: false |
Connections remain open |
InvalidLifecycleStateError |
Called stop() when not in running state |
Server was not running |
Server adapters emit events at key lifecycle points. Subscribe to these events for monitoring, logging, and custom behaviors.
type ServerAdapterEvents = {
/** Emitted when server initialization completes */
initialized: {
config: ServerAdapterConfig;
routeCount: number;
middlewareCount: number;
};
/** Emitted when server starts listening */
started: {
port: number;
host: string;
timestamp: Date;
};
/** Emitted when server stops */
stopped: {
uptime: number;
timestamp: Date;
};
/** Emitted for each incoming request */
request: {
requestId: string;
method: string;
path: string;
timestamp: Date;
};
/** Emitted for each outgoing response */
response: {
requestId: string;
statusCode: number;
duration: number;
timestamp: Date;
};
/** Emitted when an error occurs */
error: {
requestId?: string;
error: Error;
timestamp: Date;
};
};const server = await createServer(neurolink, {
framework: "hono",
config: { port: 3000 },
});
// Lifecycle events
server.on("initialized", (event) => {
console.log(`Server initialized with ${event.routeCount} routes`);
});
server.on("started", (event) => {
console.log(`Server started on ${event.host}:${event.port}`);
});
server.on("stopped", (event) => {
console.log(`Server stopped after ${event.uptime}ms uptime`);
});
// Request/response events for monitoring
server.on("request", (event) => {
console.log(`[${event.requestId}] ${event.method} ${event.path}`);
});
server.on("response", (event) => {
console.log(
`[${event.requestId}] ${event.statusCode} in ${event.duration}ms`,
);
});
// Error tracking
server.on("error", (event) => {
console.error(`[${event.requestId ?? "unknown"}] Error:`, event.error);
});
await server.initialize();
await server.start();import { createServer } from "@juspay/neurolink";
const metrics = {
requests: 0,
responses: 0,
errors: 0,
totalDuration: 0,
};
const server = await createServer(neurolink, {
framework: "hono",
config: { port: 3000 },
});
server.on("request", () => {
metrics.requests++;
});
server.on("response", (event) => {
metrics.responses++;
metrics.totalDuration += event.duration;
});
server.on("error", () => {
metrics.errors++;
});
// Expose metrics endpoint
server.registerRoute({
method: "GET",
path: "/metrics/custom",
handler: async () => ({
requests: metrics.requests,
responses: metrics.responses,
errors: metrics.errors,
avgDuration:
metrics.responses > 0 ? metrics.totalDuration / metrics.responses : 0,
activeConnections: server.getActiveConnectionCount(),
lifecycleState: server.getLifecycleState(),
}),
description: "Custom application metrics",
tags: ["monitoring"],
});NeuroLink includes a powerful OpenAPI 3.1 specification generator that creates comprehensive API documentation from your server routes. This section covers how to customize the generated OpenAPI specification.
The OpenAPIGenerator class is the core component for generating OpenAPI specifications.
import { OpenAPIGenerator } from "@juspay/neurolink";
const generator = new OpenAPIGenerator({
// Customize API info
info: {
title: "My Custom API",
version: "2.0.0",
description: "Custom API description",
},
// Server configuration
servers: [
{ url: "https://api.example.com", description: "Production" },
{ url: "https://staging-api.example.com", description: "Staging" },
],
// Base path for all routes
basePath: "/v2",
// Include security schemes in the spec
includeSecurity: true,
// Add custom tags
additionalTags: [
{ name: "custom", description: "Custom endpoints" },
{ name: "analytics", description: "Analytics and reporting" },
],
// Add custom schemas
customSchemas: {
CustomRequest: {
type: "object",
properties: {
customField: { type: "string" },
},
},
},
// Pass routes to document
routes: myRouteDefinitions,
});
// Generate the specification
const spec = generator.generate();
// Export as JSON or YAML
const jsonSpec = generator.toJSON(true); // pretty-printed
const yamlSpec = generator.toYAML();| Option | Type | Default | Description |
|---|---|---|---|
info |
object |
- | Override API info (title, version, description) |
servers |
array |
- | Custom server URLs |
basePath |
string |
/api |
Base path for all routes |
includeSecurity |
boolean |
true |
Include security schemes |
additionalTags |
array |
[] |
Extra API tags |
customSchemas |
object |
{} |
Custom JSON schemas to add |
routes |
array |
[] |
Route definitions to document |
// Add routes after initialization
generator.addRoutes(routeArray);
generator.addRoute(singleRoute);
// Generate the OpenAPI spec
const spec = generator.generate();
// Export formats
const json = generator.toJSON(true); // pretty-printed JSON
const yaml = generator.toYAML(); // YAML formatNeuroLink provides pre-defined JSON schemas for common API types.
import { ErrorResponseSchema, TokenUsageSchema } from "@juspay/neurolink";
// ErrorResponseSchema
// - error.code (string): Error code identifier
// - error.message (string): Human-readable error message
// - error.details (object): Additional error details
// - metadata.timestamp (date-time): Error timestamp
// - metadata.requestId (string): Request identifier
// TokenUsageSchema
// - input (integer): Input/prompt tokens
// - output (integer): Output/completion tokens
// - total (integer): Total tokens used
// - cacheCreationTokens (integer): Tokens for cache creation
// - cacheReadTokens (integer): Tokens read from cache
// - reasoning (integer): Tokens used for reasoning
// - cacheSavingsPercent (number): Cache savings percentageimport {
AgentExecuteRequestSchema,
AgentExecuteResponseSchema,
AgentInputSchema,
ProviderInfoSchema,
} from "@juspay/neurolink";
// AgentExecuteRequestSchema
// - input (string | object): Agent input
// - provider (string): AI provider to use
// - model (string): Specific model
// - systemPrompt (string): System prompt
// - temperature (number): Sampling temperature (0-2)
// - maxTokens (integer): Maximum tokens to generate
// - tools (string[]): Tool names to enable
// - stream (boolean): Enable streaming
// - sessionId (string): Session ID for memory
// - userId (string): User ID for context
// AgentExecuteResponseSchema
// - content (string): Generated text content
// - provider (string): Provider used
// - model (string): Model used
// - usage (TokenUsage): Token usage
// - toolCalls (array): Tool calls made
// - finishReason (string): Completion reasonimport {
ToolDefinitionSchema,
ToolExecuteRequestSchema,
ToolExecuteResponseSchema,
ToolListResponseSchema,
ToolParameterSchema,
} from "@juspay/neurolink";
// ToolDefinitionSchema
// - name (string): Tool name
// - description (string): Tool description
// - source (string): Tool source (builtin, external, custom)
// - parameters (object): Tool parameters schema
// ToolExecuteRequestSchema
// - name (string): Tool name to execute
// - arguments (object): Tool arguments
// - sessionId (string): Session context
// - userId (string): User context
// ToolExecuteResponseSchema
// - success (boolean): Execution success
// - data: Result data
// - error (string): Error message if failed
// - duration (number): Execution duration in msimport {
MCPServerStatusSchema,
MCPServersListResponseSchema,
MCPServerToolSchema,
} from "@juspay/neurolink";
// MCPServerStatusSchema
// - serverId (string): Server ID
// - name (string): Server name
// - status (string): connected | disconnected | error | connecting
// - toolCount (integer): Number of available tools
// - lastHealthCheck (date-time): Last health check timestamp
// - error (string): Error message if in error stateimport {
HealthResponseSchema,
ReadyResponseSchema,
MetricsResponseSchema,
} from "@juspay/neurolink";
// HealthResponseSchema
// - status (string): ok | degraded | unhealthy
// - timestamp (date-time): Check timestamp
// - uptime (integer): Server uptime in ms
// - version (string): Server version
// ReadyResponseSchema
// - ready (boolean): Overall readiness
// - timestamp (date-time): Check timestamp
// - services.neurolink (boolean): SDK status
// - services.tools (boolean): Tool registry status
// - services.externalServers (boolean): MCP servers statusThe OpenAPI module provides template functions for creating operations and parameters.
import {
createGetOperation,
createPostOperation,
createStreamingPostOperation,
createDeleteOperation,
} from "@juspay/neurolink";
// GET operation
const getOp = createGetOperation(
"List users", // summary
"Get all users in the system", // description
["users"], // tags
"UserListResponse", // response schema reference
[limitParam, offsetParam], // optional parameters
);
// POST operation
const postOp = createPostOperation(
"Create user", // summary
"Create a new user", // description
["users"], // tags
"CreateUserRequest", // request schema reference
"UserResponse", // response schema reference
[authHeader], // optional parameters
);
// Streaming POST operation
const streamOp = createStreamingPostOperation(
"Stream data", // summary
"Stream data via SSE", // description
["streaming"], // tags
"StreamRequest", // request schema reference
);
// DELETE operation
const deleteOp = createDeleteOperation(
"Delete user", // summary
"Delete a user by ID", // description
["users"], // tags
[userIdParam], // parameters
);import {
createPathParameter,
createQueryParameter,
createHeaderParameter,
CommonParameters,
} from "@juspay/neurolink";
// Path parameter
const userIdParam = createPathParameter(
"userId", // name
"User ID", // description
{ type: "string", format: "uuid" }, // schema (optional)
);
// Query parameter
const searchParam = createQueryParameter(
"q", // name
"Search query", // description
{ type: "string" }, // schema (optional)
false, // required (optional, default: false)
);
// Header parameter
const apiKeyHeader = createHeaderParameter(
"X-API-Key", // name
"API key for authentication", // description
true, // required (optional, default: false)
);
// Pre-defined common parameters
const { sessionId, serverName, toolName } = CommonParameters;
const { limitQuery, offsetQuery, searchQuery } = CommonParameters;
const { requestIdHeader, authorizationHeader } = CommonParameters;NeuroLink provides pre-defined security schemes for common authentication methods.
import {
BearerSecurityScheme,
ApiKeySecurityScheme,
BasicSecurityScheme,
} from "@juspay/neurolink";
// Bearer token (JWT)
// {
// type: "http",
// scheme: "bearer",
// bearerFormat: "JWT",
// description: "JWT Bearer token authentication"
// }
// API Key (header)
// {
// type: "apiKey",
// in: "header",
// name: "X-API-Key",
// description: "API key authentication via header"
// }
// Basic auth
// {
// type: "http",
// scheme: "basic",
// description: "HTTP Basic authentication"
// }const generator = new OpenAPIGenerator({
includeSecurity: true, // Enables security schemes
});
const spec = generator.generate();
// spec.components.securitySchemes = {
// bearerAuth: BearerSecurityScheme,
// apiKeyAuth: ApiKeySecurityScheme
// }
// spec.security = [{ bearerAuth: [] }, { apiKeyAuth: [] }]Add custom schemas to extend the built-in types.
const generator = new OpenAPIGenerator({
customSchemas: {
// Simple custom schema
MyCustomType: {
type: "object",
required: ["id", "name"],
properties: {
id: { type: "string", format: "uuid" },
name: { type: "string", minLength: 1 },
metadata: { type: "object", additionalProperties: true },
},
},
// Extended schema referencing built-in types
ExtendedAgentResponse: {
allOf: [
{ $ref: "#/components/schemas/AgentExecuteResponse" },
{
type: "object",
properties: {
customField: { type: "string" },
analytics: { $ref: "#/components/schemas/AnalyticsData" },
},
},
],
},
// Enum schema
Priority: {
type: "string",
enum: ["low", "medium", "high", "critical"],
description: "Priority level",
},
},
});import {
OpenAPIGenerator,
createGetOperation,
createPostOperation,
createPathParameter,
createQueryParameter,
BearerSecurityScheme,
} from "@juspay/neurolink";
// Create generator with full customization
const generator = new OpenAPIGenerator({
info: {
title: "Enterprise AI API",
version: "3.0.0",
description: `
Enterprise AI API provides secure access to AI capabilities.
## Features
- Multi-model AI generation
- Real-time streaming
- Tool execution
- Conversation memory
## Rate Limits
- Standard: 1000 req/hour
- Enterprise: Unlimited
`.trim(),
},
servers: [
{ url: "https://api.enterprise.com/v3", description: "Production" },
{ url: "https://api.staging.enterprise.com/v3", description: "Staging" },
{ url: "http://localhost:3000/v3", description: "Local Development" },
],
basePath: "/v3",
includeSecurity: true,
additionalTags: [
{ name: "analytics", description: "Usage analytics and reporting" },
{ name: "admin", description: "Administrative operations" },
{ name: "webhooks", description: "Webhook management" },
],
customSchemas: {
// Custom request types
WebhookConfig: {
type: "object",
required: ["url", "events"],
properties: {
url: { type: "string", format: "uri" },
events: {
type: "array",
items: { type: "string", enum: ["execute", "error", "complete"] },
},
secret: { type: "string", description: "HMAC secret for validation" },
},
},
// Custom response types
AnalyticsReport: {
type: "object",
properties: {
period: { type: "string" },
totalRequests: { type: "integer" },
averageLatency: { type: "number" },
tokenUsage: { $ref: "#/components/schemas/TokenUsage" },
topModels: {
type: "array",
items: {
type: "object",
properties: {
model: { type: "string" },
count: { type: "integer" },
},
},
},
},
},
},
});
// Add custom routes
generator.addRoute({
method: "GET",
path: "/v3/analytics",
description: "Get usage analytics for the specified period",
tags: ["analytics"],
responseSchema: { $ref: "#/components/schemas/AnalyticsReport" },
auth: true,
});
generator.addRoute({
method: "POST",
path: "/v3/webhooks",
description: "Register a new webhook endpoint",
tags: ["webhooks"],
requestSchema: { $ref: "#/components/schemas/WebhookConfig" },
responseSchema: {
type: "object",
properties: {
id: { type: "string" },
status: { type: "string" },
},
},
auth: true,
});
// Generate the specification
const spec = generator.generate();
// Export to file
import { writeFileSync } from "fs";
writeFileSync("openapi.json", generator.toJSON(true));
writeFileSync("openapi.yaml", generator.toYAML());For quick OpenAPI generation without instantiating the class:
import {
createOpenAPIGenerator,
generateOpenAPISpec,
generateOpenAPIFromConfig,
} from "@juspay/neurolink";
// Create generator with config
const generator = createOpenAPIGenerator({
basePath: "/api",
includeSecurity: true,
});
// Generate spec directly from routes
const spec = generateOpenAPISpec(routes, {
info: { title: "My API", version: "1.0.0" },
});
// Generate from server adapter configuration
const spec = generateOpenAPIFromConfig(serverConfig, routes);
// Automatically uses host/port from serverConfigThe OpenAPISchemas registry provides access to all built-in schemas:
import { OpenAPISchemas } from "@juspay/neurolink";
// Common
OpenAPISchemas.ErrorResponse;
OpenAPISchemas.TokenUsage;
// Agent
OpenAPISchemas.AgentInput;
OpenAPISchemas.AgentExecuteRequest;
OpenAPISchemas.AgentExecuteResponse;
OpenAPISchemas.ToolCall;
OpenAPISchemas.ProviderInfo;
// Tools
OpenAPISchemas.ToolParameter;
OpenAPISchemas.ToolDefinition;
OpenAPISchemas.ToolListResponse;
OpenAPISchemas.ToolExecuteRequest;
OpenAPISchemas.ToolExecuteResponse;
// MCP
OpenAPISchemas.MCPServerTool;
OpenAPISchemas.MCPServerStatus;
OpenAPISchemas.MCPServersListResponse;
// Memory
OpenAPISchemas.ConversationMessage;
OpenAPISchemas.Session;
OpenAPISchemas.SessionsListResponse;
// Health
OpenAPISchemas.HealthResponse;
OpenAPISchemas.ReadyResponse;
OpenAPISchemas.MetricsResponse;- Server Adapters Overview - Introduction to server adapters
- Security Guide - Security best practices
- Deployment Guide - Deployment strategies and configurations