@cogitator-ai/express 0.9.6 → 0.11.0
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.
- package/README.md +72 -12
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/middleware/auth.d.ts +6 -0
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +17 -6
- package/dist/middleware/auth.js.map +1 -1
- package/dist/middleware/error-handler.d.ts.map +1 -1
- package/dist/middleware/error-handler.js +16 -36
- package/dist/middleware/error-handler.js.map +1 -1
- package/dist/middleware/index.d.ts +1 -1
- package/dist/middleware/index.d.ts.map +1 -1
- package/dist/middleware/index.js +1 -1
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/json-body.d.ts.map +1 -1
- package/dist/middleware/json-body.js +2 -1
- package/dist/middleware/json-body.js.map +1 -1
- package/dist/middleware/rate-limit.d.ts.map +1 -1
- package/dist/middleware/rate-limit.js +6 -6
- package/dist/middleware/rate-limit.js.map +1 -1
- package/dist/routes/agents.d.ts.map +1 -1
- package/dist/routes/agents.js +69 -31
- package/dist/routes/agents.js.map +1 -1
- package/dist/routes/swarms.d.ts.map +1 -1
- package/dist/routes/swarms.js +8 -4
- package/dist/routes/swarms.js.map +1 -1
- package/dist/routes/threads.d.ts.map +1 -1
- package/dist/routes/threads.js +15 -18
- package/dist/routes/threads.js.map +1 -1
- package/dist/routes/utils.d.ts +26 -8
- package/dist/routes/utils.d.ts.map +1 -1
- package/dist/routes/utils.js +52 -12
- package/dist/routes/utils.js.map +1 -1
- package/dist/routes/workflows.d.ts.map +1 -1
- package/dist/routes/workflows.js +6 -5
- package/dist/routes/workflows.js.map +1 -1
- package/dist/server.d.ts +2 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +11 -6
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +48 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/websocket/ws-handler.d.ts +2 -2
- package/dist/websocket/ws-handler.d.ts.map +1 -1
- package/dist/websocket/ws-handler.js +123 -28
- package/dist/websocket/ws-handler.js.map +1 -1
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -52,10 +52,11 @@ app.listen(3000, () => console.log('Server running on http://localhost:3000'));
|
|
|
52
52
|
### Agents
|
|
53
53
|
|
|
54
54
|
```
|
|
55
|
-
GET /api/agents
|
|
56
|
-
POST /api/agents/:name/run
|
|
57
|
-
POST /api/agents/:name/stream
|
|
58
|
-
POST /api/agents/:name/resume
|
|
55
|
+
GET /api/agents - List all agents
|
|
56
|
+
POST /api/agents/:name/run - Run agent (JSON response)
|
|
57
|
+
POST /api/agents/:name/stream - Run agent (SSE stream)
|
|
58
|
+
POST /api/agents/:name/resume - Resume a run paused for tool approvals
|
|
59
|
+
POST /api/agents/:name/resume/stream - Resume a paused run (SSE stream)
|
|
59
60
|
```
|
|
60
61
|
|
|
61
62
|
Run/stream body: `{ input: string; context?: object; threadId?: string }`. `input` must contain more than whitespace and `threadId`, when sent, must be a non-empty string (`400 INVALID_INPUT` otherwise, before the model is called). The validator comes from `@cogitator-ai/server-shared`, so Express, Fastify, Hono and Koa refuse exactly the same bodies. The `usage` of a run answer carries `inputTokens`, `outputTokens` and `totalTokens`, plus `reasoningTokens`, `cachedInputTokens` and `cacheWriteTokens` when the model reported them, the same shape as every other adapter. The `finish` event of an agent stream carries the same `usage` (never the run's cost or duration). The agent list exposes `config.description`, never the agent instructions. The authenticated `userId` (from `auth`) is passed to the run, and the run is aborted when the client disconnects.
|
|
@@ -69,13 +70,25 @@ Run/stream body: `{ input: string; context?: object; threadId?: string }`. `inpu
|
|
|
69
70
|
### Threads (Memory)
|
|
70
71
|
|
|
71
72
|
```
|
|
72
|
-
GET /api/threads/:id - Get thread messages
|
|
73
|
+
GET /api/threads/:id - Get thread messages, a page at a time with ?limit&cursor
|
|
73
74
|
POST /api/threads/:id/messages - Add message to thread
|
|
74
75
|
DELETE /api/threads/:id - Delete thread
|
|
75
76
|
```
|
|
76
77
|
|
|
77
78
|
The routes use `cogitator.getMemory()`, which connects the configured memory adapter on first use, so threads can be read on a fresh server before any agent has run. Only a `Cogitator` without `memory` configured answers `503 UNAVAILABLE`. New messages need `role` (`user` or `assistant`, more with `threadMessageRoles`) and a non-empty string `content`, optional `metadata` is stored on the memory entry.
|
|
78
79
|
|
|
80
|
+
`GET /threads/:id` answers the whole thread by default. With `?limit=50` it answers the newest 50 messages (oldest first within the page) and a `nextCursor`, and `?limit=50&cursor=<nextCursor>` the 50 before them, until an answer has no `nextCursor`. Messages written in the same millisecond are never skipped or repeated across pages. A `limit` outside 1 to 1000 or a cursor the server never gave is refused with `400 INVALID_INPUT`.
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
let cursor: string | undefined;
|
|
84
|
+
do {
|
|
85
|
+
const query = new URLSearchParams({ limit: '50', ...(cursor && { cursor }) });
|
|
86
|
+
const page = await (await fetch(`/api/threads/${threadId}?${query}`)).json();
|
|
87
|
+
render(page.messages);
|
|
88
|
+
cursor = page.nextCursor;
|
|
89
|
+
} while (cursor);
|
|
90
|
+
```
|
|
91
|
+
|
|
79
92
|
### Workflows
|
|
80
93
|
|
|
81
94
|
```
|
|
@@ -84,7 +97,7 @@ POST /api/workflows/:name/run - Run workflow
|
|
|
84
97
|
POST /api/workflows/:name/stream - Stream workflow events
|
|
85
98
|
```
|
|
86
99
|
|
|
87
|
-
Body: `{ input?: object; options?: { maxConcurrency?: number; maxIterations?: number } }`. `maxConcurrency`/`maxIterations` must be positive integers (400 otherwise). Other options are dropped, and `checkpoint: true` is refused, since the server keeps no checkpoint store to resume from. A failed workflow
|
|
100
|
+
Body: `{ input?: object; options?: { maxConcurrency?: number; maxIterations?: number } }`. `maxConcurrency`/`maxIterations` must be positive integers (400 otherwise). With `limits.workflowMaxIterations` or `limits.workflowMaxConcurrency` set, a larger value is held to the limit, and a request that asks for nothing gets the limit. Other options are dropped, and `checkpoint: true` is refused, since the server keeps no checkpoint store to resume from. A failed workflow answers the error it failed with, mapped like any other run error (a node that hit `LLM_RATE_LIMITED` answers `429` with `Retry-After`, an internal error `500 INTERNAL_ERROR`), and its stream ends with an `error` event carrying that code instead of `workflow_completed`. Disconnecting aborts the workflow.
|
|
88
101
|
|
|
89
102
|
The stream sends `{ type: 'workflow', event, data }` events: `node_started`, `node_completed`, `node_error`, `node_progress` and finally `workflow_completed`.
|
|
90
103
|
|
|
@@ -97,7 +110,7 @@ POST /api/swarms/:name/stream - Stream swarm events
|
|
|
97
110
|
GET /api/swarms/:name/blackboard - Get configured blackboard sections
|
|
98
111
|
```
|
|
99
112
|
|
|
100
|
-
Run/stream body: `{ input: string; context?: object; threadId?: string; timeout?: number }` (`timeout` must be positive, at most `2147483647` ms). Disconnecting aborts the swarm. The stream sends `{ type: 'swarm', event, data }` events (`agent_start`, `agent_complete`, `agent_error`, `message`, the swarm's own events, and finally `swarm_completed` with the output and usage). Each run creates a fresh swarm, so the blackboard endpoint returns the configured initial sections.
|
|
113
|
+
Run/stream body: `{ input: string; context?: object; threadId?: string; timeout?: number }` (`timeout` must be positive, at most `2147483647` ms). With `limits.swarmTimeout` set, a longer timeout is held to it and a run without one gets it, and a swarm that runs out of time answers `504 RUN_TIMEOUT`. Disconnecting aborts the swarm. The stream sends `{ type: 'swarm', event, data }` events (`agent_start`, `agent_complete`, `agent_error`, `message`, the swarm's own events, and finally `swarm_completed` with the output and usage). Each run creates a fresh swarm, so the blackboard endpoint returns the configured initial sections.
|
|
101
114
|
|
|
102
115
|
### Tools & Docs
|
|
103
116
|
|
|
@@ -155,6 +168,24 @@ const server = new CogitatorServer({
|
|
|
155
168
|
description: 'AI-powered API endpoints',
|
|
156
169
|
version: '1.0.0',
|
|
157
170
|
},
|
|
171
|
+
|
|
172
|
+
// Caps on what a request may ask a run for. A larger value is held to the cap,
|
|
173
|
+
// a request without one gets the cap. Checked when the server is created.
|
|
174
|
+
limits: { swarmTimeout: 120_000, workflowMaxIterations: 50, workflowMaxConcurrency: 4 },
|
|
175
|
+
|
|
176
|
+
// 'deny' answers 401 to callers without a userId. Health, ready and the docs stay open.
|
|
177
|
+
anonymous: 'deny',
|
|
178
|
+
|
|
179
|
+
// Called with the auth context and the thread of every request that names one.
|
|
180
|
+
// false answers 403 THREAD_FORBIDDEN and no run starts.
|
|
181
|
+
authorizeThread: (auth, threadId) => threadId.startsWith(`${auth?.userId}:`),
|
|
182
|
+
|
|
183
|
+
// Dependencies for the tools of HTTP agent runs, streams and resumes (context.deps).
|
|
184
|
+
// Built from the request on the server, never read from the body.
|
|
185
|
+
deps: async (req) => ({ db: await tenantDb(req.get('x-tenant')) }),
|
|
186
|
+
|
|
187
|
+
// WebSocket runs build theirs from the upgrade request, a plain Node IncomingMessage.
|
|
188
|
+
websocket: { deps: async (req) => ({ db: await tenantDb(req.headers['x-tenant']) }) },
|
|
158
189
|
},
|
|
159
190
|
});
|
|
160
191
|
```
|
|
@@ -167,6 +198,16 @@ When `auth` returns a `userId`, everything a caller does with threads is scoped
|
|
|
167
198
|
- `GET /threads/:id`, `POST /threads/:id/messages` and `DELETE /threads/:id` check the thread's owner first; `POST` to an unknown id creates the thread owned by the caller.
|
|
168
199
|
- Another user's thread answers `403` with code `THREAD_ACCESS_DENIED`, and its messages are neither returned nor changed.
|
|
169
200
|
- Threads created earlier without an owner (no `userId`) stay open only to callers without a `userId`, such as servers with no `auth` configured.
|
|
201
|
+
- `authorizeThread(auth, threadId)` adds your own rule on top of ownership, for shared or team threads. It runs on every route that names a thread (agent run, stream and resume, swarm run and stream, `GET`, `DELETE` and `POST /threads/:id/messages`) and on WebSocket runs with a `threadId`, after the body is validated and before core checks the owner. Answering `false` refuses with `403 THREAD_FORBIDDEN`, and no run starts.
|
|
202
|
+
- `anonymous: 'deny'` refuses every caller whose `auth` gave no `userId` with `401 UNAUTHORIZED`, WebSocket upgrades included. `/health`, `/ready`, `/openapi.json` and `/docs` stay open. An unknown path under the base path answers `401` too, so an anonymous caller cannot probe which routes exist, and `404 NOT_FOUND` once the caller has a `userId`. The default, `'allow'`, lets anonymous callers in as before, and an unknown path answers `404 NOT_FOUND` in the error envelope.
|
|
203
|
+
|
|
204
|
+
### Limits and deps
|
|
205
|
+
|
|
206
|
+
`limits` caps what a client may ask a run for: `swarmTimeout` (ms), `workflowMaxIterations` and `workflowMaxConcurrency`. A request is never refused over a limit: it gets the smaller of what it asked for and the limit, or the limit when it asked for nothing, over HTTP and SSE alike. The OpenAPI spec shows each limit as the default of its field. Each limit must be a positive integer, or the constructor throws.
|
|
207
|
+
|
|
208
|
+
`deps: (req) => deps` builds the dependencies agent tools read as `context.deps` (a database handle, a tenant, a client), and the HTTP run, stream or resume gets them as `deps`. They are built on the server for each request and never come from the body. An error the hook throws is answered like a run error, before a stream starts.
|
|
209
|
+
|
|
210
|
+
WebSocket runs and resumes take theirs from `websocket.deps: (req) => deps`, called for each run with the upgrade request. That request is a plain Node `IncomingMessage` that never went through Express, so it has `headers`, `url` and `socket` but no `req.get()` and nothing a middleware adds, which is why it gets a hook of its own. Without `websocket.deps` WebSocket runs get no deps. An error it throws (or one `authorizeThread` throws) answers `{ type: 'error', id, error }` and starts no run.
|
|
170
211
|
|
|
171
212
|
### Approvals
|
|
172
213
|
|
|
@@ -190,6 +231,8 @@ await fetch('/api/agents/support/resume', {
|
|
|
190
231
|
|
|
191
232
|
The body is `{ threadId, decisions?, defaultDecision? }`, where a decision is `{ approved: boolean, reason?: string }`; malformed bodies get `400 INVALID_INPUT`. The response has the same shape as `/run` and may pause again for calls left without a decision. The run resumes as the authenticated `userId`: a thread with no paused run answers `409 RUN_NOT_PAUSED`, and another user's paused run `403 THREAD_ACCESS_DENIED`. Over WebSocket, send `{ type: 'resume', id, payload: { name, threadId, decisions?, defaultDecision? } }`; a paused run's `complete` event carries `status` and `pendingApprovals`.
|
|
192
233
|
|
|
234
|
+
`POST /agents/:name/resume/stream` takes the same body and streams the rest of the run like `/stream`. `start` and `finish` name the resumed thread, and a body, agent or thread refused before the stream opens is answered as JSON, just like `/resume`. A thread with no paused run ends the open stream with an `error` event, `code: 'RUN_NOT_PAUSED'`, and disconnecting aborts the resume.
|
|
235
|
+
|
|
193
236
|
## SSE Streaming
|
|
194
237
|
|
|
195
238
|
The `/agents/:name/stream` endpoint returns Server-Sent Events:
|
|
@@ -248,7 +291,7 @@ await server.attachWebSocket(httpServer); // defaults to `${basePath}/ws`
|
|
|
248
291
|
httpServer.listen(3000);
|
|
249
292
|
```
|
|
250
293
|
|
|
251
|
-
`attachWebSocket` throws if `enableWebSocket` is off, `init()` has not run, or `ws` is not installed. The configured `auth` function runs on the upgrade request (rejected with 401 when it throws). For custom setups, `setupWebSocket(httpServer, routeContext, config)` is also exported.
|
|
294
|
+
`attachWebSocket` throws if `enableWebSocket` is off, `init()` has not run, or `ws` is not installed. The configured `auth` function runs on the upgrade request (rejected with 401 when it throws, or when it gives no `userId` under `anonymous: 'deny'`). A `run` or `resume` on a thread `authorizeThread` refuses answers `{ type: 'error', id, error }` without starting, and `websocket.deps` is called with the upgrade request. For custom setups, `setupWebSocket(httpServer, routeContext, config)` is also exported.
|
|
252
295
|
|
|
253
296
|
Protocol:
|
|
254
297
|
|
|
@@ -257,13 +300,15 @@ Protocol:
|
|
|
257
300
|
| `{ type: 'run', id, payload: { type: 'agent', name, input, context?, threadId? } }` | Client→Server | Run an agent; events arrive as `{ type: 'event', id, payload }` (`token`, `reasoning`, `tool-call`, `tool-result`, `complete`, `cancelled`) |
|
|
258
301
|
| `{ type: 'resume', id, payload: { name, threadId, decisions?, defaultDecision? } }` | Client→Server | Resume a run paused for tool approvals; events arrive like those of `run` |
|
|
259
302
|
| `{ type: 'stop' }` | Client→Server | Abort the client's running agent (emits `cancelled`) |
|
|
260
|
-
| `{ type: 'subscribe', channel: 'agent:<name>' }` | Client→Server | Receive events of runs of that agent started by the same user elsewhere
|
|
303
|
+
| `{ type: 'subscribe', channel: 'agent:<name>' }` | Client→Server | Receive events of runs of that agent started by the same user elsewhere, on threads `authorizeThread` allows |
|
|
261
304
|
| `{ type: 'unsubscribe', channel }` | Client→Server | Stop receiving channel events |
|
|
262
305
|
| `{ type: 'ping' }` | Client→Server | Answered with `{ type: 'pong' }` |
|
|
263
306
|
| `{ type: 'subscribed' \| 'unsubscribed', id, channel }` | Server→Client | Subscription confirmed (at most 64 channels per connection) |
|
|
264
307
|
| `{ type: 'error', id?, error }` | Server→Client | Invalid message or payload, unknown agent, or a failed run |
|
|
265
308
|
|
|
266
|
-
Only agent runs are supported over WebSocket
|
|
309
|
+
Only agent runs are supported over WebSocket, use the HTTP endpoints for workflows and swarms. A new `run` from the same connection aborts the previous one. A failed run reports a `CogitatorError`'s message, any other error is logged and sent as `Internal server error`. The server pings every `pingInterval` ms and terminates clients that miss a pong.
|
|
310
|
+
|
|
311
|
+
A subscriber gets the events of a run only when it has the `userId` of the caller who started it and, with `authorizeThread` set, when `authorizeThread(subscriberAuth, threadId)` allows it on the run's thread (the `threadId` of the run, or the one core created for it). The answer is asked once per subscriber and run, and a subscriber it refuses, or throws for, gets none of the run's events. Without `authorizeThread`, callers without a `userId` share the events of each other's runs, so set `authorizeThread` or `anonymous: 'deny'` when anonymous callers must not see each other.
|
|
267
312
|
|
|
268
313
|
Client usage:
|
|
269
314
|
|
|
@@ -386,8 +431,22 @@ interface CogitatorServerConfig {
|
|
|
386
431
|
sseHeartbeatMs?: number; // Default: 5000, 0 turns SSE heartbeats off
|
|
387
432
|
acceptContext?: boolean | string[]; // context keys clients may send: none by default, a list, or true for any
|
|
388
433
|
threadMessageRoles?: ('user' | 'assistant' | 'system')[]; // roles of POST /threads/:id/messages, default user and assistant
|
|
434
|
+
limits?: RunLimits; // { swarmTimeout?, workflowMaxIterations?, workflowMaxConcurrency? }
|
|
435
|
+
anonymous?: 'allow' | 'deny'; // Default: 'allow'
|
|
436
|
+
authorizeThread?: (
|
|
437
|
+
auth: AuthContext | undefined,
|
|
438
|
+
threadId: string
|
|
439
|
+
) => boolean | Promise<boolean>;
|
|
440
|
+
deps?: (req: Request) => unknown | Promise<unknown>; // HTTP runs, WebSocket runs use websocket.deps
|
|
389
441
|
};
|
|
390
442
|
}
|
|
443
|
+
|
|
444
|
+
interface WebSocketConfig {
|
|
445
|
+
path?: string; // Default: `${basePath}/ws`
|
|
446
|
+
pingInterval?: number; // Default: 30000
|
|
447
|
+
maxPayloadSize?: number; // Default: 1 MiB
|
|
448
|
+
deps?: (req: IncomingMessage) => unknown | Promise<unknown>; // deps of WebSocket runs, from the upgrade request
|
|
449
|
+
}
|
|
391
450
|
```
|
|
392
451
|
|
|
393
452
|
`CogitatorServer` writes nothing to the console when it starts. `init()` and the WebSocket setup report through the core logger at `debug` level (`getLogger()` from `@cogitator-ai/core`, `LOG_LEVEL=debug` to see them, or `setLogger()` to route them into your own logger). Errors are still logged.
|
|
@@ -438,16 +497,17 @@ Error codes map to HTTP status codes:
|
|
|
438
497
|
- `INVALID_INPUT` → 400 (validation errors and malformed JSON bodies)
|
|
439
498
|
- `UNAUTHORIZED` → 401
|
|
440
499
|
- `THREAD_ACCESS_DENIED` → 403 (another user's thread)
|
|
500
|
+
- `THREAD_FORBIDDEN` → 403 (`authorizeThread` refused the thread)
|
|
441
501
|
- `NOT_FOUND` → 404
|
|
442
502
|
- `RUN_NOT_PAUSED` → 409 (resume of a thread without a paused run)
|
|
443
503
|
- `PAYLOAD_TOO_LARGE` → 413
|
|
444
504
|
- `RATE_LIMIT_EXCEEDED` → 429
|
|
445
|
-
- `WORKFLOW_FAILED` → 500
|
|
446
505
|
- `INTERNAL_ERROR` → 500
|
|
447
506
|
- `UNIMPLEMENTED` → 501 (optional workflows/swarms package missing)
|
|
448
507
|
- `UNAVAILABLE` → 503 (no memory configured)
|
|
508
|
+
- `RUN_TIMEOUT` → 504 (a swarm ran out of time)
|
|
449
509
|
|
|
450
|
-
A `CogitatorError` keeps its message and code and
|
|
510
|
+
A `CogitatorError` keeps its message and code and answers with its own `statusCode`, which is the code's mapped status unless the error was given another (for example `LLM_RATE_LIMITED` → 429). When it says when to retry (`retryAfter`, as provider rate limits do), the answer carries `Retry-After` in whole seconds. The mapping is `describeHttpError` of `@cogitator-ai/server-shared`, so Express, Fastify, Hono, Koa and Next answer the same error the same way. Any other error is logged on the server and answered as `500 Internal server error`, so connection strings, file paths and other internals never reach the client. The same mapping applies to a failed workflow, and the same masking to SSE `error` events, the `node_error`/`agent_error` stream events and WebSocket run errors.
|
|
451
511
|
|
|
452
512
|
## Documentation
|
|
453
513
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { CogitatorServer } from './server.js';
|
|
2
|
-
export type { AuthContext, AuthFunction, CogitatorRequest, CogitatorServerConfig, RateLimitConfig, CorsConfig, SwaggerConfig, WebSocketConfig, RouteContext, AgentListResponse, AgentRunRequest, AgentRunResponse, AgentResumeRequest, PendingApproval, ThreadResponse, AddMessageRequest, ToolListResponse, WorkflowListResponse, WorkflowRunRequest, WorkflowRunResponse, WorkflowStatusResponse, SwarmListResponse, SwarmRunRequest, SwarmRunResponse, BlackboardResponse, HealthResponse, ReadinessResponse, ReadinessCheckStatus, ErrorResponse, WebSocketMessage, WebSocketResponse, OpenAPISpec, ExpressMiddleware, } from './types.js';
|
|
3
|
-
export { createAuthMiddleware, createRateLimitMiddleware, createCorsMiddleware, errorHandler, notFoundHandler, } from './middleware/index.js';
|
|
2
|
+
export type { AuthContext, AuthFunction, DepsFunction, WebSocketDepsFunction, CogitatorRequest, CogitatorServerConfig, RateLimitConfig, CorsConfig, SwaggerConfig, WebSocketConfig, RouteContext, ResolvedServerConfig, AgentListResponse, AgentRunRequest, AgentRunResponse, AgentResumeRequest, PendingApproval, ThreadResponse, AddMessageRequest, ToolListResponse, WorkflowListResponse, WorkflowRunRequest, WorkflowRunResponse, WorkflowStatusResponse, SwarmListResponse, SwarmRunRequest, SwarmRunResponse, BlackboardResponse, HealthResponse, ReadinessResponse, ReadinessCheckStatus, ErrorResponse, WebSocketMessage, WebSocketResponse, OpenAPISpec, ExpressMiddleware, } from './types.js';
|
|
3
|
+
export { createAuthMiddleware, createAnonymousGuard, createRateLimitMiddleware, createCorsMiddleware, errorHandler, notFoundHandler, } from './middleware/index.js';
|
|
4
4
|
export { createHealthRoutes, createAgentRoutes, createThreadRoutes, createToolRoutes, createWorkflowRoutes, createSwarmRoutes, } from './routes/index.js';
|
|
5
5
|
export { ExpressStreamWriter, setupSSEHeaders, generateId, encodeSSE, encodeDone, } from './streaming/index.js';
|
|
6
6
|
export type { ExpressStreamWriterOptions } from './streaming/index.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,YAAY,EACV,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,qBAAqB,EACrB,eAAe,EACf,UAAU,EACV,aAAa,EACb,eAAe,EACf,YAAY,EACZ,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,oBAAoB,EACpB,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,EACX,iBAAiB,GAClB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,oBAAoB,EACpB,yBAAyB,EACzB,oBAAoB,EACpB,YAAY,EACZ,eAAe,GAChB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,UAAU,EACV,SAAS,EACT,UAAU,GACX,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAEvE,YAAY,EACV,WAAW,EACX,UAAU,EACV,cAAc,EACd,cAAc,EACd,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,UAAU,EACV,WAAW,EACX,KAAK,GACN,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,YAAY,EACV,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,qBAAqB,EACrB,gBAAgB,EAChB,qBAAqB,EACrB,eAAe,EACf,UAAU,EACV,aAAa,EACb,eAAe,EACf,YAAY,EACZ,oBAAoB,EACpB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,oBAAoB,EACpB,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,EACX,iBAAiB,GAClB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,yBAAyB,EACzB,oBAAoB,EACpB,YAAY,EACZ,eAAe,GAChB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,UAAU,EACV,SAAS,EACT,UAAU,GACX,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAEvE,YAAY,EACV,WAAW,EACX,UAAU,EACV,cAAc,EACd,cAAc,EACd,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,UAAU,EACV,WAAW,EACX,KAAK,GACN,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { CogitatorServer } from './server.js';
|
|
2
|
-
export { createAuthMiddleware, createRateLimitMiddleware, createCorsMiddleware, errorHandler, notFoundHandler, } from './middleware/index.js';
|
|
2
|
+
export { createAuthMiddleware, createAnonymousGuard, createRateLimitMiddleware, createCorsMiddleware, errorHandler, notFoundHandler, } from './middleware/index.js';
|
|
3
3
|
export { createHealthRoutes, createAgentRoutes, createThreadRoutes, createToolRoutes, createWorkflowRoutes, createSwarmRoutes, } from './routes/index.js';
|
|
4
4
|
export { ExpressStreamWriter, setupSSEHeaders, generateId, encodeSSE, encodeDone, } from './streaming/index.js';
|
|
5
5
|
export { generateOpenAPISpec, serveSwaggerUI } from './swagger/index.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAyC9C,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,yBAAyB,EACzB,oBAAoB,EACpB,YAAY,EACZ,eAAe,GAChB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,UAAU,EACV,SAAS,EACT,UAAU,GACX,MAAM,sBAAsB,CAAC;AAsB9B,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import type { Response, NextFunction } from 'express';
|
|
2
|
+
import { type AnonymousPolicy } from '@cogitator-ai/server-shared';
|
|
2
3
|
import type { CogitatorRequest, AuthFunction } from '../types.js';
|
|
3
4
|
export declare function createAuthMiddleware(authFn?: AuthFunction): (req: CogitatorRequest, res: Response, next: NextFunction) => Promise<void>;
|
|
5
|
+
/**
|
|
6
|
+
* Answers `401 UNAUTHORIZED` to a caller without a user id when `anonymous` is `'deny'`.
|
|
7
|
+
* Mounted after the public routes (health, ready, docs), so only the API is closed.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createAnonymousGuard(anonymous: AnonymousPolicy | undefined): (req: CogitatorRequest, res: Response, next: NextFunction) => void;
|
|
4
10
|
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAe,KAAK,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAChF,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIlE,wBAAgB,oBAAoB,CAAC,MAAM,CAAC,EAAE,YAAY,IAC1C,KAAK,gBAAgB,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,mBAkBvE;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,eAAe,GAAG,SAAS,IACjE,KAAK,gBAAgB,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,UAQjE"}
|
package/dist/middleware/auth.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { admitCaller } from '@cogitator-ai/server-shared';
|
|
1
2
|
import { generateId } from '../streaming/helpers.js';
|
|
3
|
+
import { sendError, sendFailure } from '../routes/utils.js';
|
|
2
4
|
export function createAuthMiddleware(authFn) {
|
|
3
5
|
return async (req, res, next) => {
|
|
4
6
|
req.cogitator = {
|
|
@@ -14,13 +16,22 @@ export function createAuthMiddleware(authFn) {
|
|
|
14
16
|
next();
|
|
15
17
|
}
|
|
16
18
|
catch {
|
|
17
|
-
res
|
|
18
|
-
error: {
|
|
19
|
-
message: 'Unauthorized',
|
|
20
|
-
code: 'UNAUTHORIZED',
|
|
21
|
-
},
|
|
22
|
-
});
|
|
19
|
+
sendError(res, 401, 'Unauthorized', 'UNAUTHORIZED');
|
|
23
20
|
}
|
|
24
21
|
};
|
|
25
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Answers `401 UNAUTHORIZED` to a caller without a user id when `anonymous` is `'deny'`.
|
|
25
|
+
* Mounted after the public routes (health, ready, docs), so only the API is closed.
|
|
26
|
+
*/
|
|
27
|
+
export function createAnonymousGuard(anonymous) {
|
|
28
|
+
return (req, res, next) => {
|
|
29
|
+
const refusal = admitCaller(req.cogitator?.auth?.userId, anonymous);
|
|
30
|
+
if (!refusal) {
|
|
31
|
+
next();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
sendFailure(res, refusal);
|
|
35
|
+
};
|
|
36
|
+
}
|
|
26
37
|
//# sourceMappingURL=auth.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAwB,MAAM,6BAA6B,CAAC;AAEhF,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAE5D,MAAM,UAAU,oBAAoB,CAAC,MAAqB;IACxD,OAAO,KAAK,EAAE,GAAqB,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;QACxE,GAAG,CAAC,SAAS,GAAG;YACd,SAAS,EAAE,UAAU,CAAC,KAAK,CAAC;YAC5B,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC;QAEF,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,IAAI,EAAE,CAAC;QAChB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,CAAC;YAC/B,GAAG,CAAC,SAAS,CAAC,IAAI,GAAG,IAAI,CAAC;YAC1B,IAAI,EAAE,CAAC;QACT,CAAC;QAAC,MAAM,CAAC;YACP,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,cAAc,EAAE,cAAc,CAAC,CAAC;QACtD,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,SAAsC;IACzE,OAAO,CAAC,GAAqB,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;QAClE,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;QACpE,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,IAAI,EAAE,CAAC;YACP,OAAO;QACT,CAAC;QACD,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC5B,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../src/middleware/error-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../src/middleware/error-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAqC/D,wBAAgB,YAAY,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI,CAahG;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,IAAI,CAElE"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { INTERNAL_ERROR, describeHttpError, } from '@cogitator-ai/server-shared';
|
|
2
|
+
import { sendError, sendFailure } from '../routes/utils.js';
|
|
2
3
|
const CLIENT_ERROR_CODES = {
|
|
3
4
|
400: 'INVALID_INPUT',
|
|
4
5
|
401: 'UNAUTHORIZED',
|
|
@@ -8,59 +9,38 @@ const CLIENT_ERROR_CODES = {
|
|
|
8
9
|
415: 'UNSUPPORTED_MEDIA_TYPE',
|
|
9
10
|
429: 'RATE_LIMIT_EXCEEDED',
|
|
10
11
|
};
|
|
12
|
+
/** A 4xx error of Express or its body parser, told to the client as it is */
|
|
11
13
|
function asClientError(err) {
|
|
12
14
|
if (typeof err !== 'object' || err === null)
|
|
13
|
-
return
|
|
15
|
+
return undefined;
|
|
14
16
|
const rawStatus = Reflect.get(err, 'status') ?? Reflect.get(err, 'statusCode');
|
|
15
17
|
if (typeof rawStatus !== 'number' || rawStatus < 400 || rawStatus >= 500)
|
|
16
|
-
return
|
|
18
|
+
return undefined;
|
|
17
19
|
const message = Reflect.get(err, 'message');
|
|
18
20
|
const type = Reflect.get(err, 'type');
|
|
19
21
|
return {
|
|
20
22
|
status: rawStatus,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
code: CLIENT_ERROR_CODES[rawStatus] ?? 'BAD_REQUEST',
|
|
24
|
+
message: type === 'entity.parse.failed'
|
|
25
|
+
? 'Invalid JSON body'
|
|
26
|
+
: typeof message === 'string'
|
|
27
|
+
? message
|
|
28
|
+
: 'Bad request',
|
|
23
29
|
};
|
|
24
30
|
}
|
|
25
31
|
export function errorHandler(err, _req, res, _next) {
|
|
26
32
|
if (res.headersSent) {
|
|
27
33
|
return;
|
|
28
34
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
res
|
|
32
|
-
error: {
|
|
33
|
-
message: err.message,
|
|
34
|
-
code: err.code,
|
|
35
|
-
},
|
|
36
|
-
});
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
const clientError = asClientError(err);
|
|
40
|
-
if (clientError) {
|
|
41
|
-
const message = clientError.type === 'entity.parse.failed' ? 'Invalid JSON body' : clientError.message;
|
|
42
|
-
res.status(clientError.status).json({
|
|
43
|
-
error: {
|
|
44
|
-
message,
|
|
45
|
-
code: CLIENT_ERROR_CODES[clientError.status] ?? 'BAD_REQUEST',
|
|
46
|
-
},
|
|
47
|
-
});
|
|
35
|
+
const described = describeHttpError(err) ?? asClientError(err);
|
|
36
|
+
if (described) {
|
|
37
|
+
sendFailure(res, described);
|
|
48
38
|
return;
|
|
49
39
|
}
|
|
50
40
|
console.error('[CogitatorServer] Unhandled error:', err);
|
|
51
|
-
res
|
|
52
|
-
error: {
|
|
53
|
-
message: 'Internal server error',
|
|
54
|
-
code: ErrorCode.INTERNAL_ERROR,
|
|
55
|
-
},
|
|
56
|
-
});
|
|
41
|
+
sendFailure(res, INTERNAL_ERROR);
|
|
57
42
|
}
|
|
58
43
|
export function notFoundHandler(_req, res) {
|
|
59
|
-
res
|
|
60
|
-
error: {
|
|
61
|
-
message: 'Not found',
|
|
62
|
-
code: 'NOT_FOUND',
|
|
63
|
-
},
|
|
64
|
-
});
|
|
44
|
+
sendError(res, 404, 'Not found', 'NOT_FOUND');
|
|
65
45
|
}
|
|
66
46
|
//# sourceMappingURL=error-handler.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../src/middleware/error-handler.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../src/middleware/error-handler.ts"],"names":[],"mappings":"AACA,OAAO,EACL,cAAc,EACd,iBAAiB,GAElB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAE5D,MAAM,kBAAkB,GAA2B;IACjD,GAAG,EAAE,eAAe;IACpB,GAAG,EAAE,cAAc;IACnB,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,mBAAmB;IACxB,GAAG,EAAE,wBAAwB;IAC7B,GAAG,EAAE,qBAAqB;CAC3B,CAAC;AAEF,6EAA6E;AAC7E,SAAS,aAAa,CAAC,GAAY;IACjC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAC9D,MAAM,SAAS,GAAY,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IACxF,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,GAAG,GAAG,IAAI,SAAS,IAAI,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3F,MAAM,OAAO,GAAY,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACrD,MAAM,IAAI,GAAY,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC/C,OAAO;QACL,MAAM,EAAE,SAAS;QACjB,IAAI,EAAE,kBAAkB,CAAC,SAAS,CAAC,IAAI,aAAa;QACpD,OAAO,EACL,IAAI,KAAK,qBAAqB;YAC5B,CAAC,CAAC,mBAAmB;YACrB,CAAC,CAAC,OAAO,OAAO,KAAK,QAAQ;gBAC3B,CAAC,CAAC,OAAO;gBACT,CAAC,CAAC,aAAa;KACtB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAU,EAAE,IAAa,EAAE,GAAa,EAAE,KAAmB;IACxF,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;QACpB,OAAO;IACT,CAAC;IAED,MAAM,SAAS,GAAG,iBAAiB,CAAC,GAAG,CAAC,IAAI,aAAa,CAAC,GAAG,CAAC,CAAC;IAC/D,IAAI,SAAS,EAAE,CAAC;QACd,WAAW,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC5B,OAAO;IACT,CAAC;IAED,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,GAAG,CAAC,CAAC;IACzD,WAAW,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAa,EAAE,GAAa;IAC1D,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { createAuthMiddleware } from './auth.js';
|
|
1
|
+
export { createAuthMiddleware, createAnonymousGuard } from './auth.js';
|
|
2
2
|
export { createRateLimitMiddleware } from './rate-limit.js';
|
|
3
3
|
export { createCorsMiddleware } from './cors.js';
|
|
4
4
|
export { errorHandler, notFoundHandler } from './error-handler.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/middleware/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { createAuthMiddleware } from './auth.js';
|
|
1
|
+
export { createAuthMiddleware, createAnonymousGuard } from './auth.js';
|
|
2
2
|
export { createRateLimitMiddleware } from './rate-limit.js';
|
|
3
3
|
export { createCorsMiddleware } from './cors.js';
|
|
4
4
|
export { errorHandler, notFoundHandler } from './error-handler.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-body.d.ts","sourceRoot":"","sources":["../../src/middleware/json-body.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"json-body.d.ts","sourceRoot":"","sources":["../../src/middleware/json-body.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAI9C;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,cAAc,CASpD"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { refuseNonJsonBody } from '@cogitator-ai/server-shared';
|
|
2
|
+
import { sendFailure } from '../routes/utils.js';
|
|
2
3
|
/**
|
|
3
4
|
* Refuses a request whose body is not JSON with `415 UNSUPPORTED_MEDIA_TYPE` before any
|
|
4
5
|
* route reads it. Browsers send `text/plain` and form bodies across origins without a
|
|
@@ -11,7 +12,7 @@ export function createJsonBodyGuard() {
|
|
|
11
12
|
next();
|
|
12
13
|
return;
|
|
13
14
|
}
|
|
14
|
-
res
|
|
15
|
+
sendFailure(res, refusal);
|
|
15
16
|
};
|
|
16
17
|
}
|
|
17
18
|
//# sourceMappingURL=json-body.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-body.js","sourceRoot":"","sources":["../../src/middleware/json-body.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"json-body.js","sourceRoot":"","sources":["../../src/middleware/json-body.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD;;;;GAIG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACxB,MAAM,OAAO,GAAG,iBAAiB,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;QAC3D,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,IAAI,EAAE,CAAC;YACP,OAAO;QACT,CAAC;QACD,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC5B,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/middleware/rate-limit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAW,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/middleware/rate-limit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAW,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAuBrE,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,eAAe,IA4BvD,KAAK,gBAAgB,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,UAmCjE"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sendFailure } from '../routes/utils.js';
|
|
1
2
|
function buildKeyGenerator(trustProxy) {
|
|
2
3
|
return (req) => {
|
|
3
4
|
if (trustProxy) {
|
|
@@ -49,12 +50,11 @@ export function createRateLimitMiddleware(config) {
|
|
|
49
50
|
res.setHeader('X-RateLimit-Remaining', remaining.toString());
|
|
50
51
|
res.setHeader('X-RateLimit-Reset', resetSeconds.toString());
|
|
51
52
|
if (entry.count > max) {
|
|
52
|
-
res
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
},
|
|
53
|
+
sendFailure(res, {
|
|
54
|
+
status: 429,
|
|
55
|
+
code: 'RATE_LIMIT_EXCEEDED',
|
|
56
|
+
message,
|
|
57
|
+
retryAfter: resetSeconds,
|
|
58
58
|
});
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../../src/middleware/rate-limit.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../../src/middleware/rate-limit.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/routes/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/routes/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGjC,OAAO,KAAK,EAAE,YAAY,EAAuC,MAAM,aAAa,CAAC;AAgBrF,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CA0M3D"}
|