@kavachos/nestjs 0.0.3
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/LICENSE +21 -0
- package/dist/index.d.ts +70 -0
- package/dist/index.js +628 -0
- package/dist/index.js.map +1 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 KavachOS
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Router, Request, Response, NextFunction } from 'express';
|
|
2
|
+
import { Kavach } from 'kavachos';
|
|
3
|
+
import { McpAuthModule } from 'kavachos/mcp';
|
|
4
|
+
import { NestModule, MiddlewareConsumer, DynamicModule } from '@nestjs/common';
|
|
5
|
+
|
|
6
|
+
interface KavachNestjsOptions {
|
|
7
|
+
/** The Kavach instance */
|
|
8
|
+
kavach: Kavach;
|
|
9
|
+
/** Optional MCP OAuth 2.1 module */
|
|
10
|
+
mcp?: McpAuthModule;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Build the Express Router with all KavachOS routes.
|
|
14
|
+
* Used internally by `KavachModule` and can also be used directly in
|
|
15
|
+
* Express-backed NestJS apps via `app.use`.
|
|
16
|
+
*/
|
|
17
|
+
declare function buildKavachRouter(kavach: Kavach, mcp?: McpAuthModule): Router;
|
|
18
|
+
/**
|
|
19
|
+
* Returns an Express-compatible middleware function that mounts all KavachOS
|
|
20
|
+
* routes. Use this with `app.use()` in your NestJS bootstrap, or register it
|
|
21
|
+
* via `KavachModule.forRoot()`.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* // main.ts
|
|
26
|
+
* const app = await NestFactory.create(AppModule);
|
|
27
|
+
* app.use('/api/kavach', kavachMiddleware({ kavach, mcp }));
|
|
28
|
+
* await app.listen(3000);
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
declare function kavachMiddleware(options: KavachNestjsOptions): (req: Request, res: Response, next: NextFunction) => void;
|
|
32
|
+
|
|
33
|
+
interface KavachModuleOptions {
|
|
34
|
+
/** The Kavach instance created with `createKavach()` */
|
|
35
|
+
kavach: Kavach;
|
|
36
|
+
/** Optional MCP OAuth 2.1 module created with `createMcpModule()` */
|
|
37
|
+
mcp?: McpAuthModule;
|
|
38
|
+
/**
|
|
39
|
+
* The path prefix where KavachOS routes will be mounted.
|
|
40
|
+
* @default '/api/kavach'
|
|
41
|
+
*/
|
|
42
|
+
basePath?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* NestJS dynamic module that mounts all KavachOS REST routes as Express
|
|
46
|
+
* middleware. Import it once in your root `AppModule`.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* // app.module.ts
|
|
51
|
+
* import { Module } from '@nestjs/common';
|
|
52
|
+
* import { KavachModule } from '@kavachos/nestjs';
|
|
53
|
+
* import { kavach, mcp } from './lib/kavach.js';
|
|
54
|
+
*
|
|
55
|
+
* @Module({
|
|
56
|
+
* imports: [
|
|
57
|
+
* KavachModule.forRoot({ kavach, mcp, basePath: '/api/kavach' }),
|
|
58
|
+
* ],
|
|
59
|
+
* })
|
|
60
|
+
* export class AppModule {}
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
declare class KavachModule implements NestModule {
|
|
64
|
+
private readonly options;
|
|
65
|
+
constructor(options: KavachModuleOptions);
|
|
66
|
+
configure(consumer: MiddlewareConsumer): void;
|
|
67
|
+
static forRoot(options: KavachModuleOptions): DynamicModule;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export { KavachModule, type KavachModuleOptions, type KavachNestjsOptions, buildKavachRouter, kavachMiddleware };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,628 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { Module, Inject } from '@nestjs/common';
|
|
4
|
+
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
7
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
8
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
9
|
+
if (decorator = decorators[i])
|
|
10
|
+
result = (decorator(result)) || result;
|
|
11
|
+
return result;
|
|
12
|
+
};
|
|
13
|
+
var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
|
|
14
|
+
var PermissionConstraintsSchema = z.object({
|
|
15
|
+
maxCallsPerHour: z.number().int().positive().optional(),
|
|
16
|
+
allowedArgPatterns: z.array(z.string()).optional(),
|
|
17
|
+
requireApproval: z.boolean().optional(),
|
|
18
|
+
timeWindow: z.object({
|
|
19
|
+
start: z.string(),
|
|
20
|
+
end: z.string()
|
|
21
|
+
}).optional(),
|
|
22
|
+
ipAllowlist: z.array(z.string()).optional()
|
|
23
|
+
});
|
|
24
|
+
var PermissionSchema = z.object({
|
|
25
|
+
resource: z.string().min(1),
|
|
26
|
+
actions: z.array(z.string().min(1)).min(1),
|
|
27
|
+
constraints: PermissionConstraintsSchema.optional()
|
|
28
|
+
});
|
|
29
|
+
var CreateAgentSchema = z.object({
|
|
30
|
+
ownerId: z.string().min(1),
|
|
31
|
+
name: z.string().min(1),
|
|
32
|
+
type: z.enum(["autonomous", "delegated", "service"]),
|
|
33
|
+
permissions: z.array(PermissionSchema).min(1),
|
|
34
|
+
expiresAt: z.coerce.date().optional(),
|
|
35
|
+
metadata: z.record(z.unknown()).optional()
|
|
36
|
+
});
|
|
37
|
+
var UpdateAgentSchema = z.object({
|
|
38
|
+
name: z.string().min(1).optional(),
|
|
39
|
+
permissions: z.array(PermissionSchema).optional(),
|
|
40
|
+
expiresAt: z.coerce.date().optional(),
|
|
41
|
+
metadata: z.record(z.unknown()).optional()
|
|
42
|
+
});
|
|
43
|
+
var AuthorizeSchema = z.object({
|
|
44
|
+
agentId: z.string().min(1),
|
|
45
|
+
action: z.string().min(1),
|
|
46
|
+
resource: z.string().min(1),
|
|
47
|
+
arguments: z.record(z.unknown()).optional()
|
|
48
|
+
});
|
|
49
|
+
var AuthorizeByTokenSchema = z.object({
|
|
50
|
+
action: z.string().min(1),
|
|
51
|
+
resource: z.string().min(1),
|
|
52
|
+
arguments: z.record(z.unknown()).optional()
|
|
53
|
+
});
|
|
54
|
+
var DelegateSchema = z.object({
|
|
55
|
+
fromAgent: z.string().min(1),
|
|
56
|
+
toAgent: z.string().min(1),
|
|
57
|
+
permissions: z.array(PermissionSchema).min(1),
|
|
58
|
+
expiresAt: z.coerce.date(),
|
|
59
|
+
maxDepth: z.number().int().positive().optional()
|
|
60
|
+
});
|
|
61
|
+
function sendOk(res, data, status = 200) {
|
|
62
|
+
res.status(status).json({ data });
|
|
63
|
+
}
|
|
64
|
+
function sendCreated(res, data) {
|
|
65
|
+
sendOk(res, data, 201);
|
|
66
|
+
}
|
|
67
|
+
function sendNoContent(res) {
|
|
68
|
+
res.status(204).end();
|
|
69
|
+
}
|
|
70
|
+
function sendError(res, code, message, status) {
|
|
71
|
+
res.status(status).json({ error: { code, message } });
|
|
72
|
+
}
|
|
73
|
+
function sendBadRequest(res, message) {
|
|
74
|
+
sendError(res, "BAD_REQUEST", message, 400);
|
|
75
|
+
}
|
|
76
|
+
function sendUnauthorized(res, message = "Unauthorized") {
|
|
77
|
+
sendError(res, "UNAUTHORIZED", message, 401);
|
|
78
|
+
}
|
|
79
|
+
function sendNotFound(res, message = "Not found") {
|
|
80
|
+
sendError(res, "NOT_FOUND", message, 404);
|
|
81
|
+
}
|
|
82
|
+
function sendInternalError(res, message = "Internal server error") {
|
|
83
|
+
sendError(res, "INTERNAL_ERROR", message, 500);
|
|
84
|
+
}
|
|
85
|
+
function sendValidationError(res, issues) {
|
|
86
|
+
const message = issues.map((i) => `${i.path.join(".")}: ${i.message}`).join(", ");
|
|
87
|
+
sendBadRequest(res, `Validation failed: ${message}`);
|
|
88
|
+
}
|
|
89
|
+
var MCP_CORS_HEADERS = {
|
|
90
|
+
"Access-Control-Allow-Origin": "*",
|
|
91
|
+
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
|
|
92
|
+
"Access-Control-Allow-Headers": "Content-Type, Authorization",
|
|
93
|
+
"Access-Control-Max-Age": "86400"
|
|
94
|
+
};
|
|
95
|
+
function setMcpCors(res) {
|
|
96
|
+
for (const [key, value] of Object.entries(MCP_CORS_HEADERS)) {
|
|
97
|
+
res.setHeader(key, value);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function sendMcpOk(res, data, status = 200) {
|
|
101
|
+
setMcpCors(res);
|
|
102
|
+
res.status(status).json(data);
|
|
103
|
+
}
|
|
104
|
+
function sendMcpError(res, code, message, status) {
|
|
105
|
+
setMcpCors(res);
|
|
106
|
+
res.status(status).json({ error: code, error_description: message });
|
|
107
|
+
}
|
|
108
|
+
function sendMcpNoStore(res, data, status = 200) {
|
|
109
|
+
setMcpCors(res);
|
|
110
|
+
res.setHeader("Cache-Control", "no-store");
|
|
111
|
+
res.setHeader("Pragma", "no-cache");
|
|
112
|
+
res.status(status).json(data);
|
|
113
|
+
}
|
|
114
|
+
function routeParam(req, name) {
|
|
115
|
+
const val = req.params[name];
|
|
116
|
+
return Array.isArray(val) ? val[0] ?? "" : val ?? "";
|
|
117
|
+
}
|
|
118
|
+
function buildWebRequest(req) {
|
|
119
|
+
const protocol = req.protocol ?? "http";
|
|
120
|
+
const host = req.headers.host ?? "localhost";
|
|
121
|
+
const url = `${protocol}://${host}${req.originalUrl ?? req.url}`;
|
|
122
|
+
const headers = new Headers();
|
|
123
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
124
|
+
if (value !== void 0) {
|
|
125
|
+
if (Array.isArray(value)) {
|
|
126
|
+
for (const v of value) {
|
|
127
|
+
headers.append(key, v);
|
|
128
|
+
}
|
|
129
|
+
} else {
|
|
130
|
+
headers.set(key, value);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
let body = null;
|
|
135
|
+
if (req.method !== "GET" && req.method !== "HEAD" && req.body !== void 0) {
|
|
136
|
+
const contentType = req.headers["content-type"] ?? "";
|
|
137
|
+
if (contentType.includes("application/x-www-form-urlencoded")) {
|
|
138
|
+
const params = new URLSearchParams();
|
|
139
|
+
for (const [k, v] of Object.entries(req.body)) {
|
|
140
|
+
params.set(k, v);
|
|
141
|
+
}
|
|
142
|
+
body = params.toString();
|
|
143
|
+
} else {
|
|
144
|
+
body = JSON.stringify(req.body);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return new Request(url, {
|
|
148
|
+
method: req.method,
|
|
149
|
+
headers,
|
|
150
|
+
body: body ?? void 0
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
function buildKavachRouter(kavach, mcp) {
|
|
154
|
+
const router = Router();
|
|
155
|
+
router.post("/agents", (req, res) => {
|
|
156
|
+
const parsed = CreateAgentSchema.safeParse(req.body);
|
|
157
|
+
if (!parsed.success) {
|
|
158
|
+
sendValidationError(res, parsed.error.issues);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const input = {
|
|
162
|
+
...parsed.data,
|
|
163
|
+
permissions: parsed.data.permissions
|
|
164
|
+
};
|
|
165
|
+
kavach.agent.create(input).then((agent) => sendCreated(res, agent)).catch((err) => {
|
|
166
|
+
const message = err instanceof Error ? err.message : "Failed to create agent";
|
|
167
|
+
sendInternalError(res, message);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
router.get("/agents", (req, res) => {
|
|
171
|
+
const filter = {};
|
|
172
|
+
const { userId, status, type } = req.query;
|
|
173
|
+
if (typeof userId === "string") filter.userId = userId;
|
|
174
|
+
if (typeof status === "string" && ["active", "revoked", "expired"].includes(status)) {
|
|
175
|
+
filter.status = status;
|
|
176
|
+
}
|
|
177
|
+
if (typeof type === "string" && ["autonomous", "delegated", "service"].includes(type)) {
|
|
178
|
+
filter.type = type;
|
|
179
|
+
}
|
|
180
|
+
kavach.agent.list(filter).then((agents) => sendOk(res, agents)).catch((err) => {
|
|
181
|
+
const message = err instanceof Error ? err.message : "Failed to list agents";
|
|
182
|
+
sendInternalError(res, message);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
router.get("/agents/:id", (req, res) => {
|
|
186
|
+
const id = routeParam(req, "id");
|
|
187
|
+
kavach.agent.get(id).then((agent) => {
|
|
188
|
+
if (!agent) {
|
|
189
|
+
sendNotFound(res, `Agent "${id}" not found`);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
sendOk(res, agent);
|
|
193
|
+
}).catch((err) => {
|
|
194
|
+
const message = err instanceof Error ? err.message : "Failed to get agent";
|
|
195
|
+
sendInternalError(res, message);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
router.patch("/agents/:id", (req, res) => {
|
|
199
|
+
const id = routeParam(req, "id");
|
|
200
|
+
const parsed = UpdateAgentSchema.safeParse(req.body);
|
|
201
|
+
if (!parsed.success) {
|
|
202
|
+
sendValidationError(res, parsed.error.issues);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const input = {
|
|
206
|
+
...parsed.data,
|
|
207
|
+
permissions: parsed.data.permissions
|
|
208
|
+
};
|
|
209
|
+
kavach.agent.update(id, input).then((agent) => sendOk(res, agent)).catch((err) => {
|
|
210
|
+
const message = err instanceof Error ? err.message : "Failed to update agent";
|
|
211
|
+
if (message.includes("not found")) {
|
|
212
|
+
sendNotFound(res, message);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
sendInternalError(res, message);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
router.delete("/agents/:id", (req, res) => {
|
|
219
|
+
const id = routeParam(req, "id");
|
|
220
|
+
kavach.agent.revoke(id).then(() => sendNoContent(res)).catch((err) => {
|
|
221
|
+
const message = err instanceof Error ? err.message : "Failed to revoke agent";
|
|
222
|
+
if (message.includes("not found")) {
|
|
223
|
+
sendNotFound(res, message);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
sendInternalError(res, message);
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
router.post("/agents/:id/rotate", (req, res) => {
|
|
230
|
+
const id = routeParam(req, "id");
|
|
231
|
+
kavach.agent.rotate(id).then((agent) => sendOk(res, agent)).catch((err) => {
|
|
232
|
+
const message = err instanceof Error ? err.message : "Failed to rotate agent token";
|
|
233
|
+
if (message.includes("not found")) {
|
|
234
|
+
sendNotFound(res, message);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
sendInternalError(res, message);
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
router.post("/authorize", (req, res) => {
|
|
241
|
+
const parsed = AuthorizeSchema.safeParse(req.body);
|
|
242
|
+
if (!parsed.success) {
|
|
243
|
+
sendValidationError(res, parsed.error.issues);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const xForwardedFor = req.headers["x-forwarded-for"];
|
|
247
|
+
const ip = (Array.isArray(xForwardedFor) ? xForwardedFor[0] : xForwardedFor?.split(",")[0]?.trim()) ?? req.ip ?? void 0;
|
|
248
|
+
const userAgent = (Array.isArray(req.headers["user-agent"]) ? req.headers["user-agent"][0] : req.headers["user-agent"]) ?? void 0;
|
|
249
|
+
kavach.authorize(
|
|
250
|
+
parsed.data.agentId,
|
|
251
|
+
{
|
|
252
|
+
action: parsed.data.action,
|
|
253
|
+
resource: parsed.data.resource,
|
|
254
|
+
arguments: parsed.data.arguments
|
|
255
|
+
},
|
|
256
|
+
{ ip, userAgent }
|
|
257
|
+
).then((result) => {
|
|
258
|
+
const status = result.allowed ? 200 : 403;
|
|
259
|
+
res.status(status).json({ data: result });
|
|
260
|
+
}).catch((err) => {
|
|
261
|
+
const message = err instanceof Error ? err.message : "Authorization check failed";
|
|
262
|
+
sendInternalError(res, message);
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
router.post("/authorize/token", (req, res) => {
|
|
266
|
+
const authHeader = req.headers.authorization;
|
|
267
|
+
if (!authHeader?.startsWith("Bearer ")) {
|
|
268
|
+
sendUnauthorized(res, "Missing or invalid Authorization header");
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
const token = authHeader.slice(7);
|
|
272
|
+
const parsed = AuthorizeByTokenSchema.safeParse(req.body);
|
|
273
|
+
if (!parsed.success) {
|
|
274
|
+
sendValidationError(res, parsed.error.issues);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const xForwardedFor = req.headers["x-forwarded-for"];
|
|
278
|
+
const ip = (Array.isArray(xForwardedFor) ? xForwardedFor[0] : xForwardedFor?.split(",")[0]?.trim()) ?? req.ip ?? void 0;
|
|
279
|
+
const userAgent = (Array.isArray(req.headers["user-agent"]) ? req.headers["user-agent"][0] : req.headers["user-agent"]) ?? void 0;
|
|
280
|
+
kavach.authorizeByToken(
|
|
281
|
+
token,
|
|
282
|
+
{
|
|
283
|
+
action: parsed.data.action,
|
|
284
|
+
resource: parsed.data.resource,
|
|
285
|
+
arguments: parsed.data.arguments
|
|
286
|
+
},
|
|
287
|
+
{ ip, userAgent }
|
|
288
|
+
).then((result) => {
|
|
289
|
+
const status = result.allowed ? 200 : 403;
|
|
290
|
+
res.status(status).json({ data: result });
|
|
291
|
+
}).catch((err) => {
|
|
292
|
+
const message = err instanceof Error ? err.message : "Authorization check failed";
|
|
293
|
+
sendInternalError(res, message);
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
router.post("/delegations", (req, res) => {
|
|
297
|
+
const parsed = DelegateSchema.safeParse(req.body);
|
|
298
|
+
if (!parsed.success) {
|
|
299
|
+
sendValidationError(res, parsed.error.issues);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
const input = {
|
|
303
|
+
...parsed.data,
|
|
304
|
+
permissions: parsed.data.permissions
|
|
305
|
+
};
|
|
306
|
+
kavach.delegate(input).then((chain) => sendCreated(res, chain)).catch((err) => {
|
|
307
|
+
const message = err instanceof Error ? err.message : "Failed to create delegation";
|
|
308
|
+
if (message.includes("not found")) {
|
|
309
|
+
sendNotFound(res, message);
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
if (message.includes("exceeds") || message.includes("depth")) {
|
|
313
|
+
sendBadRequest(res, message);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
sendInternalError(res, message);
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
router.delete("/delegations/:id", (req, res) => {
|
|
320
|
+
const id = routeParam(req, "id");
|
|
321
|
+
kavach.delegation.revoke(id).then(() => sendNoContent(res)).catch((err) => {
|
|
322
|
+
const message = err instanceof Error ? err.message : "Failed to revoke delegation";
|
|
323
|
+
if (message.includes("not found")) {
|
|
324
|
+
sendNotFound(res, message);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
sendInternalError(res, message);
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
router.get("/delegations/:agentId", (req, res) => {
|
|
331
|
+
const agentId = routeParam(req, "agentId");
|
|
332
|
+
kavach.delegation.listChains(agentId).then((chains) => sendOk(res, chains)).catch((err) => {
|
|
333
|
+
const message = err instanceof Error ? err.message : "Failed to list delegation chains";
|
|
334
|
+
sendInternalError(res, message);
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
router.get("/audit", (req, res) => {
|
|
338
|
+
const filter = {};
|
|
339
|
+
const { agentId, userId, since, until, actions, result, limit, offset } = req.query;
|
|
340
|
+
if (typeof agentId === "string") filter.agentId = agentId;
|
|
341
|
+
if (typeof userId === "string") filter.userId = userId;
|
|
342
|
+
if (typeof since === "string") {
|
|
343
|
+
const d = new Date(since);
|
|
344
|
+
if (!Number.isNaN(d.getTime())) filter.since = d;
|
|
345
|
+
}
|
|
346
|
+
if (typeof until === "string") {
|
|
347
|
+
const d = new Date(until);
|
|
348
|
+
if (!Number.isNaN(d.getTime())) filter.until = d;
|
|
349
|
+
}
|
|
350
|
+
if (typeof actions === "string") {
|
|
351
|
+
filter.actions = actions.split(",").map((a) => a.trim());
|
|
352
|
+
}
|
|
353
|
+
if (typeof result === "string" && ["allowed", "denied", "rate_limited"].includes(result)) {
|
|
354
|
+
filter.result = result;
|
|
355
|
+
}
|
|
356
|
+
if (typeof limit === "string") {
|
|
357
|
+
const n = Number.parseInt(limit, 10);
|
|
358
|
+
if (!Number.isNaN(n) && n > 0) filter.limit = n;
|
|
359
|
+
}
|
|
360
|
+
if (typeof offset === "string") {
|
|
361
|
+
const n = Number.parseInt(offset, 10);
|
|
362
|
+
if (!Number.isNaN(n) && n >= 0) filter.offset = n;
|
|
363
|
+
}
|
|
364
|
+
kavach.audit.query(filter).then((entries) => sendOk(res, entries)).catch((err) => {
|
|
365
|
+
const message = err instanceof Error ? err.message : "Failed to query audit logs";
|
|
366
|
+
sendInternalError(res, message);
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
router.get("/audit/export", (req, res) => {
|
|
370
|
+
const format = req.query.format ?? "json";
|
|
371
|
+
if (format !== "json" && format !== "csv") {
|
|
372
|
+
sendBadRequest(res, 'format must be "json" or "csv"');
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
const options = { format };
|
|
376
|
+
const { since, until } = req.query;
|
|
377
|
+
if (typeof since === "string") {
|
|
378
|
+
const d = new Date(since);
|
|
379
|
+
if (!Number.isNaN(d.getTime())) options.since = d;
|
|
380
|
+
}
|
|
381
|
+
if (typeof until === "string") {
|
|
382
|
+
const d = new Date(until);
|
|
383
|
+
if (!Number.isNaN(d.getTime())) options.until = d;
|
|
384
|
+
}
|
|
385
|
+
kavach.audit.export(options).then((exported) => {
|
|
386
|
+
const contentType = format === "csv" ? "text/csv" : "application/json";
|
|
387
|
+
res.setHeader("Content-Type", contentType);
|
|
388
|
+
res.setHeader("Content-Disposition", `attachment; filename="audit-export.${format}"`);
|
|
389
|
+
res.status(200).send(exported);
|
|
390
|
+
}).catch((err) => {
|
|
391
|
+
const message = err instanceof Error ? err.message : "Failed to export audit logs";
|
|
392
|
+
sendInternalError(res, message);
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
router.get("/dashboard/stats", (_req, res) => {
|
|
396
|
+
Promise.all([
|
|
397
|
+
kavach.agent.list(),
|
|
398
|
+
kavach.audit.query({
|
|
399
|
+
since: new Date(Date.now() - 24 * 60 * 60 * 1e3),
|
|
400
|
+
limit: 1e3
|
|
401
|
+
})
|
|
402
|
+
]).then(([agents, recentAudit]) => {
|
|
403
|
+
const ownerIds = new Set(agents.map((a) => a.ownerId));
|
|
404
|
+
const stats = {
|
|
405
|
+
agents: {
|
|
406
|
+
total: agents.length,
|
|
407
|
+
active: agents.filter((a) => a.status === "active").length,
|
|
408
|
+
revoked: agents.filter((a) => a.status === "revoked").length,
|
|
409
|
+
expired: agents.filter((a) => a.status === "expired").length
|
|
410
|
+
},
|
|
411
|
+
users: {
|
|
412
|
+
total: ownerIds.size
|
|
413
|
+
},
|
|
414
|
+
audit: {
|
|
415
|
+
last24h: recentAudit.length,
|
|
416
|
+
allowed: recentAudit.filter((e) => e.result === "allowed").length,
|
|
417
|
+
denied: recentAudit.filter((e) => e.result === "denied").length,
|
|
418
|
+
rateLimited: recentAudit.filter((e) => e.result === "rate_limited").length
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
sendOk(res, stats);
|
|
422
|
+
}).catch((err) => {
|
|
423
|
+
const message = err instanceof Error ? err.message : "Failed to fetch dashboard stats";
|
|
424
|
+
sendInternalError(res, message);
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
router.get("/dashboard/agents", (req, res) => {
|
|
428
|
+
const filter = {};
|
|
429
|
+
const { userId, status, type } = req.query;
|
|
430
|
+
if (typeof userId === "string") filter.userId = userId;
|
|
431
|
+
if (typeof status === "string" && ["active", "revoked", "expired"].includes(status)) {
|
|
432
|
+
filter.status = status;
|
|
433
|
+
}
|
|
434
|
+
if (typeof type === "string" && ["autonomous", "delegated", "service"].includes(type)) {
|
|
435
|
+
filter.type = type;
|
|
436
|
+
}
|
|
437
|
+
kavach.agent.list(filter).then((agents) => sendOk(res, agents)).catch((err) => {
|
|
438
|
+
const message = err instanceof Error ? err.message : "Failed to list agents";
|
|
439
|
+
sendInternalError(res, message);
|
|
440
|
+
});
|
|
441
|
+
});
|
|
442
|
+
router.get("/dashboard/audit", (req, res) => {
|
|
443
|
+
const filter = {};
|
|
444
|
+
const { agentId, userId, since, until, actions, result, limit, offset } = req.query;
|
|
445
|
+
if (typeof agentId === "string") filter.agentId = agentId;
|
|
446
|
+
if (typeof userId === "string") filter.userId = userId;
|
|
447
|
+
if (typeof since === "string") {
|
|
448
|
+
const d = new Date(since);
|
|
449
|
+
if (!Number.isNaN(d.getTime())) filter.since = d;
|
|
450
|
+
}
|
|
451
|
+
if (typeof until === "string") {
|
|
452
|
+
const d = new Date(until);
|
|
453
|
+
if (!Number.isNaN(d.getTime())) filter.until = d;
|
|
454
|
+
}
|
|
455
|
+
if (typeof actions === "string") {
|
|
456
|
+
filter.actions = actions.split(",").map((a) => a.trim());
|
|
457
|
+
}
|
|
458
|
+
if (typeof result === "string" && ["allowed", "denied", "rate_limited"].includes(result)) {
|
|
459
|
+
filter.result = result;
|
|
460
|
+
}
|
|
461
|
+
if (typeof limit === "string") {
|
|
462
|
+
const n = Number.parseInt(limit, 10);
|
|
463
|
+
if (!Number.isNaN(n) && n > 0) filter.limit = n;
|
|
464
|
+
}
|
|
465
|
+
if (typeof offset === "string") {
|
|
466
|
+
const n = Number.parseInt(offset, 10);
|
|
467
|
+
if (!Number.isNaN(n) && n >= 0) filter.offset = n;
|
|
468
|
+
}
|
|
469
|
+
kavach.audit.query(filter).then((entries) => sendOk(res, entries)).catch((err) => {
|
|
470
|
+
const message = err instanceof Error ? err.message : "Failed to query audit logs";
|
|
471
|
+
sendInternalError(res, message);
|
|
472
|
+
});
|
|
473
|
+
});
|
|
474
|
+
router.options("/.well-known/*path", (_req, res) => {
|
|
475
|
+
setMcpCors(res);
|
|
476
|
+
res.status(204).end();
|
|
477
|
+
});
|
|
478
|
+
router.options("/mcp/*path", (_req, res) => {
|
|
479
|
+
setMcpCors(res);
|
|
480
|
+
res.status(204).end();
|
|
481
|
+
});
|
|
482
|
+
router.get("/.well-known/oauth-authorization-server", (_req, res) => {
|
|
483
|
+
if (!mcp) {
|
|
484
|
+
sendNotFound(res, "MCP module not configured");
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
sendMcpOk(res, mcp.getMetadata());
|
|
488
|
+
});
|
|
489
|
+
router.get("/.well-known/oauth-protected-resource", (_req, res) => {
|
|
490
|
+
if (!mcp) {
|
|
491
|
+
sendNotFound(res, "MCP module not configured");
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
sendMcpOk(res, mcp.getProtectedResourceMetadata());
|
|
495
|
+
});
|
|
496
|
+
router.post("/mcp/register", (req, res) => {
|
|
497
|
+
if (!mcp) {
|
|
498
|
+
sendNotFound(res, "MCP module not configured");
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
mcp.registerClient(req.body).then((result) => {
|
|
502
|
+
if (!result.success) {
|
|
503
|
+
sendMcpError(res, "invalid_client_metadata", result.error.message, 400);
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
sendMcpNoStore(res, result.data, 201);
|
|
507
|
+
}).catch((err) => {
|
|
508
|
+
const message = err instanceof Error ? err.message : "Registration failed";
|
|
509
|
+
sendMcpError(res, "server_error", message, 500);
|
|
510
|
+
});
|
|
511
|
+
});
|
|
512
|
+
router.get("/mcp/authorize", (req, res) => {
|
|
513
|
+
if (!mcp) {
|
|
514
|
+
sendNotFound(res, "MCP module not configured");
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
const webRequest = buildWebRequest(req);
|
|
518
|
+
mcp.authorize(webRequest).then((result) => {
|
|
519
|
+
if (!result.success) {
|
|
520
|
+
if (result.error.code === "LOGIN_REQUIRED") {
|
|
521
|
+
const details = result.error.details;
|
|
522
|
+
if (details?.loginPage) {
|
|
523
|
+
const loginUrl = new URL(details.loginPage);
|
|
524
|
+
if (details.returnTo) {
|
|
525
|
+
loginUrl.searchParams.set("returnTo", details.returnTo);
|
|
526
|
+
}
|
|
527
|
+
res.redirect(302, loginUrl.toString());
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
sendMcpError(res, result.error.code.toLowerCase(), result.error.message, 400);
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
res.redirect(302, result.data.redirectUri);
|
|
535
|
+
}).catch((err) => {
|
|
536
|
+
const message = err instanceof Error ? err.message : "Authorization failed";
|
|
537
|
+
sendMcpError(res, "server_error", message, 500);
|
|
538
|
+
});
|
|
539
|
+
});
|
|
540
|
+
router.post("/mcp/token", (req, res) => {
|
|
541
|
+
if (!mcp) {
|
|
542
|
+
sendNotFound(res, "MCP module not configured");
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
const webRequest = buildWebRequest(req);
|
|
546
|
+
mcp.token(webRequest).then((result) => {
|
|
547
|
+
if (!result.success) {
|
|
548
|
+
const status = result.error.code === "INVALID_CLIENT" ? 401 : 400;
|
|
549
|
+
sendMcpNoStore(
|
|
550
|
+
res,
|
|
551
|
+
{
|
|
552
|
+
error: result.error.code.toLowerCase(),
|
|
553
|
+
error_description: result.error.message
|
|
554
|
+
},
|
|
555
|
+
status
|
|
556
|
+
);
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
sendMcpNoStore(res, result.data);
|
|
560
|
+
}).catch((err) => {
|
|
561
|
+
const message = err instanceof Error ? err.message : "Token exchange failed";
|
|
562
|
+
sendMcpNoStore(res, { error: "server_error", error_description: message }, 500);
|
|
563
|
+
});
|
|
564
|
+
});
|
|
565
|
+
for (const endpoint of kavach.plugins.getEndpoints()) {
|
|
566
|
+
const method = endpoint.method.toLowerCase();
|
|
567
|
+
router[method](endpoint.path, (req, res) => {
|
|
568
|
+
const webReq = buildWebRequest(req);
|
|
569
|
+
kavach.plugins.handleRequest(webReq).then((response) => {
|
|
570
|
+
if (!response) {
|
|
571
|
+
res.status(404).end();
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
res.status(response.status);
|
|
575
|
+
response.headers.forEach((value, key) => {
|
|
576
|
+
res.setHeader(key, value);
|
|
577
|
+
});
|
|
578
|
+
return response.text().then((body) => {
|
|
579
|
+
res.send(body);
|
|
580
|
+
});
|
|
581
|
+
}).catch((err) => {
|
|
582
|
+
const message = err instanceof Error ? err.message : "Plugin endpoint error";
|
|
583
|
+
sendInternalError(res, message);
|
|
584
|
+
});
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
return router;
|
|
588
|
+
}
|
|
589
|
+
function kavachMiddleware(options) {
|
|
590
|
+
const router = buildKavachRouter(options.kavach, options.mcp);
|
|
591
|
+
return (req, res, next) => {
|
|
592
|
+
router(req, res, next);
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
var KAVACH_OPTIONS = /* @__PURE__ */ Symbol("KAVACH_OPTIONS");
|
|
596
|
+
var KavachModule = class {
|
|
597
|
+
constructor(options) {
|
|
598
|
+
this.options = options;
|
|
599
|
+
}
|
|
600
|
+
configure(consumer) {
|
|
601
|
+
const basePath = this.options.basePath ?? "/api/kavach";
|
|
602
|
+
consumer.apply(
|
|
603
|
+
kavachMiddleware({
|
|
604
|
+
kavach: this.options.kavach,
|
|
605
|
+
mcp: this.options.mcp
|
|
606
|
+
})
|
|
607
|
+
).forRoutes(`${basePath}/*path`);
|
|
608
|
+
}
|
|
609
|
+
static forRoot(options) {
|
|
610
|
+
return {
|
|
611
|
+
module: KavachModule,
|
|
612
|
+
providers: [
|
|
613
|
+
{
|
|
614
|
+
provide: KAVACH_OPTIONS,
|
|
615
|
+
useValue: options
|
|
616
|
+
}
|
|
617
|
+
]
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
KavachModule = __decorateClass([
|
|
622
|
+
Module({}),
|
|
623
|
+
__decorateParam(0, Inject(KAVACH_OPTIONS))
|
|
624
|
+
], KavachModule);
|
|
625
|
+
|
|
626
|
+
export { KavachModule, buildKavachRouter, kavachMiddleware };
|
|
627
|
+
//# sourceMappingURL=index.js.map
|
|
628
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapter.ts","../src/module.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { NextFunction, Request, Response } from \"express\";\nimport { Router } from \"express\";\nimport type {\n\tAgentFilter,\n\tAuditFilter,\n\tCreateAgentInput,\n\tDelegateInput,\n\tKavach,\n\tPermission,\n\tUpdateAgentInput,\n} from \"kavachos\";\nimport type { McpAuthModule } from \"kavachos/mcp\";\nimport { z } from \"zod\";\n\n// ─── Zod Validation Schemas ──────────────────────────────────────────────────\n\nconst PermissionConstraintsSchema = z.object({\n\tmaxCallsPerHour: z.number().int().positive().optional(),\n\tallowedArgPatterns: z.array(z.string()).optional(),\n\trequireApproval: z.boolean().optional(),\n\ttimeWindow: z\n\t\t.object({\n\t\t\tstart: z.string(),\n\t\t\tend: z.string(),\n\t\t})\n\t\t.optional(),\n\tipAllowlist: z.array(z.string()).optional(),\n});\n\nconst PermissionSchema = z.object({\n\tresource: z.string().min(1),\n\tactions: z.array(z.string().min(1)).min(1),\n\tconstraints: PermissionConstraintsSchema.optional(),\n});\n\nconst CreateAgentSchema = z.object({\n\townerId: z.string().min(1),\n\tname: z.string().min(1),\n\ttype: z.enum([\"autonomous\", \"delegated\", \"service\"]),\n\tpermissions: z.array(PermissionSchema).min(1),\n\texpiresAt: z.coerce.date().optional(),\n\tmetadata: z.record(z.unknown()).optional(),\n});\n\nconst UpdateAgentSchema = z.object({\n\tname: z.string().min(1).optional(),\n\tpermissions: z.array(PermissionSchema).optional(),\n\texpiresAt: z.coerce.date().optional(),\n\tmetadata: z.record(z.unknown()).optional(),\n});\n\nconst AuthorizeSchema = z.object({\n\tagentId: z.string().min(1),\n\taction: z.string().min(1),\n\tresource: z.string().min(1),\n\targuments: z.record(z.unknown()).optional(),\n});\n\nconst AuthorizeByTokenSchema = z.object({\n\taction: z.string().min(1),\n\tresource: z.string().min(1),\n\targuments: z.record(z.unknown()).optional(),\n});\n\nconst DelegateSchema = z.object({\n\tfromAgent: z.string().min(1),\n\ttoAgent: z.string().min(1),\n\tpermissions: z.array(PermissionSchema).min(1),\n\texpiresAt: z.coerce.date(),\n\tmaxDepth: z.number().int().positive().optional(),\n});\n\n// ─── Response Helpers ────────────────────────────────────────────────────────\n\nfunction sendOk<T>(res: Response, data: T, status = 200): void {\n\tres.status(status).json({ data });\n}\n\nfunction sendCreated<T>(res: Response, data: T): void {\n\tsendOk(res, data, 201);\n}\n\nfunction sendNoContent(res: Response): void {\n\tres.status(204).end();\n}\n\nfunction sendError(res: Response, code: string, message: string, status: number): void {\n\tres.status(status).json({ error: { code, message } });\n}\n\nfunction sendBadRequest(res: Response, message: string): void {\n\tsendError(res, \"BAD_REQUEST\", message, 400);\n}\n\nfunction sendUnauthorized(res: Response, message = \"Unauthorized\"): void {\n\tsendError(res, \"UNAUTHORIZED\", message, 401);\n}\n\nfunction sendNotFound(res: Response, message = \"Not found\"): void {\n\tsendError(res, \"NOT_FOUND\", message, 404);\n}\n\nfunction sendInternalError(res: Response, message = \"Internal server error\"): void {\n\tsendError(res, \"INTERNAL_ERROR\", message, 500);\n}\n\nfunction sendValidationError(res: Response, issues: z.ZodIssue[]): void {\n\tconst message = issues.map((i) => `${i.path.join(\".\")}: ${i.message}`).join(\", \");\n\tsendBadRequest(res, `Validation failed: ${message}`);\n}\n\n// ─── MCP CORS Helpers ────────────────────────────────────────────────────────\n\nconst MCP_CORS_HEADERS: Record<string, string> = {\n\t\"Access-Control-Allow-Origin\": \"*\",\n\t\"Access-Control-Allow-Methods\": \"GET, POST, OPTIONS\",\n\t\"Access-Control-Allow-Headers\": \"Content-Type, Authorization\",\n\t\"Access-Control-Max-Age\": \"86400\",\n};\n\nfunction setMcpCors(res: Response): void {\n\tfor (const [key, value] of Object.entries(MCP_CORS_HEADERS)) {\n\t\tres.setHeader(key, value);\n\t}\n}\n\nfunction sendMcpOk<T>(res: Response, data: T, status = 200): void {\n\tsetMcpCors(res);\n\tres.status(status).json(data);\n}\n\nfunction sendMcpError(res: Response, code: string, message: string, status: number): void {\n\tsetMcpCors(res);\n\tres.status(status).json({ error: code, error_description: message });\n}\n\nfunction sendMcpNoStore<T>(res: Response, data: T, status = 200): void {\n\tsetMcpCors(res);\n\tres.setHeader(\"Cache-Control\", \"no-store\");\n\tres.setHeader(\"Pragma\", \"no-cache\");\n\tres.status(status).json(data);\n}\n\nfunction routeParam(req: Request, name: string): string {\n\tconst val = req.params[name];\n\treturn Array.isArray(val) ? (val[0] ?? \"\") : (val ?? \"\");\n}\n\n// ─── Web Request Builder ─────────────────────────────────────────────────────\n\nfunction buildWebRequest(req: Request): globalThis.Request {\n\tconst protocol = req.protocol ?? \"http\";\n\tconst host = req.headers.host ?? \"localhost\";\n\tconst url = `${protocol}://${host}${req.originalUrl ?? req.url}`;\n\n\tconst headers = new Headers();\n\tfor (const [key, value] of Object.entries(req.headers)) {\n\t\tif (value !== undefined) {\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\tfor (const v of value) {\n\t\t\t\t\theaders.append(key, v);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\theaders.set(key, value);\n\t\t\t}\n\t\t}\n\t}\n\n\tlet body: string | null = null;\n\tif (req.method !== \"GET\" && req.method !== \"HEAD\" && req.body !== undefined) {\n\t\tconst contentType = req.headers[\"content-type\"] ?? \"\";\n\t\tif (contentType.includes(\"application/x-www-form-urlencoded\")) {\n\t\t\tconst params = new URLSearchParams();\n\t\t\tfor (const [k, v] of Object.entries(req.body as Record<string, string>)) {\n\t\t\t\tparams.set(k, v);\n\t\t\t}\n\t\t\tbody = params.toString();\n\t\t} else {\n\t\t\tbody = JSON.stringify(req.body);\n\t\t}\n\t}\n\n\treturn new Request(url, {\n\t\tmethod: req.method,\n\t\theaders,\n\t\tbody: body ?? undefined,\n\t});\n}\n\n// ─── KavachOS NestJS Options ─────────────────────────────────────────────────\n\nexport interface KavachNestjsOptions {\n\t/** The Kavach instance */\n\tkavach: Kavach;\n\t/** Optional MCP OAuth 2.1 module */\n\tmcp?: McpAuthModule;\n}\n\n// ─── Express Router Builder ──────────────────────────────────────────────────\n\n/**\n * Build the Express Router with all KavachOS routes.\n * Used internally by `KavachModule` and can also be used directly in\n * Express-backed NestJS apps via `app.use`.\n */\nexport function buildKavachRouter(kavach: Kavach, mcp?: McpAuthModule): Router {\n\tconst router = Router();\n\n\t// ── Agent REST API ──────────────────────────────────────────────\n\n\trouter.post(\"/agents\", (req: Request, res: Response) => {\n\t\tconst parsed = CreateAgentSchema.safeParse(req.body);\n\t\tif (!parsed.success) {\n\t\t\tsendValidationError(res, parsed.error.issues);\n\t\t\treturn;\n\t\t}\n\t\tconst input: CreateAgentInput = {\n\t\t\t...parsed.data,\n\t\t\tpermissions: parsed.data.permissions as Permission[],\n\t\t};\n\t\tkavach.agent\n\t\t\t.create(input)\n\t\t\t.then((agent) => sendCreated(res, agent))\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tconst message = err instanceof Error ? err.message : \"Failed to create agent\";\n\t\t\t\tsendInternalError(res, message);\n\t\t\t});\n\t});\n\n\trouter.get(\"/agents\", (req: Request, res: Response) => {\n\t\tconst filter: AgentFilter = {};\n\t\tconst { userId, status, type } = req.query;\n\t\tif (typeof userId === \"string\") filter.userId = userId;\n\t\tif (typeof status === \"string\" && [\"active\", \"revoked\", \"expired\"].includes(status)) {\n\t\t\tfilter.status = status as AgentFilter[\"status\"];\n\t\t}\n\t\tif (typeof type === \"string\" && [\"autonomous\", \"delegated\", \"service\"].includes(type)) {\n\t\t\tfilter.type = type as AgentFilter[\"type\"];\n\t\t}\n\t\tkavach.agent\n\t\t\t.list(filter)\n\t\t\t.then((agents) => sendOk(res, agents))\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tconst message = err instanceof Error ? err.message : \"Failed to list agents\";\n\t\t\t\tsendInternalError(res, message);\n\t\t\t});\n\t});\n\n\trouter.get(\"/agents/:id\", (req: Request, res: Response) => {\n\t\tconst id = routeParam(req, \"id\");\n\t\tkavach.agent\n\t\t\t.get(id)\n\t\t\t.then((agent) => {\n\t\t\t\tif (!agent) {\n\t\t\t\t\tsendNotFound(res, `Agent \"${id}\" not found`);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsendOk(res, agent);\n\t\t\t})\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tconst message = err instanceof Error ? err.message : \"Failed to get agent\";\n\t\t\t\tsendInternalError(res, message);\n\t\t\t});\n\t});\n\n\trouter.patch(\"/agents/:id\", (req: Request, res: Response) => {\n\t\tconst id = routeParam(req, \"id\");\n\t\tconst parsed = UpdateAgentSchema.safeParse(req.body);\n\t\tif (!parsed.success) {\n\t\t\tsendValidationError(res, parsed.error.issues);\n\t\t\treturn;\n\t\t}\n\t\tconst input: UpdateAgentInput = {\n\t\t\t...parsed.data,\n\t\t\tpermissions: parsed.data.permissions as Permission[] | undefined,\n\t\t};\n\t\tkavach.agent\n\t\t\t.update(id, input)\n\t\t\t.then((agent) => sendOk(res, agent))\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tconst message = err instanceof Error ? err.message : \"Failed to update agent\";\n\t\t\t\tif (message.includes(\"not found\")) {\n\t\t\t\t\tsendNotFound(res, message);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsendInternalError(res, message);\n\t\t\t});\n\t});\n\n\trouter.delete(\"/agents/:id\", (req: Request, res: Response) => {\n\t\tconst id = routeParam(req, \"id\");\n\t\tkavach.agent\n\t\t\t.revoke(id)\n\t\t\t.then(() => sendNoContent(res))\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tconst message = err instanceof Error ? err.message : \"Failed to revoke agent\";\n\t\t\t\tif (message.includes(\"not found\")) {\n\t\t\t\t\tsendNotFound(res, message);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsendInternalError(res, message);\n\t\t\t});\n\t});\n\n\trouter.post(\"/agents/:id/rotate\", (req: Request, res: Response) => {\n\t\tconst id = routeParam(req, \"id\");\n\t\tkavach.agent\n\t\t\t.rotate(id)\n\t\t\t.then((agent) => sendOk(res, agent))\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tconst message = err instanceof Error ? err.message : \"Failed to rotate agent token\";\n\t\t\t\tif (message.includes(\"not found\")) {\n\t\t\t\t\tsendNotFound(res, message);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsendInternalError(res, message);\n\t\t\t});\n\t});\n\n\t// ── Authorization ───────────────────────────────────────────────\n\n\trouter.post(\"/authorize\", (req: Request, res: Response) => {\n\t\tconst parsed = AuthorizeSchema.safeParse(req.body);\n\t\tif (!parsed.success) {\n\t\t\tsendValidationError(res, parsed.error.issues);\n\t\t\treturn;\n\t\t}\n\t\tconst xForwardedFor = req.headers[\"x-forwarded-for\"];\n\t\tconst ip =\n\t\t\t(Array.isArray(xForwardedFor) ? xForwardedFor[0] : xForwardedFor?.split(\",\")[0]?.trim()) ??\n\t\t\treq.ip ??\n\t\t\tundefined;\n\t\tconst userAgent =\n\t\t\t(Array.isArray(req.headers[\"user-agent\"])\n\t\t\t\t? req.headers[\"user-agent\"][0]\n\t\t\t\t: req.headers[\"user-agent\"]) ?? undefined;\n\t\tkavach\n\t\t\t.authorize(\n\t\t\t\tparsed.data.agentId,\n\t\t\t\t{\n\t\t\t\t\taction: parsed.data.action,\n\t\t\t\t\tresource: parsed.data.resource,\n\t\t\t\t\targuments: parsed.data.arguments,\n\t\t\t\t},\n\t\t\t\t{ ip, userAgent },\n\t\t\t)\n\t\t\t.then((result) => {\n\t\t\t\tconst status = result.allowed ? 200 : 403;\n\t\t\t\tres.status(status).json({ data: result });\n\t\t\t})\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tconst message = err instanceof Error ? err.message : \"Authorization check failed\";\n\t\t\t\tsendInternalError(res, message);\n\t\t\t});\n\t});\n\n\trouter.post(\"/authorize/token\", (req: Request, res: Response) => {\n\t\tconst authHeader = req.headers.authorization;\n\t\tif (!authHeader?.startsWith(\"Bearer \")) {\n\t\t\tsendUnauthorized(res, \"Missing or invalid Authorization header\");\n\t\t\treturn;\n\t\t}\n\t\tconst token = authHeader.slice(7);\n\n\t\tconst parsed = AuthorizeByTokenSchema.safeParse(req.body);\n\t\tif (!parsed.success) {\n\t\t\tsendValidationError(res, parsed.error.issues);\n\t\t\treturn;\n\t\t}\n\t\tconst xForwardedFor = req.headers[\"x-forwarded-for\"];\n\t\tconst ip =\n\t\t\t(Array.isArray(xForwardedFor) ? xForwardedFor[0] : xForwardedFor?.split(\",\")[0]?.trim()) ??\n\t\t\treq.ip ??\n\t\t\tundefined;\n\t\tconst userAgent =\n\t\t\t(Array.isArray(req.headers[\"user-agent\"])\n\t\t\t\t? req.headers[\"user-agent\"][0]\n\t\t\t\t: req.headers[\"user-agent\"]) ?? undefined;\n\t\tkavach\n\t\t\t.authorizeByToken(\n\t\t\t\ttoken,\n\t\t\t\t{\n\t\t\t\t\taction: parsed.data.action,\n\t\t\t\t\tresource: parsed.data.resource,\n\t\t\t\t\targuments: parsed.data.arguments,\n\t\t\t\t},\n\t\t\t\t{ ip, userAgent },\n\t\t\t)\n\t\t\t.then((result) => {\n\t\t\t\tconst status = result.allowed ? 200 : 403;\n\t\t\t\tres.status(status).json({ data: result });\n\t\t\t})\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tconst message = err instanceof Error ? err.message : \"Authorization check failed\";\n\t\t\t\tsendInternalError(res, message);\n\t\t\t});\n\t});\n\n\t// ── Delegation ──────────────────────────────────────────────────\n\n\trouter.post(\"/delegations\", (req: Request, res: Response) => {\n\t\tconst parsed = DelegateSchema.safeParse(req.body);\n\t\tif (!parsed.success) {\n\t\t\tsendValidationError(res, parsed.error.issues);\n\t\t\treturn;\n\t\t}\n\t\tconst input: DelegateInput = {\n\t\t\t...parsed.data,\n\t\t\tpermissions: parsed.data.permissions as Permission[],\n\t\t};\n\t\tkavach\n\t\t\t.delegate(input)\n\t\t\t.then((chain) => sendCreated(res, chain))\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tconst message = err instanceof Error ? err.message : \"Failed to create delegation\";\n\t\t\t\tif (message.includes(\"not found\")) {\n\t\t\t\t\tsendNotFound(res, message);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (message.includes(\"exceeds\") || message.includes(\"depth\")) {\n\t\t\t\t\tsendBadRequest(res, message);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsendInternalError(res, message);\n\t\t\t});\n\t});\n\n\trouter.delete(\"/delegations/:id\", (req: Request, res: Response) => {\n\t\tconst id = routeParam(req, \"id\");\n\t\tkavach.delegation\n\t\t\t.revoke(id)\n\t\t\t.then(() => sendNoContent(res))\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tconst message = err instanceof Error ? err.message : \"Failed to revoke delegation\";\n\t\t\t\tif (message.includes(\"not found\")) {\n\t\t\t\t\tsendNotFound(res, message);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsendInternalError(res, message);\n\t\t\t});\n\t});\n\n\trouter.get(\"/delegations/:agentId\", (req: Request, res: Response) => {\n\t\tconst agentId = routeParam(req, \"agentId\");\n\t\tkavach.delegation\n\t\t\t.listChains(agentId)\n\t\t\t.then((chains) => sendOk(res, chains))\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tconst message = err instanceof Error ? err.message : \"Failed to list delegation chains\";\n\t\t\t\tsendInternalError(res, message);\n\t\t\t});\n\t});\n\n\t// ── Audit ───────────────────────────────────────────────────────\n\n\trouter.get(\"/audit\", (req: Request, res: Response) => {\n\t\tconst filter: AuditFilter = {};\n\t\tconst { agentId, userId, since, until, actions, result, limit, offset } = req.query;\n\n\t\tif (typeof agentId === \"string\") filter.agentId = agentId;\n\t\tif (typeof userId === \"string\") filter.userId = userId;\n\t\tif (typeof since === \"string\") {\n\t\t\tconst d = new Date(since);\n\t\t\tif (!Number.isNaN(d.getTime())) filter.since = d;\n\t\t}\n\t\tif (typeof until === \"string\") {\n\t\t\tconst d = new Date(until);\n\t\t\tif (!Number.isNaN(d.getTime())) filter.until = d;\n\t\t}\n\t\tif (typeof actions === \"string\") {\n\t\t\tfilter.actions = actions.split(\",\").map((a) => a.trim());\n\t\t}\n\t\tif (typeof result === \"string\" && [\"allowed\", \"denied\", \"rate_limited\"].includes(result)) {\n\t\t\tfilter.result = result as AuditFilter[\"result\"];\n\t\t}\n\t\tif (typeof limit === \"string\") {\n\t\t\tconst n = Number.parseInt(limit, 10);\n\t\t\tif (!Number.isNaN(n) && n > 0) filter.limit = n;\n\t\t}\n\t\tif (typeof offset === \"string\") {\n\t\t\tconst n = Number.parseInt(offset, 10);\n\t\t\tif (!Number.isNaN(n) && n >= 0) filter.offset = n;\n\t\t}\n\n\t\tkavach.audit\n\t\t\t.query(filter)\n\t\t\t.then((entries) => sendOk(res, entries))\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tconst message = err instanceof Error ? err.message : \"Failed to query audit logs\";\n\t\t\t\tsendInternalError(res, message);\n\t\t\t});\n\t});\n\n\trouter.get(\"/audit/export\", (req: Request, res: Response) => {\n\t\tconst format = (req.query.format as string | undefined) ?? \"json\";\n\t\tif (format !== \"json\" && format !== \"csv\") {\n\t\t\tsendBadRequest(res, 'format must be \"json\" or \"csv\"');\n\t\t\treturn;\n\t\t}\n\n\t\tconst options: { format: \"json\" | \"csv\"; since?: Date; until?: Date } = { format };\n\t\tconst { since, until } = req.query;\n\t\tif (typeof since === \"string\") {\n\t\t\tconst d = new Date(since);\n\t\t\tif (!Number.isNaN(d.getTime())) options.since = d;\n\t\t}\n\t\tif (typeof until === \"string\") {\n\t\t\tconst d = new Date(until);\n\t\t\tif (!Number.isNaN(d.getTime())) options.until = d;\n\t\t}\n\n\t\tkavach.audit\n\t\t\t.export(options)\n\t\t\t.then((exported) => {\n\t\t\t\tconst contentType = format === \"csv\" ? \"text/csv\" : \"application/json\";\n\t\t\t\tres.setHeader(\"Content-Type\", contentType);\n\t\t\t\tres.setHeader(\"Content-Disposition\", `attachment; filename=\"audit-export.${format}\"`);\n\t\t\t\tres.status(200).send(exported);\n\t\t\t})\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tconst message = err instanceof Error ? err.message : \"Failed to export audit logs\";\n\t\t\t\tsendInternalError(res, message);\n\t\t\t});\n\t});\n\n\t// ── Dashboard API ───────────────────────────────────────────────\n\n\trouter.get(\"/dashboard/stats\", (_req: Request, res: Response) => {\n\t\tPromise.all([\n\t\t\tkavach.agent.list(),\n\t\t\tkavach.audit.query({\n\t\t\t\tsince: new Date(Date.now() - 24 * 60 * 60 * 1000),\n\t\t\t\tlimit: 1000,\n\t\t\t}),\n\t\t])\n\t\t\t.then(([agents, recentAudit]) => {\n\t\t\t\tconst ownerIds = new Set(agents.map((a) => a.ownerId));\n\t\t\t\tconst stats = {\n\t\t\t\t\tagents: {\n\t\t\t\t\t\ttotal: agents.length,\n\t\t\t\t\t\tactive: agents.filter((a) => a.status === \"active\").length,\n\t\t\t\t\t\trevoked: agents.filter((a) => a.status === \"revoked\").length,\n\t\t\t\t\t\texpired: agents.filter((a) => a.status === \"expired\").length,\n\t\t\t\t\t},\n\t\t\t\t\tusers: {\n\t\t\t\t\t\ttotal: ownerIds.size,\n\t\t\t\t\t},\n\t\t\t\t\taudit: {\n\t\t\t\t\t\tlast24h: recentAudit.length,\n\t\t\t\t\t\tallowed: recentAudit.filter((e) => e.result === \"allowed\").length,\n\t\t\t\t\t\tdenied: recentAudit.filter((e) => e.result === \"denied\").length,\n\t\t\t\t\t\trateLimited: recentAudit.filter((e) => e.result === \"rate_limited\").length,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\tsendOk(res, stats);\n\t\t\t})\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tconst message = err instanceof Error ? err.message : \"Failed to fetch dashboard stats\";\n\t\t\t\tsendInternalError(res, message);\n\t\t\t});\n\t});\n\n\trouter.get(\"/dashboard/agents\", (req: Request, res: Response) => {\n\t\tconst filter: AgentFilter = {};\n\t\tconst { userId, status, type } = req.query;\n\t\tif (typeof userId === \"string\") filter.userId = userId;\n\t\tif (typeof status === \"string\" && [\"active\", \"revoked\", \"expired\"].includes(status)) {\n\t\t\tfilter.status = status as AgentFilter[\"status\"];\n\t\t}\n\t\tif (typeof type === \"string\" && [\"autonomous\", \"delegated\", \"service\"].includes(type)) {\n\t\t\tfilter.type = type as AgentFilter[\"type\"];\n\t\t}\n\t\tkavach.agent\n\t\t\t.list(filter)\n\t\t\t.then((agents) => sendOk(res, agents))\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tconst message = err instanceof Error ? err.message : \"Failed to list agents\";\n\t\t\t\tsendInternalError(res, message);\n\t\t\t});\n\t});\n\n\trouter.get(\"/dashboard/audit\", (req: Request, res: Response) => {\n\t\tconst filter: AuditFilter = {};\n\t\tconst { agentId, userId, since, until, actions, result, limit, offset } = req.query;\n\n\t\tif (typeof agentId === \"string\") filter.agentId = agentId;\n\t\tif (typeof userId === \"string\") filter.userId = userId;\n\t\tif (typeof since === \"string\") {\n\t\t\tconst d = new Date(since);\n\t\t\tif (!Number.isNaN(d.getTime())) filter.since = d;\n\t\t}\n\t\tif (typeof until === \"string\") {\n\t\t\tconst d = new Date(until);\n\t\t\tif (!Number.isNaN(d.getTime())) filter.until = d;\n\t\t}\n\t\tif (typeof actions === \"string\") {\n\t\t\tfilter.actions = actions.split(\",\").map((a) => a.trim());\n\t\t}\n\t\tif (typeof result === \"string\" && [\"allowed\", \"denied\", \"rate_limited\"].includes(result)) {\n\t\t\tfilter.result = result as AuditFilter[\"result\"];\n\t\t}\n\t\tif (typeof limit === \"string\") {\n\t\t\tconst n = Number.parseInt(limit, 10);\n\t\t\tif (!Number.isNaN(n) && n > 0) filter.limit = n;\n\t\t}\n\t\tif (typeof offset === \"string\") {\n\t\t\tconst n = Number.parseInt(offset, 10);\n\t\t\tif (!Number.isNaN(n) && n >= 0) filter.offset = n;\n\t\t}\n\n\t\tkavach.audit\n\t\t\t.query(filter)\n\t\t\t.then((entries) => sendOk(res, entries))\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tconst message = err instanceof Error ? err.message : \"Failed to query audit logs\";\n\t\t\t\tsendInternalError(res, message);\n\t\t\t});\n\t});\n\n\t// ── MCP OAuth 2.1 Endpoints ─────────────────────────────────────\n\n\trouter.options(\"/.well-known/*path\", (_req: Request, res: Response) => {\n\t\tsetMcpCors(res);\n\t\tres.status(204).end();\n\t});\n\n\trouter.options(\"/mcp/*path\", (_req: Request, res: Response) => {\n\t\tsetMcpCors(res);\n\t\tres.status(204).end();\n\t});\n\n\trouter.get(\"/.well-known/oauth-authorization-server\", (_req: Request, res: Response) => {\n\t\tif (!mcp) {\n\t\t\tsendNotFound(res, \"MCP module not configured\");\n\t\t\treturn;\n\t\t}\n\t\tsendMcpOk(res, mcp.getMetadata());\n\t});\n\n\trouter.get(\"/.well-known/oauth-protected-resource\", (_req: Request, res: Response) => {\n\t\tif (!mcp) {\n\t\t\tsendNotFound(res, \"MCP module not configured\");\n\t\t\treturn;\n\t\t}\n\t\tsendMcpOk(res, mcp.getProtectedResourceMetadata());\n\t});\n\n\trouter.post(\"/mcp/register\", (req: Request, res: Response) => {\n\t\tif (!mcp) {\n\t\t\tsendNotFound(res, \"MCP module not configured\");\n\t\t\treturn;\n\t\t}\n\t\tmcp\n\t\t\t.registerClient(req.body as Parameters<typeof mcp.registerClient>[0])\n\t\t\t.then((result) => {\n\t\t\t\tif (!result.success) {\n\t\t\t\t\tsendMcpError(res, \"invalid_client_metadata\", result.error.message, 400);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsendMcpNoStore(res, result.data, 201);\n\t\t\t})\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tconst message = err instanceof Error ? err.message : \"Registration failed\";\n\t\t\t\tsendMcpError(res, \"server_error\", message, 500);\n\t\t\t});\n\t});\n\n\trouter.get(\"/mcp/authorize\", (req: Request, res: Response) => {\n\t\tif (!mcp) {\n\t\t\tsendNotFound(res, \"MCP module not configured\");\n\t\t\treturn;\n\t\t}\n\t\tconst webRequest = buildWebRequest(req);\n\t\tmcp\n\t\t\t.authorize(webRequest)\n\t\t\t.then((result) => {\n\t\t\t\tif (!result.success) {\n\t\t\t\t\tif (result.error.code === \"LOGIN_REQUIRED\") {\n\t\t\t\t\t\tconst details = result.error.details as\n\t\t\t\t\t\t\t| { loginPage?: string; returnTo?: string }\n\t\t\t\t\t\t\t| undefined;\n\t\t\t\t\t\tif (details?.loginPage) {\n\t\t\t\t\t\t\tconst loginUrl = new URL(details.loginPage);\n\t\t\t\t\t\t\tif (details.returnTo) {\n\t\t\t\t\t\t\t\tloginUrl.searchParams.set(\"returnTo\", details.returnTo);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tres.redirect(302, loginUrl.toString());\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tsendMcpError(res, result.error.code.toLowerCase(), result.error.message, 400);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tres.redirect(302, result.data.redirectUri);\n\t\t\t})\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tconst message = err instanceof Error ? err.message : \"Authorization failed\";\n\t\t\t\tsendMcpError(res, \"server_error\", message, 500);\n\t\t\t});\n\t});\n\n\trouter.post(\"/mcp/token\", (req: Request, res: Response) => {\n\t\tif (!mcp) {\n\t\t\tsendNotFound(res, \"MCP module not configured\");\n\t\t\treturn;\n\t\t}\n\t\tconst webRequest = buildWebRequest(req);\n\t\tmcp\n\t\t\t.token(webRequest)\n\t\t\t.then((result) => {\n\t\t\t\tif (!result.success) {\n\t\t\t\t\tconst status = result.error.code === \"INVALID_CLIENT\" ? 401 : 400;\n\t\t\t\t\tsendMcpNoStore(\n\t\t\t\t\t\tres,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\terror: result.error.code.toLowerCase(),\n\t\t\t\t\t\t\terror_description: result.error.message,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tstatus,\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsendMcpNoStore(res, result.data);\n\t\t\t})\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tconst message = err instanceof Error ? err.message : \"Token exchange failed\";\n\t\t\t\tsendMcpNoStore(res, { error: \"server_error\", error_description: message }, 500);\n\t\t\t});\n\t});\n\n\t// ── Plugin Endpoints ────────────────────────────────────────────\n\n\tfor (const endpoint of kavach.plugins.getEndpoints()) {\n\t\tconst method = endpoint.method.toLowerCase() as \"get\" | \"post\" | \"put\" | \"patch\" | \"delete\";\n\t\trouter[method](endpoint.path, (req: Request, res: Response) => {\n\t\t\tconst webReq = buildWebRequest(req);\n\t\t\tkavach.plugins\n\t\t\t\t.handleRequest(webReq)\n\t\t\t\t.then((response) => {\n\t\t\t\t\tif (!response) {\n\t\t\t\t\t\tres.status(404).end();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tres.status(response.status);\n\t\t\t\t\tresponse.headers.forEach((value, key) => {\n\t\t\t\t\t\tres.setHeader(key, value);\n\t\t\t\t\t});\n\t\t\t\t\treturn response.text().then((body) => {\n\t\t\t\t\t\tres.send(body);\n\t\t\t\t\t});\n\t\t\t\t})\n\t\t\t\t.catch((err: unknown) => {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : \"Plugin endpoint error\";\n\t\t\t\t\tsendInternalError(res, message);\n\t\t\t\t});\n\t\t});\n\t}\n\n\treturn router;\n}\n\n// ─── NestJS Middleware Factory ────────────────────────────────────────────────\n\n/**\n * Returns an Express-compatible middleware function that mounts all KavachOS\n * routes. Use this with `app.use()` in your NestJS bootstrap, or register it\n * via `KavachModule.forRoot()`.\n *\n * @example\n * ```typescript\n * // main.ts\n * const app = await NestFactory.create(AppModule);\n * app.use('/api/kavach', kavachMiddleware({ kavach, mcp }));\n * await app.listen(3000);\n * ```\n */\nexport function kavachMiddleware(options: KavachNestjsOptions) {\n\tconst router = buildKavachRouter(options.kavach, options.mcp);\n\treturn (req: Request, res: Response, next: NextFunction) => {\n\t\trouter(req, res, next);\n\t};\n}\n","import type { DynamicModule, MiddlewareConsumer, NestModule } from \"@nestjs/common\";\nimport { Inject, Module } from \"@nestjs/common\";\nimport type { Kavach } from \"kavachos\";\nimport type { McpAuthModule } from \"kavachos/mcp\";\nimport { kavachMiddleware } from \"./adapter.js\";\n\n// ─── Injection Token ──────────────────────────────────────────────────────────\n\nconst KAVACH_OPTIONS = Symbol(\"KAVACH_OPTIONS\");\n\n// ─── Module Options ───────────────────────────────────────────────────────────\n\nexport interface KavachModuleOptions {\n\t/** The Kavach instance created with `createKavach()` */\n\tkavach: Kavach;\n\t/** Optional MCP OAuth 2.1 module created with `createMcpModule()` */\n\tmcp?: McpAuthModule;\n\t/**\n\t * The path prefix where KavachOS routes will be mounted.\n\t * @default '/api/kavach'\n\t */\n\tbasePath?: string;\n}\n\n// ─── KavachModule ─────────────────────────────────────────────────────────────\n\n/**\n * NestJS dynamic module that mounts all KavachOS REST routes as Express\n * middleware. Import it once in your root `AppModule`.\n *\n * @example\n * ```typescript\n * // app.module.ts\n * import { Module } from '@nestjs/common';\n * import { KavachModule } from '@kavachos/nestjs';\n * import { kavach, mcp } from './lib/kavach.js';\n *\n * @Module({\n * imports: [\n * KavachModule.forRoot({ kavach, mcp, basePath: '/api/kavach' }),\n * ],\n * })\n * export class AppModule {}\n * ```\n */\n@Module({})\nexport class KavachModule implements NestModule {\n\tconstructor(\n\t\t@Inject(KAVACH_OPTIONS)\n\t\tprivate readonly options: KavachModuleOptions,\n\t) {}\n\n\tconfigure(consumer: MiddlewareConsumer): void {\n\t\tconst basePath = this.options.basePath ?? \"/api/kavach\";\n\t\tconsumer\n\t\t\t.apply(\n\t\t\t\tkavachMiddleware({\n\t\t\t\t\tkavach: this.options.kavach,\n\t\t\t\t\tmcp: this.options.mcp,\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.forRoutes(`${basePath}/*path`);\n\t}\n\n\tstatic forRoot(options: KavachModuleOptions): DynamicModule {\n\t\treturn {\n\t\t\tmodule: KavachModule,\n\t\t\tproviders: [\n\t\t\t\t{\n\t\t\t\t\tprovide: KAVACH_OPTIONS,\n\t\t\t\t\tuseValue: options,\n\t\t\t\t},\n\t\t\t],\n\t\t};\n\t}\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kavachos/nestjs",
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"description": "NestJS adapter for KavachOS",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"keywords": [
|
|
18
|
+
"kavachos",
|
|
19
|
+
"nestjs",
|
|
20
|
+
"auth",
|
|
21
|
+
"agent",
|
|
22
|
+
"mcp"
|
|
23
|
+
],
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"author": "KavachOS <hello@kavachos.com>",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "https://github.com/kavachos/kavachos.git",
|
|
29
|
+
"directory": "packages/adapters/nestjs"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"@nestjs/common": ">=10.0.0",
|
|
33
|
+
"@nestjs/core": ">=10.0.0",
|
|
34
|
+
"zod": ">=3.0.0",
|
|
35
|
+
"kavachos": "0.0.3"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@nestjs/common": "^11.0.0",
|
|
39
|
+
"@nestjs/core": "^11.0.0",
|
|
40
|
+
"@types/express": "^5.0.0",
|
|
41
|
+
"reflect-metadata": "^0.2.0",
|
|
42
|
+
"rxjs": "^7.0.0",
|
|
43
|
+
"tsup": "^8.4.0",
|
|
44
|
+
"typescript": "^5.8.0",
|
|
45
|
+
"zod": "^3.24.0",
|
|
46
|
+
"kavachos": "0.0.3"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "tsup",
|
|
50
|
+
"typecheck": "tsc --noEmit"
|
|
51
|
+
}
|
|
52
|
+
}
|