@elsium-ai/app

App bootstrap, HTTP server, and API routes for ElsiumAI.

Install

npm install @elsium-ai/app

What’s Inside

Category Export Kind
App createApp Function
ElsiumApp Interface
Types AppConfig Interface
ServerConfig Interface
CorsConfig Interface
AuthConfig Interface
RateLimitConfig Interface
ChatRequest Interface
ChatResponse Interface
CompleteRequest Interface
HealthResponse Interface
MetricsResponse Interface
Middleware corsMiddleware Function
authMiddleware Function
rateLimitMiddleware Function
Routes createRoutes Function
RoutesDeps Interface
RBAC createRBAC Function
Permission Type
Role Interface
RBACConfig Interface
RBAC Interface

App

createApp

Creates and returns a fully configured ElsiumAI application with a gateway, tracer, middleware stack, agent registry, and HTTP routes.

function createApp(config: AppConfig): ElsiumApp
ParameterTypeDescription
configAppConfigFull application configuration including gateway, agents, observability, and server settings.

Returns ElsiumApp — the application handle exposing the Hono instance, gateway, tracer, and a listen method to start the HTTP server.

import { createApp } from '@elsium-ai/app'

const app = createApp({
  gateway: {
    providers: {
      openai: { apiKey: process.env.OPENAI_API_KEY! },
    },
    defaultModel: 'gpt-4o',
  },
  server: {
    port: 3000,
    cors: { origin: ['http://localhost:5173'], credentials: true },
    auth: { type: 'bearer', token: process.env.API_TOKEN! },
    rateLimit: { windowMs: 60_000, maxRequests: 100 },
  },
})

const { port, stop } = app.listen()
console.log(`Listening on port ${port}`)

ElsiumApp

The object returned by createApp. Provides access to the underlying Hono app, gateway, tracer, and a method to start the HTTP server.

interface ElsiumApp {
  readonly hono: Hono
  readonly gateway: Gateway
  readonly tracer: Tracer
  listen(port?: number): { port: number; stop: () => void }
}
Property / MethodTypeDescription
honoHonoThe underlying Hono application instance. Use it to add custom routes or middleware.
gatewayGatewayThe configured LLM gateway.
tracerTracerThe observability tracer for cost and latency tracking.
listen(port?)(port?: number) => { port: number; stop: () => void }Starts the HTTP server. Falls back to server.port from config, then 3000. Returns the resolved port and a stop function to shut down the server.

Types

AppConfig

Top-level configuration object passed to createApp.

interface AppConfig {
  gateway: {
    providers: Record<string, { apiKey: string; baseUrl?: string }>
    defaultModel?: string
  }
  agents?: Agent[]
  rag?: RAGPipeline
  observe?: {
    tracing?: boolean
    costTracking?: boolean
    export?: string
  }
  server?: ServerConfig
}

ServerConfig

HTTP server and middleware configuration.

interface ServerConfig {
  port?: number
  hostname?: string
  cors?: boolean | CorsConfig
  auth?: AuthConfig
  rateLimit?: RateLimitConfig
}

CorsConfig

Fine-grained CORS settings. When cors in ServerConfig is set to true, sensible defaults are used.

interface CorsConfig {
  origin?: string | string[]
  methods?: string[]
  headers?: string[]
  credentials?: boolean
}

AuthConfig

Bearer-token authentication configuration. The middleware uses timing-safe comparison to validate tokens.

interface AuthConfig {
  type: 'bearer'
  token: string
}

RateLimitConfig

Per-client sliding-window rate limiting configuration.

interface RateLimitConfig {
  windowMs: number
  maxRequests: number
}

ChatRequest

Request body for the POST /chat endpoint.

interface ChatRequest {
  message: string
  agent?: string
  stream?: boolean
}

ChatResponse

Response body from the POST /chat endpoint.

