@backendkit-labs/agent-web 0.1.0 → 0.4.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/dist/auth/JwtAuth.d.ts +42 -0
- package/dist/auth/JwtAuth.d.ts.map +1 -0
- package/dist/auth/JwtAuth.js +69 -0
- package/dist/auth/JwtAuth.js.map +1 -0
- package/dist/index.d.ts +10 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -1
- package/dist/index.js.map +1 -1
- package/dist/metrics/MetricsCollector.d.ts +46 -0
- package/dist/metrics/MetricsCollector.d.ts.map +1 -0
- package/dist/metrics/MetricsCollector.js +95 -0
- package/dist/metrics/MetricsCollector.js.map +1 -0
- package/dist/server/AgentServer.d.ts +46 -2
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +37 -4
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/routes.d.ts +2 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +20 -5
- package/dist/server/routes.js.map +1 -1
- package/dist/session/SessionManager.d.ts +12 -2
- package/dist/session/SessionManager.d.ts.map +1 -1
- package/dist/session/SessionManager.js +29 -6
- package/dist/session/SessionManager.js.map +1 -1
- package/dist/store/SessionMetaStore.d.ts +46 -0
- package/dist/store/SessionMetaStore.d.ts.map +1 -0
- package/dist/store/SessionMetaStore.js +72 -0
- package/dist/store/SessionMetaStore.js.map +1 -0
- package/dist/transport/HeadlessTransport.d.ts +21 -0
- package/dist/transport/HeadlessTransport.d.ts.map +1 -0
- package/dist/transport/HeadlessTransport.js +42 -0
- package/dist/transport/HeadlessTransport.js.map +1 -0
- package/dist/trigger/TriggerBus.d.ts +129 -0
- package/dist/trigger/TriggerBus.d.ts.map +1 -0
- package/dist/trigger/TriggerBus.js +249 -0
- package/dist/trigger/TriggerBus.js.map +1 -0
- package/package.json +11 -1
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import jwt from 'jsonwebtoken';
|
|
2
|
+
import type { AuthHook } from '../server/AgentServer';
|
|
3
|
+
export interface JwtAuthOptions {
|
|
4
|
+
/** Symmetric secret for HS256/HS384/HS512. */
|
|
5
|
+
secret?: string;
|
|
6
|
+
/** PEM public key for RS256/ES256 etc. */
|
|
7
|
+
publicKey?: string;
|
|
8
|
+
algorithms?: jwt.Algorithm[];
|
|
9
|
+
audience?: string | RegExp | string[];
|
|
10
|
+
issuer?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface AuthUser {
|
|
13
|
+
sub: string;
|
|
14
|
+
email?: string;
|
|
15
|
+
roles?: string[];
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
}
|
|
18
|
+
declare module 'fastify' {
|
|
19
|
+
interface FastifyRequest {
|
|
20
|
+
user?: AuthUser;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* JWT authentication helper.
|
|
25
|
+
*
|
|
26
|
+
* Reads the token from:
|
|
27
|
+
* 1. Authorization: Bearer <token> header (REST / MCP)
|
|
28
|
+
* 2. ?token=<jwt> query param (browser WebSocket — can't set headers)
|
|
29
|
+
*
|
|
30
|
+
* Usage:
|
|
31
|
+
* const server = new AgentServer({
|
|
32
|
+
* auth: new JwtAuth({ secret: process.env.JWT_SECRET! }).hook(),
|
|
33
|
+
* ...
|
|
34
|
+
* });
|
|
35
|
+
*/
|
|
36
|
+
export declare class JwtAuth {
|
|
37
|
+
private readonly opts;
|
|
38
|
+
constructor(opts: JwtAuthOptions);
|
|
39
|
+
hook(): AuthHook;
|
|
40
|
+
verify(token: string): AuthUser;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=JwtAuth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JwtAuth.d.ts","sourceRoot":"","sources":["../../src/auth/JwtAuth.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,cAAc,CAAC;AAE/B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC3B,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,QAAQ;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAGD,OAAO,QAAQ,SAAS,CAAC;IACrB,UAAU,cAAc;QACpB,IAAI,CAAC,EAAE,QAAQ,CAAC;KACnB;CACJ;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,OAAO;IACJ,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,cAAc;IAMjD,IAAI,IAAI,QAAQ;IAehB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ;CAalC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.JwtAuth = void 0;
|
|
7
|
+
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
8
|
+
/**
|
|
9
|
+
* JWT authentication helper.
|
|
10
|
+
*
|
|
11
|
+
* Reads the token from:
|
|
12
|
+
* 1. Authorization: Bearer <token> header (REST / MCP)
|
|
13
|
+
* 2. ?token=<jwt> query param (browser WebSocket — can't set headers)
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
* const server = new AgentServer({
|
|
17
|
+
* auth: new JwtAuth({ secret: process.env.JWT_SECRET! }).hook(),
|
|
18
|
+
* ...
|
|
19
|
+
* });
|
|
20
|
+
*/
|
|
21
|
+
class JwtAuth {
|
|
22
|
+
opts;
|
|
23
|
+
constructor(opts) {
|
|
24
|
+
this.opts = opts;
|
|
25
|
+
if (!opts.secret && !opts.publicKey) {
|
|
26
|
+
throw new Error('JwtAuth: provide either secret (HS*) or publicKey (RS*/ES*)');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
hook() {
|
|
30
|
+
return async (req, reply) => {
|
|
31
|
+
const token = extractToken(req);
|
|
32
|
+
if (!token) {
|
|
33
|
+
reply.code(401).send({ error: 'Missing authentication token' });
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
req.user = this.verify(token);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
reply.code(401).send({ error: 'Invalid or expired token' });
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
verify(token) {
|
|
45
|
+
const key = (this.opts.secret ?? this.opts.publicKey);
|
|
46
|
+
const payload = jsonwebtoken_1.default.verify(token, key, {
|
|
47
|
+
algorithms: this.opts.algorithms,
|
|
48
|
+
// Cast required: jwt.VerifyOptions.audience is a variadic tuple type
|
|
49
|
+
audience: this.opts.audience,
|
|
50
|
+
issuer: this.opts.issuer,
|
|
51
|
+
});
|
|
52
|
+
if (typeof payload !== 'object' || !payload) {
|
|
53
|
+
throw new Error('Unexpected JWT payload type');
|
|
54
|
+
}
|
|
55
|
+
return payload;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.JwtAuth = JwtAuth;
|
|
59
|
+
function extractToken(req) {
|
|
60
|
+
const auth = req.headers.authorization;
|
|
61
|
+
if (auth?.startsWith('Bearer '))
|
|
62
|
+
return auth.slice(7);
|
|
63
|
+
// Browser WebSocket can't set headers — fall back to query param
|
|
64
|
+
const query = req.query;
|
|
65
|
+
if (typeof query.token === 'string' && query.token)
|
|
66
|
+
return query.token;
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=JwtAuth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JwtAuth.js","sourceRoot":"","sources":["../../src/auth/JwtAuth.ts"],"names":[],"mappings":";;;;;;AAAA,gEAA+B;AA4B/B;;;;;;;;;;;;GAYG;AACH,MAAa,OAAO;IACa;IAA7B,YAA6B,IAAoB;QAApB,SAAI,GAAJ,IAAI,CAAgB;QAC7C,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;QACnF,CAAC;IACL,CAAC;IAED,IAAI;QACA,OAAO,KAAK,EAAE,GAAmB,EAAE,KAAmB,EAAiB,EAAE;YACrE,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;YAChC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACT,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,8BAA8B,EAAE,CAAC,CAAC;gBAChE,OAAO;YACX,CAAC;YACD,IAAI,CAAC;gBACD,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAClC,CAAC;YAAC,MAAM,CAAC;gBACL,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC,CAAC;YAChE,CAAC;QACL,CAAC,CAAC;IACN,CAAC;IAED,MAAM,CAAC,KAAa;QAChB,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAE,CAAC;QACvD,MAAM,OAAO,GAAG,sBAAG,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,EAAE;YACnC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU;YAChC,qEAAqE;YACrE,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,QAAyC;YAC7D,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM;SAC3B,CAAC,CAAC;QACH,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,OAAO,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QACnD,CAAC;QACD,OAAO,OAAmB,CAAC;IAC/B,CAAC;CACJ;AAnCD,0BAmCC;AAED,SAAS,YAAY,CAAC,GAAmB;IACrC,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC;IACvC,IAAI,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACtD,iEAAiE;IACjE,MAAM,KAAK,GAAG,GAAG,CAAC,KAA+B,CAAC;IAClD,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC,KAAK,CAAC;IACvE,OAAO,IAAI,CAAC;AAChB,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
export { AgentServer } from './server/AgentServer';
|
|
2
|
-
export type { AgentServerOptions, AuthHook } from './server/AgentServer';
|
|
2
|
+
export type { AgentServerOptions, AuthHook, RateLimitOptions, MetricsOptions } from './server/AgentServer';
|
|
3
3
|
export { SessionManager } from './session/SessionManager';
|
|
4
4
|
export type { Session, SessionManagerOptions, EngineFactory } from './session/SessionManager';
|
|
5
5
|
export { WebSocketTransport } from './transport/WebSocketTransport';
|
|
6
6
|
export type { WsMessage } from './transport/WebSocketTransport';
|
|
7
7
|
export { MonitorBus } from './monitor/MonitorBus';
|
|
8
8
|
export type { MonitorFrame } from './monitor/MonitorBus';
|
|
9
|
+
export { JwtAuth } from './auth/JwtAuth';
|
|
10
|
+
export type { JwtAuthOptions, AuthUser } from './auth/JwtAuth';
|
|
11
|
+
export { MetricsCollector } from './metrics/MetricsCollector';
|
|
12
|
+
export type { MetricsCollectorOptions, RunEndFn } from './metrics/MetricsCollector';
|
|
13
|
+
export { InMemorySessionMetaStore, RedisSessionMetaStore } from './store/SessionMetaStore';
|
|
14
|
+
export type { SessionMeta, SessionMetaStore, RedisLike } from './store/SessionMetaStore';
|
|
15
|
+
export { TriggerBus } from './trigger/TriggerBus';
|
|
16
|
+
export type { TriggerEngineFactory, TriggerDefinition, TriggerResult, CronTriggerDef, WebhookTriggerDef, QueueTriggerDef, QueueConnection, } from './trigger/TriggerBus';
|
|
17
|
+
export { HeadlessTransport } from './transport/HeadlessTransport';
|
|
9
18
|
//# sourceMappingURL=index.d.ts.map
|
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,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,YAAY,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,YAAY,EAAE,kBAAkB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3G,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,YAAY,EAAE,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9F,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,YAAY,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAEhE,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGzD,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,YAAY,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,YAAY,EAAE,uBAAuB,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAGpF,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAC3F,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAGzF,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,YAAY,EACR,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,eAAe,GAClB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MonitorBus = exports.WebSocketTransport = exports.SessionManager = exports.AgentServer = void 0;
|
|
3
|
+
exports.HeadlessTransport = exports.TriggerBus = exports.RedisSessionMetaStore = exports.InMemorySessionMetaStore = exports.MetricsCollector = exports.JwtAuth = exports.MonitorBus = exports.WebSocketTransport = exports.SessionManager = exports.AgentServer = void 0;
|
|
4
4
|
var AgentServer_1 = require("./server/AgentServer");
|
|
5
5
|
Object.defineProperty(exports, "AgentServer", { enumerable: true, get: function () { return AgentServer_1.AgentServer; } });
|
|
6
6
|
var SessionManager_1 = require("./session/SessionManager");
|
|
@@ -9,4 +9,19 @@ var WebSocketTransport_1 = require("./transport/WebSocketTransport");
|
|
|
9
9
|
Object.defineProperty(exports, "WebSocketTransport", { enumerable: true, get: function () { return WebSocketTransport_1.WebSocketTransport; } });
|
|
10
10
|
var MonitorBus_1 = require("./monitor/MonitorBus");
|
|
11
11
|
Object.defineProperty(exports, "MonitorBus", { enumerable: true, get: function () { return MonitorBus_1.MonitorBus; } });
|
|
12
|
+
// ── Auth ──────────────────────────────────────────────────────────────────────
|
|
13
|
+
var JwtAuth_1 = require("./auth/JwtAuth");
|
|
14
|
+
Object.defineProperty(exports, "JwtAuth", { enumerable: true, get: function () { return JwtAuth_1.JwtAuth; } });
|
|
15
|
+
// ── Metrics ───────────────────────────────────────────────────────────────────
|
|
16
|
+
var MetricsCollector_1 = require("./metrics/MetricsCollector");
|
|
17
|
+
Object.defineProperty(exports, "MetricsCollector", { enumerable: true, get: function () { return MetricsCollector_1.MetricsCollector; } });
|
|
18
|
+
// ── Session store ─────────────────────────────────────────────────────────────
|
|
19
|
+
var SessionMetaStore_1 = require("./store/SessionMetaStore");
|
|
20
|
+
Object.defineProperty(exports, "InMemorySessionMetaStore", { enumerable: true, get: function () { return SessionMetaStore_1.InMemorySessionMetaStore; } });
|
|
21
|
+
Object.defineProperty(exports, "RedisSessionMetaStore", { enumerable: true, get: function () { return SessionMetaStore_1.RedisSessionMetaStore; } });
|
|
22
|
+
// ── Trigger bus ───────────────────────────────────────────────────────────────
|
|
23
|
+
var TriggerBus_1 = require("./trigger/TriggerBus");
|
|
24
|
+
Object.defineProperty(exports, "TriggerBus", { enumerable: true, get: function () { return TriggerBus_1.TriggerBus; } });
|
|
25
|
+
var HeadlessTransport_1 = require("./transport/HeadlessTransport");
|
|
26
|
+
Object.defineProperty(exports, "HeadlessTransport", { enumerable: true, get: function () { return HeadlessTransport_1.HeadlessTransport; } });
|
|
12
27
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,oDAAmD;AAA1C,0GAAA,WAAW,OAAA;AAGpB,2DAA0D;AAAjD,gHAAA,cAAc,OAAA;AAGvB,qEAAoE;AAA3D,wHAAA,kBAAkB,OAAA;AAG3B,mDAAkD;AAAzC,wGAAA,UAAU,OAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,oDAAmD;AAA1C,0GAAA,WAAW,OAAA;AAGpB,2DAA0D;AAAjD,gHAAA,cAAc,OAAA;AAGvB,qEAAoE;AAA3D,wHAAA,kBAAkB,OAAA;AAG3B,mDAAkD;AAAzC,wGAAA,UAAU,OAAA;AAGnB,iFAAiF;AACjF,0CAAyC;AAAhC,kGAAA,OAAO,OAAA;AAGhB,iFAAiF;AACjF,+DAA8D;AAArD,oHAAA,gBAAgB,OAAA;AAGzB,iFAAiF;AACjF,6DAA2F;AAAlF,4HAAA,wBAAwB,OAAA;AAAE,yHAAA,qBAAqB,OAAA;AAGxD,iFAAiF;AACjF,mDAAkD;AAAzC,wGAAA,UAAU,OAAA;AAWnB,mEAAkE;AAAzD,sHAAA,iBAAiB,OAAA"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export interface MetricsCollectorOptions {
|
|
2
|
+
/** Prefix for all metric names. Default: 'bk'. */
|
|
3
|
+
prefix?: string;
|
|
4
|
+
/** Include Node.js default metrics (memory, CPU, GC). Default: true. */
|
|
5
|
+
collectNodeMetrics?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export type RunEndFn = (status?: 'success' | 'error') => void;
|
|
8
|
+
/**
|
|
9
|
+
* Prometheus metrics collector for AgentServer.
|
|
10
|
+
*
|
|
11
|
+
* Exposes:
|
|
12
|
+
* {prefix}_sessions_active — gauge: live WebSocket sessions
|
|
13
|
+
* {prefix}_sessions_total — counter: all sessions created
|
|
14
|
+
* {prefix}_messages_total — counter: user input messages received
|
|
15
|
+
* {prefix}_runs_total{status} — counter: agent runs by status (success|error)
|
|
16
|
+
* {prefix}_run_duration_seconds — histogram: agent run wall time
|
|
17
|
+
*
|
|
18
|
+
* Usage:
|
|
19
|
+
* const server = new AgentServer({
|
|
20
|
+
* metrics: { enabled: true }, // exposes GET /metrics
|
|
21
|
+
* ...
|
|
22
|
+
* });
|
|
23
|
+
*/
|
|
24
|
+
export declare class MetricsCollector {
|
|
25
|
+
private readonly registry;
|
|
26
|
+
private readonly sessionsActive;
|
|
27
|
+
private readonly sessionsTotal;
|
|
28
|
+
private readonly messagesTotal;
|
|
29
|
+
private readonly runsTotal;
|
|
30
|
+
private readonly runDuration;
|
|
31
|
+
constructor(opts?: MetricsCollectorOptions);
|
|
32
|
+
sessionOpened(): void;
|
|
33
|
+
sessionClosed(): void;
|
|
34
|
+
messageReceived(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Call at the start of a run. Returns a finish function to call when done.
|
|
37
|
+
*
|
|
38
|
+
* const finish = metrics.runStarted();
|
|
39
|
+
* try { await engine.run(input); finish(); }
|
|
40
|
+
* catch { finish('error'); }
|
|
41
|
+
*/
|
|
42
|
+
runStarted(): RunEndFn;
|
|
43
|
+
collect(): Promise<string>;
|
|
44
|
+
get contentType(): string;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=MetricsCollector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MetricsCollector.d.ts","sourceRoot":"","sources":["../../src/metrics/MetricsCollector.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,uBAAuB;IACpC,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,MAAM,MAAM,QAAQ,GAAG,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,OAAO,KAAK,IAAI,CAAC;AAE9D;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,gBAAgB;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;IACpC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAQ;IACvC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;IACxC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;IACxC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;IACpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAY;gBAE5B,IAAI,GAAE,uBAA4B;IAyC9C,aAAa,IAAI,IAAI;IAKrB,aAAa,IAAI,IAAI;IAIrB,eAAe,IAAI,IAAI;IAIvB;;;;;;OAMG;IACH,UAAU,IAAI,QAAQ;IAShB,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;IAIhC,IAAI,WAAW,IAAI,MAAM,CAExB;CACJ"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MetricsCollector = void 0;
|
|
4
|
+
const prom_client_1 = require("prom-client");
|
|
5
|
+
/**
|
|
6
|
+
* Prometheus metrics collector for AgentServer.
|
|
7
|
+
*
|
|
8
|
+
* Exposes:
|
|
9
|
+
* {prefix}_sessions_active — gauge: live WebSocket sessions
|
|
10
|
+
* {prefix}_sessions_total — counter: all sessions created
|
|
11
|
+
* {prefix}_messages_total — counter: user input messages received
|
|
12
|
+
* {prefix}_runs_total{status} — counter: agent runs by status (success|error)
|
|
13
|
+
* {prefix}_run_duration_seconds — histogram: agent run wall time
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
* const server = new AgentServer({
|
|
17
|
+
* metrics: { enabled: true }, // exposes GET /metrics
|
|
18
|
+
* ...
|
|
19
|
+
* });
|
|
20
|
+
*/
|
|
21
|
+
class MetricsCollector {
|
|
22
|
+
registry;
|
|
23
|
+
sessionsActive;
|
|
24
|
+
sessionsTotal;
|
|
25
|
+
messagesTotal;
|
|
26
|
+
runsTotal;
|
|
27
|
+
runDuration;
|
|
28
|
+
constructor(opts = {}) {
|
|
29
|
+
const prefix = opts.prefix ?? 'bk';
|
|
30
|
+
this.registry = new prom_client_1.Registry();
|
|
31
|
+
if (opts.collectNodeMetrics !== false) {
|
|
32
|
+
(0, prom_client_1.collectDefaultMetrics)({ register: this.registry, prefix: `${prefix}_node_` });
|
|
33
|
+
}
|
|
34
|
+
this.sessionsActive = new prom_client_1.Gauge({
|
|
35
|
+
name: `${prefix}_sessions_active`,
|
|
36
|
+
help: 'Number of currently active WebSocket sessions',
|
|
37
|
+
registers: [this.registry],
|
|
38
|
+
});
|
|
39
|
+
this.sessionsTotal = new prom_client_1.Counter({
|
|
40
|
+
name: `${prefix}_sessions_total`,
|
|
41
|
+
help: 'Total WebSocket sessions created since startup',
|
|
42
|
+
registers: [this.registry],
|
|
43
|
+
});
|
|
44
|
+
this.messagesTotal = new prom_client_1.Counter({
|
|
45
|
+
name: `${prefix}_messages_total`,
|
|
46
|
+
help: 'Total user input messages received',
|
|
47
|
+
registers: [this.registry],
|
|
48
|
+
});
|
|
49
|
+
this.runsTotal = new prom_client_1.Counter({
|
|
50
|
+
name: `${prefix}_runs_total`,
|
|
51
|
+
help: 'Total agent runs executed',
|
|
52
|
+
labelNames: ['status'],
|
|
53
|
+
registers: [this.registry],
|
|
54
|
+
});
|
|
55
|
+
this.runDuration = new prom_client_1.Histogram({
|
|
56
|
+
name: `${prefix}_run_duration_seconds`,
|
|
57
|
+
help: 'Agent run duration in seconds',
|
|
58
|
+
buckets: [0.1, 0.5, 1, 2, 5, 10, 30, 60],
|
|
59
|
+
registers: [this.registry],
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
sessionOpened() {
|
|
63
|
+
this.sessionsActive.inc();
|
|
64
|
+
this.sessionsTotal.inc();
|
|
65
|
+
}
|
|
66
|
+
sessionClosed() {
|
|
67
|
+
this.sessionsActive.dec();
|
|
68
|
+
}
|
|
69
|
+
messageReceived() {
|
|
70
|
+
this.messagesTotal.inc();
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Call at the start of a run. Returns a finish function to call when done.
|
|
74
|
+
*
|
|
75
|
+
* const finish = metrics.runStarted();
|
|
76
|
+
* try { await engine.run(input); finish(); }
|
|
77
|
+
* catch { finish('error'); }
|
|
78
|
+
*/
|
|
79
|
+
runStarted() {
|
|
80
|
+
const startMs = Date.now();
|
|
81
|
+
return (status = 'success') => {
|
|
82
|
+
const durationSec = (Date.now() - startMs) / 1000;
|
|
83
|
+
this.runsTotal.labels(status).inc();
|
|
84
|
+
this.runDuration.observe(durationSec);
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
async collect() {
|
|
88
|
+
return this.registry.metrics();
|
|
89
|
+
}
|
|
90
|
+
get contentType() {
|
|
91
|
+
return this.registry.contentType;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
exports.MetricsCollector = MetricsCollector;
|
|
95
|
+
//# sourceMappingURL=MetricsCollector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MetricsCollector.js","sourceRoot":"","sources":["../../src/metrics/MetricsCollector.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,8 +2,23 @@ import type { FastifyRequest, FastifyReply } from 'fastify';
|
|
|
2
2
|
import { SessionManager } from '../session/SessionManager';
|
|
3
3
|
import type { SessionManagerOptions } from '../session/SessionManager';
|
|
4
4
|
import { MonitorBus } from '../monitor/MonitorBus';
|
|
5
|
+
import type { MetricsCollectorOptions } from '../metrics/MetricsCollector';
|
|
6
|
+
import type { SessionMetaStore } from '../store/SessionMetaStore';
|
|
7
|
+
import type { TriggerBus } from '../trigger/TriggerBus';
|
|
5
8
|
export type AuthHook = (req: FastifyRequest, reply: FastifyReply) => Promise<void>;
|
|
6
|
-
export interface
|
|
9
|
+
export interface RateLimitOptions {
|
|
10
|
+
/** Max requests per IP per time window. Default: 100. */
|
|
11
|
+
max?: number;
|
|
12
|
+
/** Time window string (e.g. '1 minute', '30 seconds'). Default: '1 minute'. */
|
|
13
|
+
timeWindow?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface MetricsOptions extends MetricsCollectorOptions {
|
|
16
|
+
/** Enable Prometheus /metrics endpoint. Default: false. */
|
|
17
|
+
enabled: boolean;
|
|
18
|
+
/** Path for the metrics endpoint. Default: '/metrics'. */
|
|
19
|
+
path?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface AgentServerOptions extends Omit<SessionManagerOptions, 'metrics' | 'store'> {
|
|
7
22
|
/** TCP port to listen on. Default: 3000. */
|
|
8
23
|
port?: number;
|
|
9
24
|
/** Host to bind to. Default: '0.0.0.0'. */
|
|
@@ -14,16 +29,45 @@ export interface AgentServerOptions extends SessionManagerOptions {
|
|
|
14
29
|
logger?: boolean | object;
|
|
15
30
|
/** Allowed CORS origins. Default: '*'. */
|
|
16
31
|
cors?: string | string[];
|
|
32
|
+
/**
|
|
33
|
+
* Rate limiting per IP. Requires @fastify/rate-limit to be installed.
|
|
34
|
+
* @example { max: 60, timeWindow: '1 minute' }
|
|
35
|
+
*/
|
|
36
|
+
rateLimiting?: RateLimitOptions;
|
|
37
|
+
/**
|
|
38
|
+
* Prometheus metrics. Requires prom-client to be installed.
|
|
39
|
+
* @example { enabled: true, path: '/metrics' }
|
|
40
|
+
*/
|
|
41
|
+
metrics?: MetricsOptions;
|
|
42
|
+
/**
|
|
43
|
+
* Durable store for session metadata (Redis, etc.).
|
|
44
|
+
* Default: in-memory (no persistence).
|
|
45
|
+
*/
|
|
46
|
+
store?: SessionMetaStore;
|
|
47
|
+
/**
|
|
48
|
+
* Optional TriggerBus — registers webhook routes on this server and
|
|
49
|
+
* starts cron jobs when start() is called.
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* const triggers = new TriggerBus(engineFactory)
|
|
53
|
+
* .addCron({ schedule: '0 9 * * 1-5', name: 'report', buildPrompt: () => '...' });
|
|
54
|
+
* new AgentServer({ triggers, ... });
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
triggers?: TriggerBus;
|
|
17
58
|
}
|
|
18
59
|
export declare class AgentServer {
|
|
19
60
|
private app;
|
|
20
61
|
private sessions;
|
|
21
62
|
private readonly monitor;
|
|
22
|
-
private readonly
|
|
63
|
+
private readonly collector;
|
|
64
|
+
private readonly triggerBus;
|
|
65
|
+
private readonly _port;
|
|
23
66
|
private readonly host;
|
|
24
67
|
constructor(opts: AgentServerOptions);
|
|
25
68
|
start(): Promise<string>;
|
|
26
69
|
stop(): Promise<void>;
|
|
70
|
+
get port(): number;
|
|
27
71
|
get sessionManager(): SessionManager;
|
|
28
72
|
get monitorBus(): MonitorBus;
|
|
29
73
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentServer.d.ts","sourceRoot":"","sources":["../../src/server/AgentServer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAmB,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"AgentServer.d.ts","sourceRoot":"","sources":["../../src/server/AgentServer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAmB,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAC3E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAGxD,MAAM,MAAM,QAAQ,GAAG,CAAC,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnF,MAAM,WAAW,gBAAgB;IAC7B,yDAAyD;IACzD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAe,SAAQ,uBAAuB;IAC3D,2DAA2D;IAC3D,OAAO,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAAC,qBAAqB,EAAE,SAAS,GAAG,OAAO,CAAC;IACxF,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,iFAAiF;IACjF,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC1B,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACzB;;;OAGG;IACH,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC;;;OAGG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB;;;OAGG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,UAAU,CAAC;CACzB;AAED,qBAAa,WAAW;IACpB,OAAO,CAAC,GAAG,CAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA+B;IACzD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyB;IACpD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;gBAElB,IAAI,EAAE,kBAAkB;IAsE9B,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAMxB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAM3B,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,IAAI,cAAc,IAAI,cAAc,CAEnC;IAED,IAAI,UAAU,IAAI,UAAU,CAE3B;CACJ"}
|
|
@@ -8,22 +8,31 @@ const fastify_1 = __importDefault(require("fastify"));
|
|
|
8
8
|
const websocket_1 = __importDefault(require("@fastify/websocket"));
|
|
9
9
|
const SessionManager_1 = require("../session/SessionManager");
|
|
10
10
|
const MonitorBus_1 = require("../monitor/MonitorBus");
|
|
11
|
+
const MetricsCollector_1 = require("../metrics/MetricsCollector");
|
|
11
12
|
const routes_1 = require("./routes");
|
|
12
13
|
class AgentServer {
|
|
13
14
|
app;
|
|
14
15
|
sessions;
|
|
15
16
|
monitor;
|
|
16
|
-
|
|
17
|
+
collector;
|
|
18
|
+
triggerBus;
|
|
19
|
+
_port;
|
|
17
20
|
host;
|
|
18
21
|
constructor(opts) {
|
|
19
|
-
this.
|
|
22
|
+
this._port = opts.port ?? 3000;
|
|
20
23
|
this.host = opts.host ?? '0.0.0.0';
|
|
21
24
|
this.monitor = new MonitorBus_1.MonitorBus();
|
|
25
|
+
this.triggerBus = opts.triggers;
|
|
26
|
+
this.collector = opts.metrics?.enabled
|
|
27
|
+
? new MetricsCollector_1.MetricsCollector({ prefix: opts.metrics.prefix, collectNodeMetrics: opts.metrics.collectNodeMetrics })
|
|
28
|
+
: undefined;
|
|
22
29
|
this.sessions = new SessionManager_1.SessionManager({
|
|
23
30
|
engineFactory: opts.engineFactory,
|
|
24
31
|
maxIdleMs: opts.maxIdleMs,
|
|
25
32
|
maxSessions: opts.maxSessions,
|
|
26
33
|
monitorBus: this.monitor,
|
|
34
|
+
metrics: this.collector,
|
|
35
|
+
store: opts.store,
|
|
27
36
|
});
|
|
28
37
|
this.app = (0, fastify_1.default)({ logger: opts.logger ?? false });
|
|
29
38
|
// CORS headers
|
|
@@ -39,6 +48,21 @@ class AgentServer {
|
|
|
39
48
|
reply.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
40
49
|
reply.code(204).send();
|
|
41
50
|
});
|
|
51
|
+
// Rate limiting (optional dep)
|
|
52
|
+
if (opts.rateLimiting) {
|
|
53
|
+
const rl = opts.rateLimiting;
|
|
54
|
+
try {
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
56
|
+
const rateLimitPlugin = require('@fastify/rate-limit');
|
|
57
|
+
void this.app.register(rateLimitPlugin, {
|
|
58
|
+
max: rl.max ?? 100,
|
|
59
|
+
timeWindow: rl.timeWindow ?? '1 minute',
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
console.warn('[agent-web] @fastify/rate-limit not found — rate limiting disabled. Run: npm i @fastify/rate-limit');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
42
66
|
if (opts.auth) {
|
|
43
67
|
const authHook = opts.auth;
|
|
44
68
|
this.app.addHook('preHandler', authHook);
|
|
@@ -47,19 +71,28 @@ class AgentServer {
|
|
|
47
71
|
// resolves the plugin before wiring routes (required for WS routes in v11).
|
|
48
72
|
const sessions = this.sessions;
|
|
49
73
|
const monitor = this.monitor;
|
|
74
|
+
const collector = this.collector;
|
|
75
|
+
const metricsPath = opts.metrics?.path;
|
|
76
|
+
const triggers = this.triggerBus;
|
|
50
77
|
this.app.register(async (instance) => {
|
|
51
78
|
await instance.register(websocket_1.default);
|
|
52
|
-
(0, routes_1.registerRoutes)(instance, sessions, monitor);
|
|
79
|
+
(0, routes_1.registerRoutes)(instance, sessions, monitor, collector, metricsPath);
|
|
80
|
+
triggers?.registerRoutes(instance);
|
|
53
81
|
});
|
|
54
82
|
}
|
|
55
83
|
async start() {
|
|
56
|
-
|
|
84
|
+
this.triggerBus?.start();
|
|
85
|
+
const address = await this.app.listen({ port: this._port, host: this.host });
|
|
57
86
|
return address;
|
|
58
87
|
}
|
|
59
88
|
async stop() {
|
|
89
|
+
await this.triggerBus?.close();
|
|
60
90
|
this.sessions.close();
|
|
61
91
|
await this.app.close();
|
|
62
92
|
}
|
|
93
|
+
get port() {
|
|
94
|
+
return this._port;
|
|
95
|
+
}
|
|
63
96
|
get sessionManager() {
|
|
64
97
|
return this.sessions;
|
|
65
98
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentServer.js","sourceRoot":"","sources":["../../src/server/AgentServer.ts"],"names":[],"mappings":";;;;;;AAAA,sDAA8B;AAC9B,mEAAkD;AAElD,8DAA2D;AAE3D,sDAAmD;AACnD,qCAA0C;
|
|
1
|
+
{"version":3,"file":"AgentServer.js","sourceRoot":"","sources":["../../src/server/AgentServer.ts"],"names":[],"mappings":"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"}
|
package/dist/server/routes.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { FastifyInstance } from 'fastify';
|
|
2
2
|
import type { SessionManager } from '../session/SessionManager';
|
|
3
3
|
import type { MonitorBus } from '../monitor/MonitorBus';
|
|
4
|
-
|
|
4
|
+
import type { MetricsCollector } from '../metrics/MetricsCollector';
|
|
5
|
+
export declare function registerRoutes(app: FastifyInstance, sessions: SessionManager, monitorBus?: MonitorBus, metrics?: MetricsCollector, metricsPath?: string): void;
|
|
5
6
|
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/server/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/server/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAEpE,wBAAgB,cAAc,CAC1B,GAAG,EAAE,eAAe,EACpB,QAAQ,EAAE,cAAc,EACxB,UAAU,CAAC,EAAE,UAAU,EACvB,OAAO,CAAC,EAAE,gBAAgB,EAC1B,WAAW,CAAC,EAAE,MAAM,GACrB,IAAI,CAiGN"}
|
package/dist/server/routes.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.registerRoutes = registerRoutes;
|
|
4
|
-
function registerRoutes(app, sessions, monitorBus) {
|
|
4
|
+
function registerRoutes(app, sessions, monitorBus, metrics, metricsPath) {
|
|
5
5
|
// ── Health ────────────────────────────────────────────────────────────────
|
|
6
6
|
app.get('/health', async () => ({
|
|
7
7
|
status: 'ok',
|
|
@@ -9,6 +9,14 @@ function registerRoutes(app, sessions, monitorBus) {
|
|
|
9
9
|
monitors: monitorBus?.size ?? 0,
|
|
10
10
|
timestamp: new Date().toISOString(),
|
|
11
11
|
}));
|
|
12
|
+
// ── Prometheus metrics ────────────────────────────────────────────────────
|
|
13
|
+
if (metrics) {
|
|
14
|
+
const path = metricsPath ?? '/metrics';
|
|
15
|
+
app.get(path, async (_req, reply) => {
|
|
16
|
+
const body = await metrics.collect();
|
|
17
|
+
reply.header('Content-Type', metrics.contentType).send(body);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
12
20
|
// ── Sessions ─────────────────────────────────────────────────────────────
|
|
13
21
|
app.get('/sessions', async () => ({ sessions: sessions.list() }));
|
|
14
22
|
app.delete('/sessions/:id', async (req, reply) => {
|
|
@@ -23,10 +31,12 @@ function registerRoutes(app, sessions, monitorBus) {
|
|
|
23
31
|
// The engine sends AgentEvents as JSON frames; the client sends:
|
|
24
32
|
// { type: 'input', content: '...' } ← user message
|
|
25
33
|
// { type: 'abort' } ← cancel current run
|
|
26
|
-
app.get('/chat', { websocket: true }, (socket,
|
|
34
|
+
app.get('/chat', { websocket: true }, (socket, req) => {
|
|
27
35
|
let session;
|
|
36
|
+
// Pass authenticated userId if auth is configured (set by JwtAuth preHandler)
|
|
37
|
+
const userId = req.user?.sub;
|
|
28
38
|
try {
|
|
29
|
-
session = sessions.create(socket);
|
|
39
|
+
session = sessions.create(socket, userId);
|
|
30
40
|
// Announce session id so the client can reference it
|
|
31
41
|
socket.send(JSON.stringify({ type: 'session_created', sessionId: session.id }));
|
|
32
42
|
}
|
|
@@ -41,10 +51,15 @@ function registerRoutes(app, sessions, monitorBus) {
|
|
|
41
51
|
const msg = JSON.parse(raw.toString());
|
|
42
52
|
if (msg.type === 'input' && typeof msg.content === 'string') {
|
|
43
53
|
sessions.get(session.id);
|
|
54
|
+
metrics?.messageReceived();
|
|
44
55
|
// Broadcast user input to monitor observers before running
|
|
45
56
|
monitorBus?.broadcastRunInput(session.id, msg.content);
|
|
46
|
-
//
|
|
47
|
-
|
|
57
|
+
// Track run duration via metrics
|
|
58
|
+
const finish = metrics?.runStarted();
|
|
59
|
+
void session.engine.run(msg.content)
|
|
60
|
+
.then(() => finish?.('success'))
|
|
61
|
+
.catch((err) => {
|
|
62
|
+
finish?.('error');
|
|
48
63
|
const message = err instanceof Error ? err.message : 'Engine error';
|
|
49
64
|
socket.send(JSON.stringify({ type: 'error', message }));
|
|
50
65
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/server/routes.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/server/routes.ts"],"names":[],"mappings":"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"}
|