@elsium-ai/app 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +502 -17
  2. package/package.json +9 -9
package/README.md CHANGED
@@ -8,37 +8,522 @@ App bootstrap, HTTP server, and API routes for [ElsiumAI](https://github.com/els
8
8
  ## Install
9
9
 
10
10
  ```bash
11
- npm install @elsium-ai/app @elsium-ai/core
11
+ npm install @elsium-ai/app
12
12
  ```
13
13
 
14
14
  ## What's Inside
15
15
 
16
- - **HTTP Server** Built-in server with route definitions
17
- - **CORS** Configurable cross-origin resource sharing
18
- - **Auth** Authentication middleware
19
- - **Rate Limiting** Request rate limiting per client
20
- - **RBAC** Role-based access control with inheritance and wildcard matching
16
+ | Category | Export | Kind |
17
+ | --- | --- | --- |
18
+ | **App** | `createApp` | Function |
19
+ | | `ElsiumApp` | Interface |
20
+ | **Types** | `AppConfig` | Interface |
21
+ | | `ServerConfig` | Interface |
22
+ | | `CorsConfig` | Interface |
23
+ | | `AuthConfig` | Interface |
24
+ | | `RateLimitConfig` | Interface |
25
+ | | `ChatRequest` | Interface |
26
+ | | `ChatResponse` | Interface |
27
+ | | `CompleteRequest` | Interface |
28
+ | | `HealthResponse` | Interface |
29
+ | | `MetricsResponse` | Interface |
30
+ | **Middleware** | `corsMiddleware` | Function |
31
+ | | `authMiddleware` | Function |
32
+ | | `rateLimitMiddleware` | Function |
33
+ | **Routes** | `createRoutes` | Function |
34
+ | | `RoutesDeps` | Interface |
35
+ | **RBAC** | `createRBAC` | Function |
36
+ | | `Permission` | Type |
37
+ | | `Role` | Interface |
38
+ | | `RBACConfig` | Interface |
39
+ | | `RBAC` | Interface |
21
40
 
22
- ## Usage
41
+ ---
23
42
 
24
- ```typescript
25
- import { createApp, createRBAC } from '@elsium-ai/app'
43
+ ## App
44
+
45
+ ### `createApp`
46
+
47
+ Creates and returns a fully configured ElsiumAI application with a gateway, tracer, middleware stack, agent registry, and HTTP routes.
48
+
49
+ ```ts
50
+ function createApp(config: AppConfig): ElsiumApp
51
+ ```
52
+
53
+ | Parameter | Type | Description |
54
+ | --- | --- | --- |
55
+ | `config` | `AppConfig` | Full application configuration including gateway, agents, observability, and server settings. |
56
+
57
+ **Returns** `ElsiumApp` -- the application handle exposing the Hono instance, gateway, tracer, and a `listen` method to start the HTTP server.
58
+
59
+ ```ts
60
+ import { createApp } from '@elsium-ai/app'
61
+
62
+ const app = createApp({
63
+ gateway: {
64
+ providers: {
65
+ openai: { apiKey: process.env.OPENAI_API_KEY! },
66
+ },
67
+ defaultModel: 'gpt-4o',
68
+ },
69
+ server: {
70
+ port: 3000,
71
+ cors: { origin: ['http://localhost:5173'], credentials: true },
72
+ auth: { type: 'bearer', token: process.env.API_TOKEN! },
73
+ rateLimit: { windowMs: 60_000, maxRequests: 100 },
74
+ },
75
+ })
76
+
77
+ const { port, stop } = app.listen()
78
+ console.log(`Listening on port ${port}`)
79
+ ```
80
+
81
+ ### `ElsiumApp`
82
+
83
+ The object returned by `createApp`. Provides access to the underlying Hono app, gateway, tracer, and a method to start the HTTP server.
84
+
85
+ ```ts
86
+ interface ElsiumApp {
87
+ readonly hono: Hono
88
+ readonly gateway: Gateway
89
+ readonly tracer: Tracer
90
+ listen(port?: number): { port: number; stop: () => void }
91
+ }
92
+ ```
93
+
94
+ | Property / Method | Type | Description |
95
+ | --- | --- | --- |
96
+ | `hono` | `Hono` | The underlying Hono application instance. Use it to add custom routes or middleware. |
97
+ | `gateway` | `Gateway` | The configured LLM gateway. |
98
+ | `tracer` | `Tracer` | The observability tracer for cost and latency tracking. |
99
+ | `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. |
100
+
101
+ ---
102
+
103
+ ## Types
104
+
105
+ ### `AppConfig`
106
+
107
+ Top-level configuration object passed to `createApp`.
108
+
109
+ ```ts
110
+ interface AppConfig {
111
+ gateway: {
112
+ providers: Record<string, { apiKey: string; baseUrl?: string }>
113
+ defaultModel?: string
114
+ }
115
+ agents?: Agent[]
116
+ rag?: RAGPipeline
117
+ observe?: {
118
+ tracing?: boolean
119
+ costTracking?: boolean
120
+ export?: string
121
+ }
122
+ server?: ServerConfig
123
+ }
124
+ ```
125
+
126
+ ### `ServerConfig`
127
+
128
+ HTTP server and middleware configuration.
129
+
130
+ ```ts
131
+ interface ServerConfig {
132
+ port?: number
133
+ hostname?: string
134
+ cors?: boolean | CorsConfig
135
+ auth?: AuthConfig
136
+ rateLimit?: RateLimitConfig
137
+ }
138
+ ```
139
+
140
+ ### `CorsConfig`
141
+
142
+ Fine-grained CORS settings. When `cors` in `ServerConfig` is set to `true`, sensible defaults are used.
143
+
144
+ ```ts
145
+ interface CorsConfig {
146
+ origin?: string | string[]
147
+ methods?: string[]
148
+ headers?: string[]
149
+ credentials?: boolean
150
+ }
151
+ ```
152
+
153
+ ### `AuthConfig`
154
+
155
+ Bearer-token authentication configuration. The middleware uses timing-safe comparison to validate tokens.
156
+
157
+ ```ts
158
+ interface AuthConfig {
159
+ type: 'bearer'
160
+ token: string
161
+ }
162
+ ```
163
+
164
+ ### `RateLimitConfig`
165
+
166
+ Per-client sliding-window rate limiting configuration.
167
+
168
+ ```ts
169
+ interface RateLimitConfig {
170
+ windowMs: number
171
+ maxRequests: number
172
+ }
173
+ ```
174
+
175
+ ### `ChatRequest`
176
+
177
+ Request body for the `POST /chat` endpoint.
178
+
179
+ ```ts
180
+ interface ChatRequest {
181
+ message: string
182
+ agent?: string
183
+ stream?: boolean
184
+ }
185
+ ```
186
+
187
+ ### `ChatResponse`
188
+
189
+ Response body from the `POST /chat` endpoint.
190
+
191
+ ```ts
192
+ interface ChatResponse {
193
+ message: string
194
+ usage: {
195
+ inputTokens: number
196
+ outputTokens: number
197
+ totalTokens: number
198
+ cost: number
199
+ }
200
+ model: string
201
+ traceId: string
202
+ }
203
+ ```
204
+
205
+ ### `CompleteRequest`
206
+
207
+ Request body for the `POST /complete` endpoint.
208
+
209
+ ```ts
210
+ interface CompleteRequest {
211
+ messages: Array<{ role: string; content: string }>
212
+ model?: string
213
+ system?: string
214
+ maxTokens?: number
215
+ temperature?: number
216
+ stream?: boolean
217
+ }
218
+ ```
219
+
220
+ ### `HealthResponse`
221
+
222
+ Response body from the `GET /health` endpoint.
223
+
224
+ ```ts
225
+ interface HealthResponse {
226
+ status: 'ok' | 'degraded'
227
+ version: string
228
+ uptime: number
229
+ providers: string[]
230
+ }
231
+ ```
232
+
233
+ ### `MetricsResponse`
234
+
235
+ Response body from the `GET /metrics` endpoint.
236
+
237
+ ```ts
238
+ interface MetricsResponse {
239
+ uptime: number
240
+ totalRequests: number
241
+ totalTokens: number
242
+ totalCost: number
243
+ byModel: Record<string, { requests: number; tokens: number; cost: number }>
244
+ }
245
+ ```
246
+
247
+ ---
248
+
249
+ ## Middleware
250
+
251
+ 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.
252
+
253
+ ### `corsMiddleware`
254
+
255
+ Returns a Hono middleware that sets CORS headers and handles preflight `OPTIONS` requests.
256
+
257
+ ```ts
258
+ function corsMiddleware(config?: CorsConfig | boolean): (c: Context, next: Next) => Promise<Response | void>
259
+ ```
260
+
261
+ | Parameter | Type | Default | Description |
262
+ | --- | --- | --- | --- |
263
+ | `config` | `CorsConfig \| boolean` | `true` | When `true`, uses default methods `['GET', 'POST', 'OPTIONS']` and an empty origin list. Pass a `CorsConfig` object for fine-grained control. |
264
+
265
+ ```ts
266
+ import { corsMiddleware } from '@elsium-ai/app'
267
+ import { Hono } from 'hono'
268
+
269
+ const app = new Hono()
270
+
271
+ app.use('*', corsMiddleware({
272
+ origin: ['https://myapp.com'],
273
+ methods: ['GET', 'POST'],
274
+ credentials: true,
275
+ }))
276
+ ```
277
+
278
+ ### `authMiddleware`
279
+
280
+ Returns a Hono middleware that validates `Authorization: Bearer <token>` headers using timing-safe comparison. The `/health` endpoint is always excluded from auth checks.
281
+
282
+ ```ts
283
+ function authMiddleware(config: AuthConfig): (c: Context, next: Next) => Promise<Response | void>
284
+ ```
285
+
286
+ | Parameter | Type | Description |
287
+ | --- | --- | --- |
288
+ | `config` | `AuthConfig` | Must specify `type: 'bearer'` and the expected `token` string. |
289
+
290
+ **Responses on failure:**
291
+ - `401` with `{ error: 'Missing Authorization header' }` when the header is absent.
292
+ - `401` with `{ error: 'Invalid token' }` when the token does not match.
293
+
294
+ ```ts
295
+ import { authMiddleware } from '@elsium-ai/app'
296
+ import { Hono } from 'hono'
297
+
298
+ const app = new Hono()
299
+
300
+ app.use('*', authMiddleware({
301
+ type: 'bearer',
302
+ token: process.env.API_TOKEN!,
303
+ }))
304
+ ```
305
+
306
+ ### `rateLimitMiddleware`
307
+
308
+ 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.
309
+
310
+ ```ts
311
+ function rateLimitMiddleware(config: RateLimitConfig): (c: Context, next: Next) => Promise<Response | void>
312
+ ```
313
+
314
+ | Parameter | Type | Description |
315
+ | --- | --- | --- |
316
+ | `config` | `RateLimitConfig` | `windowMs` is the time window in milliseconds; `maxRequests` is the maximum number of requests allowed per window. |
317
+
318
+ **Responses on failure:**
319
+ - `429` with `{ error: 'Too many requests', retryAfterMs: number }` when the limit is exceeded.
320
+
321
+ ```ts
322
+ import { rateLimitMiddleware } from '@elsium-ai/app'
323
+ import { Hono } from 'hono'
324
+
325
+ const app = new Hono()
326
+
327
+ app.use('*', rateLimitMiddleware({
328
+ windowMs: 60_000,
329
+ maxRequests: 100,
330
+ }))
331
+ ```
332
+
333
+ ---
334
+
335
+ ## Routes
336
+
337
+ ### `createRoutes`
338
+
339
+ Creates a Hono sub-application with all built-in API routes: `GET /health`, `GET /metrics`, `POST /chat`, `POST /complete`, and `GET /agents`.
340
+
341
+ ```ts
342
+ function createRoutes(deps: RoutesDeps): Hono
343
+ ```
344
+
345
+ | Parameter | Type | Description |
346
+ | --- | --- | --- |
347
+ | `deps` | `RoutesDeps` | Dependencies injected into route handlers, including the gateway, agent registry, tracer, and server metadata. |
348
+
349
+ **Returns** a `Hono` instance with the following routes:
350
+
351
+ | Method | Path | Description |
352
+ | --- | --- | --- |
353
+ | `GET` | `/health` | Returns a `HealthResponse` with status, version, uptime, and provider list. |
354
+ | `GET` | `/metrics` | Returns a `MetricsResponse` with request counts, token usage, and cost breakdowns. |
355
+ | `POST` | `/chat` | Accepts a `ChatRequest`, dispatches to the specified (or default) agent, and returns a `ChatResponse`. |
356
+ | `POST` | `/complete` | Accepts a `CompleteRequest`, forwards to the gateway, and returns the completion result. |
357
+ | `GET` | `/agents` | Lists all registered agents with their names, models, and tool names. |
358
+
359
+ ```ts
360
+ import { createRoutes } from '@elsium-ai/app'
361
+ import { Hono } from 'hono'
362
+
363
+ const routes = createRoutes({
364
+ gateway: myGateway,
365
+ agents: new Map([['assistant', myAgent]]),
366
+ defaultAgent: myAgent,
367
+ tracer: myTracer,
368
+ startTime: Date.now(),
369
+ version: '1.0.0',
370
+ providers: ['openai'],
371
+ })
372
+
373
+ const app = new Hono()
374
+ app.route('/', routes)
375
+ ```
376
+
377
+ ### `RoutesDeps`
378
+
379
+ Dependency injection interface for `createRoutes`.
380
+
381
+ ```ts
382
+ interface RoutesDeps {
383
+ gateway: Gateway
384
+ agents: Map<string, Agent>
385
+ defaultAgent?: Agent
386
+ tracer?: Tracer
387
+ startTime: number
388
+ version: string
389
+ providers: string[]
390
+ }
391
+ ```
392
+
393
+ | Field | Type | Description |
394
+ | --- | --- | --- |
395
+ | `gateway` | `Gateway` | The LLM gateway used by the `/complete` endpoint. |
396
+ | `agents` | `Map<string, Agent>` | Registry of named agents used by the `/chat` endpoint. |
397
+ | `defaultAgent` | `Agent` (optional) | The agent used when no `agent` field is specified in a chat request. |
398
+ | `tracer` | `Tracer` (optional) | Observability tracer for tracking LLM calls. |
399
+ | `startTime` | `number` | Timestamp (ms) when the server started, used to calculate uptime. |
400
+ | `version` | `string` | Application version string returned by `/health`. |
401
+ | `providers` | `string[]` | List of configured provider names returned by `/health`. |
402
+
403
+ ---
404
+
405
+ ## RBAC
406
+
407
+ ### `createRBAC`
408
+
409
+ 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.
410
+
411
+ ```ts
412
+ function createRBAC(config: RBACConfig): RBAC
413
+ ```
414
+
415
+ | Parameter | Type | Description |
416
+ | --- | --- | --- |
417
+ | `config` | `RBACConfig` | Defines custom roles, a default role, and how the role is extracted from each request. |
418
+
419
+ **Returns** an `RBAC` object with methods for permission checking and middleware creation.
420
+
421
+ **Built-in roles:**
422
+
423
+ | Role | Permissions |
424
+ | --- | --- |
425
+ | `admin` | `model:use:*`, `agent:execute:*`, `tool:call:*`, `config:read`, `config:write`, `audit:read`, `audit:write` |
426
+ | `operator` | `model:use:*`, `agent:execute:*`, `tool:call:*`, `config:read`, `audit:read` |
427
+ | `user` | `model:use`, `agent:execute`, `tool:call` |
428
+ | `viewer` | `config:read`, `audit:read` |
429
+
430
+ ```ts
431
+ import { createRBAC } from '@elsium-ai/app'
26
432
 
27
433
  const rbac = createRBAC({
28
434
  roles: [
29
- { name: 'viewer', permissions: ['model:read:*'] },
30
- { name: 'analyst', permissions: ['model:use:gpt-4o-mini'], inherits: ['viewer'] },
31
- { name: 'admin', permissions: ['*'], inherits: ['analyst'] },
435
+ {
436
+ name: 'analyst',
437
+ permissions: ['model:use:gpt-4o-mini'],
438
+ inherits: ['viewer'],
439
+ },
32
440
  ],
441
+ defaultRole: 'viewer',
33
442
  })
34
443
 
35
- const app = createApp({
36
- port: 3000,
37
- cors: { origins: ['http://localhost:5173'] },
38
- rateLimit: { windowMs: 60_000, max: 100 },
39
- })
444
+ // Check a permission
445
+ rbac.hasPermission('analyst', 'model:use:gpt-4o-mini') // true
446
+ rbac.hasPermission('analyst', 'config:read') // true (inherited from viewer)
447
+
448
+ // Use as Hono middleware
449
+ app.post('/chat', rbac.middleware('model:use'), handler)
450
+ ```
451
+
452
+ ### `Permission`
453
+
454
+ A union type representing all recognized permissions. Supports resource-specific and wildcard variants.
455
+
456
+ ```ts
457
+ type Permission =
458
+ | 'model:use'
459
+ | 'model:use:*'
460
+ | `model:use:${string}`
461
+ | 'agent:execute'
462
+ | 'agent:execute:*'
463
+ | `agent:execute:${string}`
464
+ | 'tool:call'
465
+ | 'tool:call:*'
466
+ | `tool:call:${string}`
467
+ | 'config:read'
468
+ | 'config:write'
469
+ | 'audit:read'
470
+ | 'audit:write'
471
+ ```
472
+
473
+ 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`).
474
+
475
+ ### `Role`
476
+
477
+ Defines a named role with a set of permissions and optional inheritance from other roles.
478
+
479
+ ```ts
480
+ interface Role {
481
+ name: string
482
+ permissions: Permission[]
483
+ inherits?: string[]
484
+ }
485
+ ```
486
+
487
+ ### `RBACConfig`
488
+
489
+ Configuration for `createRBAC`.
490
+
491
+ ```ts
492
+ interface RBACConfig {
493
+ roles: Role[]
494
+ defaultRole?: string
495
+ roleExtractor?: (c: Context) => string | undefined
496
+ trustRoleHeader?: boolean
497
+ }
40
498
  ```
41
499
 
500
+ | Field | Type | Description |
501
+ | --- | --- | --- |
502
+ | `roles` | `Role[]` | Custom role definitions. These override built-in roles with the same name. |
503
+ | `defaultRole` | `string` (optional) | The role assigned when no role can be determined from the request. Defaults to `'viewer'`. |
504
+ | `roleExtractor` | `(c: Context) => string \| undefined` (optional) | Custom function to extract the role name from a Hono request context. |
505
+ | `trustRoleHeader` | `boolean` (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. |
506
+
507
+ ### `RBAC`
508
+
509
+ The object returned by `createRBAC`.
510
+
511
+ ```ts
512
+ interface RBAC {
513
+ hasPermission(role: string, permission: Permission): boolean
514
+ middleware(required: Permission): (c: Context, next: Next) => Promise<Response | undefined>
515
+ getRolePermissions(role: string): Permission[]
516
+ }
517
+ ```
518
+
519
+ | Method | Description |
520
+ | --- | --- |
521
+ | `hasPermission(role, permission)` | Returns `true` if the given role (including inherited permissions) grants the specified permission. |
522
+ | `middleware(required)` | Returns a Hono middleware that rejects requests with `403` if the caller's role lacks the required permission. |
523
+ | `getRolePermissions(role)` | Returns the deduplicated list of all permissions for a role, including those inherited from parent roles. |
524
+
525
+ ---
526
+
42
527
  ## Part of ElsiumAI
43
528
 
44
529
  This package is the app layer of the [ElsiumAI](https://github.com/elsium-ai/elsium-ai) framework. See the [full documentation](https://github.com/elsium-ai/elsium-ai) for guides and examples.
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@elsium-ai/app",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "App bootstrap, HTTP server, and API routes for ElsiumAI",
5
5
  "license": "MIT",
6
6
  "author": "Eric Utrera <ebutrera9103@gmail.com>",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "https://github.com/elsium-ai/elsium-ai",
9
+ "url": "git+https://github.com/elsium-ai/elsium-ai.git",
10
10
  "directory": "packages/app"
11
11
  },
12
12
  "type": "module",
@@ -26,13 +26,13 @@
26
26
  "dev": "bun --watch src/index.ts"
27
27
  },
28
28
  "dependencies": {
29
- "@elsium-ai/core": "^0.2.1",
30
- "@elsium-ai/gateway": "^0.2.1",
31
- "@elsium-ai/agents": "^0.2.1",
32
- "@elsium-ai/tools": "^0.2.1",
33
- "@elsium-ai/observe": "^0.2.1",
34
- "@elsium-ai/rag": "^0.2.1",
35
- "@elsium-ai/workflows": "^0.2.1",
29
+ "@elsium-ai/core": "^0.2.2",
30
+ "@elsium-ai/gateway": "^0.2.2",
31
+ "@elsium-ai/agents": "^0.2.2",
32
+ "@elsium-ai/tools": "^0.2.2",
33
+ "@elsium-ai/observe": "^0.2.2",
34
+ "@elsium-ai/rag": "^0.2.2",
35
+ "@elsium-ai/workflows": "^0.2.2",
36
36
  "@hono/node-server": "^1.13.0",
37
37
  "hono": "^4.7.0",
38
38
  "zod": "^3.24.0"