interface ChatResponse {
  message: string
  usage: {
    inputTokens: number
    outputTokens: number
    totalTokens: number
    cost: number
  }
  model: string
  traceId: string
}

CompleteRequest

Request body for the POST /complete endpoint.

interface CompleteRequest {
  messages: Array<{ role: string; content: string }>
  model?: string
  system?: string
  maxTokens?: number
  temperature?: number
  stream?: boolean
}

HealthResponse

Response body from the GET /health endpoint.

interface HealthResponse {
  status: 'ok' | 'degraded'
  version: string
  uptime: number
  providers: string[]
}

MetricsResponse

Response body from the GET /metrics endpoint.

interface MetricsResponse {
  uptime: number
  totalRequests: number
  totalTokens: number
  totalCost: number
  byModel: Record<string, { requests: number; tokens: number; cost: number }>
}

Middleware

All middleware functions return a Hono-compatible handler (c: Context, next: Next) => Promise<...>. They are applied automatically when the corresponding ServerConfig field is set, but they can also be used standalone on any Hono app.

corsMiddleware

Returns a Hono middleware that sets CORS headers and handles preflight OPTIONS requests.

function corsMiddleware(config?: CorsConfig | boolean): (c: Context, next: Next) => Promise<Response | void>
ParameterTypeDefaultDescription
configCorsConfig | booleantrueWhen true, uses default methods ['GET', 'POST', 'OPTIONS'] and an empty origin list. Pass a CorsConfig object for fine-grained control.
import { corsMiddleware } from '@elsium-ai/app'
import { Hono } from 'hono'

const app = new Hono()

app.use('*', corsMiddleware({
  origin: ['https://myapp.com'],
  methods: ['GET', 'POST'],
  credentials: true,
}))

authMiddleware

Returns a Hono middleware that validates Authorization: Bearer <token> headers using timing-safe comparison. The /health endpoint is always excluded from auth checks.

function authMiddleware(config: AuthConfig): (c: Context, next: Next) => Promise<Response | void>
ParameterTypeDescription
configAuthConfigMust specify type: 'bearer' and the expected token string.

Responses on failure:

  • 401 with { error: 'Missing Authorization header' } when the header is absent.
  • 401 with { error: 'Invalid token' } when the token does not match.
import { authMiddleware } from '@elsium-ai/app'
import { Hono } from 'hono'

const app = new Hono()

app.use('*', authMiddleware({
  type: 'bearer',
  token: process.env.API_TOKEN!,
}))

rateLimitMiddleware

Returns a Hono middleware that enforces per-client rate limiting using an in-memory sliding window. Client identity is determined from the CF-Connecting-IP header, then X-Real-IP, falling back to 'anonymous'. Sets X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset response headers.

function rateLimitMiddleware(config: RateLimitConfig): (c: Context, next: Next) => Promise<Response | void>
ParameterTypeDescription
configRateLimitConfigwindowMs is the time window in milliseconds; maxRequests is the maximum number of requests allowed per window.

Responses on failure:

  • 429 with { error: 'Too many requests', retryAfterMs: number } when the limit is exceeded.
import { rateLimitMiddleware } from '@elsium-ai/app'
import { Hono } from 'hono'

const app = new Hono()

app.use('*', rateLimitMiddleware({
  windowMs: 60_000,
  maxRequests: 100,
}))

Routes

createRoutes

Creates a Hono sub-application with all built-in API routes: GET /health, GET /metrics, POST /chat, POST /complete, and GET /agents.

function createRoutes(deps: RoutesDeps): Hono
ParameterTypeDescription
depsRoutesDepsDependencies injected into route handlers, including the gateway, agent registry, tracer, and server metadata.

Returns a Hono instance with the following routes:

MethodPathDescription
GET/healthReturns a HealthResponse with status, version, uptime, and provider list.
GET/metricsReturns a MetricsResponse with request counts, token usage, and cost breakdowns.
POST/chatAccepts a ChatRequest, dispatches to the specified (or default) agent, and returns a ChatResponse.
POST/completeAccepts a CompleteRequest, forwards to the gateway, and returns the completion result.
GET/agentsLists all registered agents with their names, models, and tool names.
import { createRoutes } from '@elsium-ai/app'
import { Hono } from 'hono'

const routes = createRoutes({
  gateway: myGateway,
  agents: new Map([['assistant', myAgent]]),
  defaultAgent: myAgent,
  tracer: myTracer,
  startTime: Date.now(),
  version: '1.0.0',
  providers: ['openai'],
})

const app = new Hono()
app.route('/', routes)

RoutesDeps

Dependency injection interface for createRoutes.

interface RoutesDeps {
  gateway: Gateway
  agents: Map<string, Agent>
  defaultAgent?: Agent
  tracer?: Tracer
  startTime: number
  version: string
  providers: string[]
}
FieldTypeDescription
gatewayGatewayThe LLM gateway used by the /complete endpoint.
agentsMap<string, Agent>Registry of named agents used by the /chat endpoint.
defaultAgentAgent (optional)The agent used when no agent field is specified in a chat request.
tracerTracer (optional)Observability tracer for tracking LLM calls.
startTimenumberTimestamp (ms) when the server started, used to calculate uptime.
versionstringApplication version string returned by /health.
providersstring[]List of configured provider names returned by /health.

RBAC

createRBAC

Creates a role-based access control system with permission checking, role inheritance, wildcard matching, and Hono middleware generation. Includes four built-in roles (admin, operator, user, viewer) that can be overridden by user-defined roles.

function createRBAC(config: RBACConfig): RBAC
ParameterTypeDescription
configRBACConfigDefines custom roles, a default role, and how the role is extracted from each request.

Returns an RBAC object with methods for permission checking and middleware creation.

Built-in roles:

RolePermissions
adminmodel:use:*, agent:execute:*, tool:call:*, config:read, config:write, audit:read, audit:write
operatormodel:use:*, agent:execute:*, tool:call:*, config:read, audit:read
usermodel:use, agent:execute, tool:call
viewerconfig:read, audit:read
import { createRBAC } from '@elsium-ai/app'

const rbac = createRBAC({
  roles: [
    {
      name: 'analyst',
      permissions: ['model:use:gpt-4o-mini'],
      inherits: ['viewer'],
    },
  ],
  defaultRole: 'viewer',
})

// Check a permission
rbac.hasPermission('analyst', 'model:use:gpt-4o-mini') // true
rbac.hasPermission('analyst', 'config:read')            // true (inherited from viewer)

// Use as Hono middleware
app.post('/chat', rbac.middleware('model:use'), handler)

Permission

A union type representing all recognized permissions. Supports resource-specific and wildcard variants.

type Permission =
  | 'model:use'
  | 'model:use:*'
  | `model:use:${string}`
  | 'agent:execute'
  | 'agent:execute:*'
  | `agent:execute:${string}`
  | 'tool:call'
  | 'tool:call:*'
  | `tool:call:${string}`
  | 'config:read'
  | 'config:write'
  | 'audit:read'
  | 'audit:write'

Wildcard permissions (e.g., model:use:*) grant access to all resource-specific permissions under that namespace (e.g., model:use:gpt-4o) as well as the base permission (model:use).

Role

Defines a named role with a set of permissions and optional inheritance from other roles.

interface Role {
  name: string
  permissions: Permission[]
  inherits?: string[]
}

RBACConfig

Configuration for createRBAC.

interface RBACConfig {
  roles: Role[]
  defaultRole?: string
  roleExtractor?: (c: Context) => string | undefined
  trustRoleHeader?: boolean
}
FieldTypeDescription
rolesRole[]Custom role definitions. These override built-in roles with the same name.
defaultRolestring (optional)The role assigned when no role can be determined from the request. Defaults to 'viewer'.
roleExtractor(c: Context) => string | undefined (optional)Custom function to extract the role name from a Hono request context.
trustRoleHeaderboolean (optional)When true, reads the role from the X-Role request header. Warning: only enable this in development or behind a trusted reverse proxy, as any client can self-assign roles.

RBAC

The object returned by createRBAC.

interface RBAC {
  hasPermission(role: string, permission: Permission): boolean
  middleware(required: Permission): (c: Context, next: Next) => Promise<Response | undefined>
  getRolePermissions(role: string): Permission[]
}
MethodDescription
hasPermission(role, permission)Returns true if the given role (including inherited permissions) grants the specified permission.
middleware(required)Returns a Hono middleware that rejects requests with 403 if the caller’s role lacks the required permission.
getRolePermissions(role)Returns the deduplicated list of all permissions for a role, including those inherited from parent roles.

Tenant Middleware

Multi-tenant isolation middleware for per-tenant rate limiting and budget enforcement.

Export Signature Description
tenantMiddleware tenantMiddleware(config: TenantMiddlewareConfig): HonoMiddleware Resolve tenant from request context
tenantRateLimitMiddleware tenantRateLimitMiddleware(): HonoMiddleware Per-tenant request rate limiting (uses maxRequestsPerMinute from tenant limits)
tenantBudgetMiddleware tenantBudgetMiddleware(): HonoMiddleware Per-tenant token and cost budget enforcement (fixed/reset window, 429 on exceed)

TenantMiddlewareConfig

interface TenantMiddlewareConfig {
  extractTenant: (c: Context) => TenantContext | null  // Resolve tenant from request
  onUnknownTenant?: 'reject' | 'default'               // Behavior for unknown tenants (default: 'reject')
  defaultTenant?: TenantContext                          // Fallback tenant when using 'default' mode
}

Example

import { tenantMiddleware, tenantRateLimitMiddleware, tenantBudgetMiddleware } from '@elsium-ai/app'

app.use('*', tenantMiddleware({
  extractTenant: (c) => {
    const apiKey = c.req.header('X-API-Key')
    return apiKey ? lookupTenant(apiKey) : null
  },
  onUnknownTenant: 'reject',
}))

app.use('*', tenantRateLimitMiddleware())
app.use('*', tenantBudgetMiddleware())

SSE Utilities

Server-Sent Events helpers for streaming responses.

Export Signature Description
sseHeaders sseHeaders(): Record<string, string> Standard SSE response headers (Content-Type, Cache-Control, Connection, X-Accel-Buffering)
formatSSE formatSSE(event: string, data: unknown): string Format a named SSE event with JSON data
streamResponse streamResponse(c: Context, source: ElsiumStream | AsyncIterable<unknown>): Response Convert an ElsiumStream to an SSE Response

Stream Event Types

interface StreamChatEvent {
  type: 'text_delta' | 'message_end' | 'error'
  text?: string
  usage?: { inputTokens: number; outputTokens: number; totalTokens: number }
  error?: string
}

interface StreamCompleteEvent {
  type: 'text_delta' | 'tool_call_start' | 'tool_call_delta' | 'message_end' | 'error'
  text?: string
  toolCall?: { id: string; name: string }
  toolCallId?: string
  arguments?: string
  usage?: { inputTokens: number; outputTokens: number; totalTokens: number }
  error?: string
}

Example

import { sseHeaders, formatSSE } from '@elsium-ai/app'

const headers = sseHeaders()
// => { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', ... }

const message = formatSSE('message', { type: 'text_delta', text: 'Hello' })
// => 'data: {"type":"text_delta","text":"Hello"}\n\n'

const named = formatSSE('error', { message: 'Something went wrong' })
// => 'event: error\ndata: {"message":"Something went wrong"}\n\n'

Part of ElsiumAI

This package is the app bootstrap layer of the ElsiumAI framework. See the Getting Started guide or the Fundamentals for comprehensive coverage of every feature.

License

MIT