@qodalis/cli-server-plugin-admin 1.0.0-beta.1
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/auth-controller.d.ts +15 -0
- package/dist/auth/auth-controller.d.ts.map +1 -0
- package/dist/auth/auth-controller.js +90 -0
- package/dist/auth/auth-controller.js.map +1 -0
- package/dist/auth/auth-middleware.d.ts +17 -0
- package/dist/auth/auth-middleware.d.ts.map +1 -0
- package/dist/auth/auth-middleware.js +35 -0
- package/dist/auth/auth-middleware.js.map +1 -0
- package/dist/auth/jwt-service.d.ts +15 -0
- package/dist/auth/jwt-service.d.ts.map +1 -0
- package/dist/auth/jwt-service.js +55 -0
- package/dist/auth/jwt-service.js.map +1 -0
- package/dist/cli-admin-builder.d.ts +85 -0
- package/dist/cli-admin-builder.d.ts.map +1 -0
- package/dist/cli-admin-builder.js +225 -0
- package/dist/cli-admin-builder.js.map +1 -0
- package/dist/controllers/config-controller.d.ts +11 -0
- package/dist/controllers/config-controller.d.ts.map +1 -0
- package/dist/controllers/config-controller.js +31 -0
- package/dist/controllers/config-controller.js.map +1 -0
- package/dist/controllers/logs-controller.d.ts +11 -0
- package/dist/controllers/logs-controller.d.ts.map +1 -0
- package/dist/controllers/logs-controller.js +32 -0
- package/dist/controllers/logs-controller.js.map +1 -0
- package/dist/controllers/plugins-controller.d.ts +11 -0
- package/dist/controllers/plugins-controller.d.ts.map +1 -0
- package/dist/controllers/plugins-controller.js +29 -0
- package/dist/controllers/plugins-controller.js.map +1 -0
- package/dist/controllers/status-controller.d.ts +16 -0
- package/dist/controllers/status-controller.d.ts.map +1 -0
- package/dist/controllers/status-controller.js +33 -0
- package/dist/controllers/status-controller.js.map +1 -0
- package/dist/controllers/ws-clients-controller.d.ts +17 -0
- package/dist/controllers/ws-clients-controller.d.ts.map +1 -0
- package/dist/controllers/ws-clients-controller.js +18 -0
- package/dist/controllers/ws-clients-controller.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/services/admin-config.d.ts +34 -0
- package/dist/services/admin-config.d.ts.map +1 -0
- package/dist/services/admin-config.js +94 -0
- package/dist/services/admin-config.js.map +1 -0
- package/dist/services/log-ring-buffer.d.ts +52 -0
- package/dist/services/log-ring-buffer.d.ts.map +1 -0
- package/dist/services/log-ring-buffer.js +119 -0
- package/dist/services/log-ring-buffer.js.map +1 -0
- package/dist/services/module-registry.d.ts +54 -0
- package/dist/services/module-registry.d.ts.map +1 -0
- package/dist/services/module-registry.js +84 -0
- package/dist/services/module-registry.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +44 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { AdminConfig } from '../services/admin-config';
|
|
3
|
+
export interface AuthControllerResult {
|
|
4
|
+
router: Router;
|
|
5
|
+
cleanupInterval: ReturnType<typeof setInterval>;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Creates the auth controller router.
|
|
9
|
+
*
|
|
10
|
+
* Routes (relative to mount point):
|
|
11
|
+
* - POST /login — authenticate and receive JWT
|
|
12
|
+
* - GET /me — get current user info from token
|
|
13
|
+
*/
|
|
14
|
+
export declare function createAuthController(config: AdminConfig, jwtSecret: string): AuthControllerResult;
|
|
15
|
+
//# sourceMappingURL=auth-controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-controller.d.ts","sourceRoot":"","sources":["../../auth/auth-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAGpD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAUvD,MAAM,WAAW,oBAAoB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;CACnD;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,GAAG,oBAAoB,CAyFjG"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createAuthController = createAuthController;
|
|
4
|
+
const express_1 = require("express");
|
|
5
|
+
const jwt_service_1 = require("./jwt-service");
|
|
6
|
+
const auth_middleware_1 = require("./auth-middleware");
|
|
7
|
+
const MAX_ATTEMPTS = 5;
|
|
8
|
+
const WINDOW_MS = 60_000; // 1 minute
|
|
9
|
+
/**
|
|
10
|
+
* Creates the auth controller router.
|
|
11
|
+
*
|
|
12
|
+
* Routes (relative to mount point):
|
|
13
|
+
* - POST /login — authenticate and receive JWT
|
|
14
|
+
* - GET /me — get current user info from token
|
|
15
|
+
*/
|
|
16
|
+
function createAuthController(config, jwtSecret) {
|
|
17
|
+
const router = (0, express_1.Router)();
|
|
18
|
+
const authMiddleware = (0, auth_middleware_1.createAuthMiddleware)(jwtSecret);
|
|
19
|
+
const failedAttempts = new Map();
|
|
20
|
+
// Periodically clean up expired entries (every 5 minutes)
|
|
21
|
+
const cleanupInterval = setInterval(() => {
|
|
22
|
+
const now = Date.now();
|
|
23
|
+
for (const [ip, attempt] of failedAttempts) {
|
|
24
|
+
if (now - attempt.firstAttemptAt > WINDOW_MS) {
|
|
25
|
+
failedAttempts.delete(ip);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}, 5 * 60_000);
|
|
29
|
+
// Prevent the timer from keeping the process alive
|
|
30
|
+
if (cleanupInterval.unref) {
|
|
31
|
+
cleanupInterval.unref();
|
|
32
|
+
}
|
|
33
|
+
router.post('/login', (req, res) => {
|
|
34
|
+
const ip = req.ip ?? req.socket.remoteAddress ?? 'unknown';
|
|
35
|
+
// Rate limiting
|
|
36
|
+
const now = Date.now();
|
|
37
|
+
const attempt = failedAttempts.get(ip);
|
|
38
|
+
if (attempt) {
|
|
39
|
+
if (now - attempt.firstAttemptAt > WINDOW_MS) {
|
|
40
|
+
// Window expired, reset
|
|
41
|
+
failedAttempts.delete(ip);
|
|
42
|
+
}
|
|
43
|
+
else if (attempt.count >= MAX_ATTEMPTS) {
|
|
44
|
+
res.status(429).json({
|
|
45
|
+
error: 'Too many failed login attempts. Try again later.',
|
|
46
|
+
});
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const { username, password } = req.body ?? {};
|
|
51
|
+
if (!username || !password) {
|
|
52
|
+
res.status(400).json({ error: 'Username and password are required' });
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (!config.validateCredentials(username, password)) {
|
|
56
|
+
// Track failed attempt
|
|
57
|
+
const existing = failedAttempts.get(ip);
|
|
58
|
+
if (existing && now - existing.firstAttemptAt <= WINDOW_MS) {
|
|
59
|
+
existing.count++;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
failedAttempts.set(ip, { count: 1, firstAttemptAt: now });
|
|
63
|
+
}
|
|
64
|
+
res.status(401).json({ error: 'Invalid credentials' });
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// Clear failed attempts on success
|
|
68
|
+
failedAttempts.delete(ip);
|
|
69
|
+
const authenticatedAt = new Date().toISOString();
|
|
70
|
+
const token = (0, jwt_service_1.signToken)({ username, authenticatedAt }, jwtSecret, '24h');
|
|
71
|
+
res.json({
|
|
72
|
+
token,
|
|
73
|
+
expiresIn: 86400,
|
|
74
|
+
username,
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
router.get('/me', authMiddleware, (req, res) => {
|
|
78
|
+
const authReq = req;
|
|
79
|
+
if (!authReq.user) {
|
|
80
|
+
res.status(401).json({ error: 'Not authenticated' });
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
res.json({
|
|
84
|
+
username: authReq.user.username,
|
|
85
|
+
authenticatedAt: authReq.user.authenticatedAt,
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
return { router, cleanupInterval };
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=auth-controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-controller.js","sourceRoot":"","sources":["../../auth/auth-controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Request, RequestHandler } from 'express';
|
|
2
|
+
import { JwtPayload } from './jwt-service';
|
|
3
|
+
/**
|
|
4
|
+
* Extended request interface with authenticated user info.
|
|
5
|
+
*/
|
|
6
|
+
export interface AuthenticatedRequest extends Request {
|
|
7
|
+
user?: JwtPayload;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Creates an Express middleware that validates JWT Bearer tokens.
|
|
11
|
+
*
|
|
12
|
+
* Skips authentication for the `/auth/login` path.
|
|
13
|
+
*
|
|
14
|
+
* @param secret JWT secret used to verify tokens.
|
|
15
|
+
*/
|
|
16
|
+
export declare function createAuthMiddleware(secret: string): RequestHandler;
|
|
17
|
+
//# sourceMappingURL=auth-middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-middleware.d.ts","sourceRoot":"","sources":["../../auth/auth-middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAA0B,cAAc,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAe,UAAU,EAAE,MAAM,eAAe,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,OAAO;IACjD,IAAI,CAAC,EAAE,UAAU,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAwBnE"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createAuthMiddleware = createAuthMiddleware;
|
|
4
|
+
const jwt_service_1 = require("./jwt-service");
|
|
5
|
+
/**
|
|
6
|
+
* Creates an Express middleware that validates JWT Bearer tokens.
|
|
7
|
+
*
|
|
8
|
+
* Skips authentication for the `/auth/login` path.
|
|
9
|
+
*
|
|
10
|
+
* @param secret JWT secret used to verify tokens.
|
|
11
|
+
*/
|
|
12
|
+
function createAuthMiddleware(secret) {
|
|
13
|
+
return (req, res, next) => {
|
|
14
|
+
// Skip auth for login endpoint
|
|
15
|
+
if (req.path === '/auth/login') {
|
|
16
|
+
next();
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const authHeader = req.headers.authorization;
|
|
20
|
+
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
21
|
+
res.status(401).json({ error: 'Missing or invalid Authorization header' });
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const token = authHeader.slice(7);
|
|
25
|
+
try {
|
|
26
|
+
const decoded = (0, jwt_service_1.verifyToken)(token, secret);
|
|
27
|
+
req.user = decoded;
|
|
28
|
+
next();
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
res.status(401).json({ error: 'Invalid or expired token' });
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=auth-middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-middleware.js","sourceRoot":"","sources":["../../auth/auth-middleware.ts"],"names":[],"mappings":";;AAiBA,oDAwBC;AAxCD,+CAAwD;AASxD;;;;;;GAMG;AACH,SAAgB,oBAAoB,CAAC,MAAc;IAC/C,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAQ,EAAE;QAC7D,+BAA+B;QAC/B,IAAI,GAAG,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YAC7B,IAAI,EAAE,CAAC;YACP,OAAO;QACX,CAAC;QAED,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC;QAC7C,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACnD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,yCAAyC,EAAE,CAAC,CAAC;YAC3E,OAAO;QACX,CAAC;QAED,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAElC,IAAI,CAAC;YACD,MAAM,OAAO,GAAG,IAAA,yBAAW,EAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAC1C,GAA4B,CAAC,IAAI,GAAG,OAAO,CAAC;YAC7C,IAAI,EAAE,CAAC;QACX,CAAC;QAAC,MAAM,CAAC;YACL,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC,CAAC;QAChE,CAAC;IACL,CAAC,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface JwtPayload {
|
|
2
|
+
username: string;
|
|
3
|
+
authenticatedAt: string;
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Sign a JWT token.
|
|
8
|
+
*/
|
|
9
|
+
export declare function signToken(payload: JwtPayload, secret: string, expiresIn?: string | number): string;
|
|
10
|
+
/**
|
|
11
|
+
* Verify and decode a JWT token.
|
|
12
|
+
* Returns the decoded payload, or throws on invalid/expired tokens.
|
|
13
|
+
*/
|
|
14
|
+
export declare function verifyToken(token: string, secret: string): JwtPayload;
|
|
15
|
+
//# sourceMappingURL=jwt-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt-service.d.ts","sourceRoot":"","sources":["../../auth/jwt-service.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAgB,SAAS,CACrB,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,MAAM,GAAG,MAAc,GACnC,MAAM,CAKR;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACvB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACf,UAAU,CAEZ"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.signToken = signToken;
|
|
37
|
+
exports.verifyToken = verifyToken;
|
|
38
|
+
const jwt = __importStar(require("jsonwebtoken"));
|
|
39
|
+
/**
|
|
40
|
+
* Sign a JWT token.
|
|
41
|
+
*/
|
|
42
|
+
function signToken(payload, secret, expiresIn = '24h') {
|
|
43
|
+
const options = {
|
|
44
|
+
expiresIn: typeof expiresIn === 'number' ? expiresIn : expiresIn,
|
|
45
|
+
};
|
|
46
|
+
return jwt.sign(payload, secret, options);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Verify and decode a JWT token.
|
|
50
|
+
* Returns the decoded payload, or throws on invalid/expired tokens.
|
|
51
|
+
*/
|
|
52
|
+
function verifyToken(token, secret) {
|
|
53
|
+
return jwt.verify(token, secret);
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=jwt-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt-service.js","sourceRoot":"","sources":["../../auth/jwt-service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWA,8BASC;AAMD,kCAKC;AA/BD,kDAAoC;AAQpC;;GAEG;AACH,SAAgB,SAAS,CACrB,OAAmB,EACnB,MAAc,EACd,YAA6B,KAAK;IAElC,MAAM,OAAO,GAAoB;QAC7B,SAAS,EAAE,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAE,SAA0C;KACrG,CAAC;IACF,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAC9C,CAAC;AAED;;;GAGG;AACH,SAAgB,WAAW,CACvB,KAAa,EACb,MAAc;IAEd,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAe,CAAC;AACnD,CAAC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Router, RequestHandler } from 'express';
|
|
2
|
+
import { WsClientsDeps } from './controllers/ws-clients-controller';
|
|
3
|
+
import { IRegistryLike, IBuilderLike } from './services/module-registry';
|
|
4
|
+
import { LogRingBuffer } from './services/log-ring-buffer';
|
|
5
|
+
export interface CliAdminBuildDeps {
|
|
6
|
+
/** The command registry instance. */
|
|
7
|
+
registry: IRegistryLike;
|
|
8
|
+
/** The WebSocket event socket manager. */
|
|
9
|
+
eventSocketManager: WsClientsDeps & {
|
|
10
|
+
broadcastMessage(message: Record<string, unknown>): void;
|
|
11
|
+
};
|
|
12
|
+
/** The CLI builder instance (for reading modules). */
|
|
13
|
+
builder: IBuilderLike;
|
|
14
|
+
/** Optional broadcast function override for log events. */
|
|
15
|
+
broadcastFn?: (message: Record<string, unknown>) => void;
|
|
16
|
+
}
|
|
17
|
+
export interface CliAdminPluginResult {
|
|
18
|
+
/** Express router — mount at `/api/v1/qcli`. */
|
|
19
|
+
router: Router;
|
|
20
|
+
/** Express router serving the SPA at `/qcli/admin`. */
|
|
21
|
+
dashboardRouter: Router;
|
|
22
|
+
/** The auth middleware, in case you need to protect additional routes. */
|
|
23
|
+
authMiddleware: RequestHandler;
|
|
24
|
+
/** The log ring buffer, in case you need to push entries programmatically. */
|
|
25
|
+
logBuffer: LogRingBuffer;
|
|
26
|
+
/** Clean up timers and restore console. Call when shutting down. */
|
|
27
|
+
dispose: () => void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Fluent builder for configuring the admin dashboard plugin.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* import { CliAdminBuilder } from '@qodalis/cli-server-plugin-admin';
|
|
35
|
+
*
|
|
36
|
+
* const adminPlugin = new CliAdminBuilder()
|
|
37
|
+
* .setCredentials('admin', 'secret')
|
|
38
|
+
* .build({ registry, eventSocketManager, builder });
|
|
39
|
+
*
|
|
40
|
+
* app.use('/api/v1/qcli', adminPlugin.router);
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare class CliAdminBuilder {
|
|
44
|
+
private readonly _config;
|
|
45
|
+
private _jwtSecret?;
|
|
46
|
+
private _registeredJobs;
|
|
47
|
+
private _dashboardDir?;
|
|
48
|
+
private _enabledFeatures;
|
|
49
|
+
/**
|
|
50
|
+
* Set admin credentials.
|
|
51
|
+
*/
|
|
52
|
+
setCredentials(username: string, password: string): CliAdminBuilder;
|
|
53
|
+
/**
|
|
54
|
+
* Set JWT signing secret. If not set, reads from QCLI_ADMIN_JWT_SECRET
|
|
55
|
+
* env var or generates a random secret.
|
|
56
|
+
*/
|
|
57
|
+
setJwtSecret(secret: string): CliAdminBuilder;
|
|
58
|
+
/**
|
|
59
|
+
* Set the number of registered jobs (for status endpoint).
|
|
60
|
+
*/
|
|
61
|
+
setRegisteredJobs(count: number): CliAdminBuilder;
|
|
62
|
+
/**
|
|
63
|
+
* Set additional enabled features (for status endpoint).
|
|
64
|
+
* Features like 'filesystem' and 'jobs' are auto-detected;
|
|
65
|
+
* use this to add custom features.
|
|
66
|
+
*/
|
|
67
|
+
setEnabledFeatures(features: string[]): CliAdminBuilder;
|
|
68
|
+
/**
|
|
69
|
+
* Build the admin plugin, returning the Express router and auth middleware.
|
|
70
|
+
*/
|
|
71
|
+
build(deps: CliAdminBuildDeps): CliAdminPluginResult;
|
|
72
|
+
/**
|
|
73
|
+
* Set the path to the dashboard dist directory.
|
|
74
|
+
* If not set, the builder will try to resolve it automatically.
|
|
75
|
+
*/
|
|
76
|
+
setDashboardDir(dir: string): CliAdminBuilder;
|
|
77
|
+
/**
|
|
78
|
+
* Resolve the dashboard dist directory. Looks for:
|
|
79
|
+
* 1. Explicitly set path
|
|
80
|
+
* 2. @qodalis/cli-server-dashboard/dist (npm package)
|
|
81
|
+
* 3. Relative paths from this file and cwd (development)
|
|
82
|
+
*/
|
|
83
|
+
private _resolveDashboardDir;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=cli-admin-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-admin-builder.d.ts","sourceRoot":"","sources":["../cli-admin-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,cAAc,EAA2B,MAAM,SAAS,CAAC;AAQ1E,OAAO,EAA6B,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAC/F,OAAO,EAAkB,aAAa,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AACzF,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAM3D,MAAM,WAAW,iBAAiB;IAC9B,qCAAqC;IACrC,QAAQ,EAAE,aAAa,CAAC;IACxB,0CAA0C;IAC1C,kBAAkB,EAAE,aAAa,GAAG;QAChC,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;KAC5D,CAAC;IACF,sDAAsD;IACtD,OAAO,EAAE,YAAY,CAAC;IACtB,2DAA2D;IAC3D,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CAC5D;AAED,MAAM,WAAW,oBAAoB;IACjC,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,eAAe,EAAE,MAAM,CAAC;IACxB,0EAA0E;IAC1E,cAAc,EAAE,cAAc,CAAC;IAC/B,8EAA8E;IAC9E,SAAS,EAAE,aAAa,CAAC;IACzB,oEAAoE;IACpE,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,eAAe;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,aAAa,CAAC,CAAS;IAC/B,OAAO,CAAC,gBAAgB,CAAgB;IAExC;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,eAAe;IAKnE;;;OAGG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe;IAM7C;;OAEG;IACH,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe;IAKjD;;;;OAIG;IACH,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,eAAe;IAKvD;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,iBAAiB,GAAG,oBAAoB;IA2FpD;;;OAGG;IACH,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe;IAK7C;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;CA6B/B"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.CliAdminBuilder = void 0;
|
|
37
|
+
const express_1 = require("express");
|
|
38
|
+
const auth_middleware_1 = require("./auth/auth-middleware");
|
|
39
|
+
const auth_controller_1 = require("./auth/auth-controller");
|
|
40
|
+
const status_controller_1 = require("./controllers/status-controller");
|
|
41
|
+
const plugins_controller_1 = require("./controllers/plugins-controller");
|
|
42
|
+
const config_controller_1 = require("./controllers/config-controller");
|
|
43
|
+
const logs_controller_1 = require("./controllers/logs-controller");
|
|
44
|
+
const ws_clients_controller_1 = require("./controllers/ws-clients-controller");
|
|
45
|
+
const module_registry_1 = require("./services/module-registry");
|
|
46
|
+
const log_ring_buffer_1 = require("./services/log-ring-buffer");
|
|
47
|
+
const admin_config_1 = require("./services/admin-config");
|
|
48
|
+
const fs_1 = require("fs");
|
|
49
|
+
const path_1 = require("path");
|
|
50
|
+
const crypto = __importStar(require("crypto"));
|
|
51
|
+
/**
|
|
52
|
+
* Fluent builder for configuring the admin dashboard plugin.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* import { CliAdminBuilder } from '@qodalis/cli-server-plugin-admin';
|
|
57
|
+
*
|
|
58
|
+
* const adminPlugin = new CliAdminBuilder()
|
|
59
|
+
* .setCredentials('admin', 'secret')
|
|
60
|
+
* .build({ registry, eventSocketManager, builder });
|
|
61
|
+
*
|
|
62
|
+
* app.use('/api/v1/qcli', adminPlugin.router);
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
class CliAdminBuilder {
|
|
66
|
+
_config = new admin_config_1.AdminConfig();
|
|
67
|
+
_jwtSecret;
|
|
68
|
+
_registeredJobs = 0;
|
|
69
|
+
_dashboardDir;
|
|
70
|
+
_enabledFeatures = [];
|
|
71
|
+
/**
|
|
72
|
+
* Set admin credentials.
|
|
73
|
+
*/
|
|
74
|
+
setCredentials(username, password) {
|
|
75
|
+
this._config.setCredentials(username, password);
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Set JWT signing secret. If not set, reads from QCLI_ADMIN_JWT_SECRET
|
|
80
|
+
* env var or generates a random secret.
|
|
81
|
+
*/
|
|
82
|
+
setJwtSecret(secret) {
|
|
83
|
+
this._jwtSecret = secret;
|
|
84
|
+
this._config.setJwtSecret(secret);
|
|
85
|
+
return this;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Set the number of registered jobs (for status endpoint).
|
|
89
|
+
*/
|
|
90
|
+
setRegisteredJobs(count) {
|
|
91
|
+
this._registeredJobs = count;
|
|
92
|
+
return this;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Set additional enabled features (for status endpoint).
|
|
96
|
+
* Features like 'filesystem' and 'jobs' are auto-detected;
|
|
97
|
+
* use this to add custom features.
|
|
98
|
+
*/
|
|
99
|
+
setEnabledFeatures(features) {
|
|
100
|
+
this._enabledFeatures = features;
|
|
101
|
+
return this;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Build the admin plugin, returning the Express router and auth middleware.
|
|
105
|
+
*/
|
|
106
|
+
build(deps) {
|
|
107
|
+
const { registry, eventSocketManager, builder, broadcastFn } = deps;
|
|
108
|
+
// Resolve JWT secret: explicit > env var > random
|
|
109
|
+
const secret = this._jwtSecret
|
|
110
|
+
?? process.env.QCLI_ADMIN_JWT_SECRET
|
|
111
|
+
?? crypto.randomBytes(32).toString('hex');
|
|
112
|
+
// Create services
|
|
113
|
+
const moduleRegistry = new module_registry_1.ModuleRegistry(registry, builder);
|
|
114
|
+
const logBuffer = new log_ring_buffer_1.LogRingBuffer();
|
|
115
|
+
const broadcast = broadcastFn ?? ((msg) => eventSocketManager.broadcastMessage(msg));
|
|
116
|
+
logBuffer.setBroadcastFn(broadcast);
|
|
117
|
+
logBuffer.interceptConsole();
|
|
118
|
+
// Create auth middleware
|
|
119
|
+
const authMiddleware = (0, auth_middleware_1.createAuthMiddleware)(secret);
|
|
120
|
+
// Create main router
|
|
121
|
+
const router = (0, express_1.Router)();
|
|
122
|
+
// Auth routes (login is unauthenticated, /me requires auth)
|
|
123
|
+
const authResult = (0, auth_controller_1.createAuthController)(this._config, secret);
|
|
124
|
+
router.use('/auth', authResult.router);
|
|
125
|
+
// Apply auth middleware to all routes below
|
|
126
|
+
router.use(authMiddleware);
|
|
127
|
+
// Status
|
|
128
|
+
const registeredJobs = this._registeredJobs;
|
|
129
|
+
const enabledFeatures = this._enabledFeatures;
|
|
130
|
+
const hasFilesystem = !!(builder.fileStorageProvider || builder.fileSystemOptions);
|
|
131
|
+
const statusDeps = {
|
|
132
|
+
getActiveWsConnections: () => eventSocketManager.getClients().length,
|
|
133
|
+
// TODO: expose getActiveShellSessions() on CliEventSocketManager
|
|
134
|
+
getActiveShellSessions: () => 0,
|
|
135
|
+
getRegisteredCommands: () => registry.processors.length,
|
|
136
|
+
getRegisteredJobs: () => registeredJobs,
|
|
137
|
+
getEnabledFeatures: () => {
|
|
138
|
+
const features = [...enabledFeatures];
|
|
139
|
+
if (hasFilesystem && !features.includes('filesystem')) {
|
|
140
|
+
features.push('filesystem');
|
|
141
|
+
}
|
|
142
|
+
if (registeredJobs > 0 && !features.includes('jobs')) {
|
|
143
|
+
features.push('jobs');
|
|
144
|
+
}
|
|
145
|
+
return features;
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
router.use('/status', (0, status_controller_1.createStatusController)(statusDeps));
|
|
149
|
+
// Plugins
|
|
150
|
+
router.use('/plugins', (0, plugins_controller_1.createPluginsController)(moduleRegistry));
|
|
151
|
+
// Config
|
|
152
|
+
router.use('/config', (0, config_controller_1.createConfigController)(this._config));
|
|
153
|
+
// Logs
|
|
154
|
+
router.use('/logs', (0, logs_controller_1.createLogsController)(logBuffer));
|
|
155
|
+
// WebSocket clients
|
|
156
|
+
router.use('/ws/clients', (0, ws_clients_controller_1.createWsClientsController)(eventSocketManager));
|
|
157
|
+
// Dashboard SPA static file serving
|
|
158
|
+
const dashboardRouter = (0, express_1.Router)();
|
|
159
|
+
const dashboardDistDir = this._resolveDashboardDir();
|
|
160
|
+
if (dashboardDistDir) {
|
|
161
|
+
dashboardRouter.use((0, express_1.static)(dashboardDistDir));
|
|
162
|
+
// SPA fallback: serve index.html for all non-file routes
|
|
163
|
+
dashboardRouter.get('*', (_req, res) => {
|
|
164
|
+
res.sendFile((0, path_1.join)(dashboardDistDir, 'index.html'));
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
dashboardRouter.get('*', (_req, res) => {
|
|
169
|
+
res.status(404).json({
|
|
170
|
+
error: 'Admin dashboard not found. Ensure the package was built with "npm run copy-dashboard" or install @qodalis/cli-server-dashboard.',
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
const dispose = () => {
|
|
175
|
+
clearInterval(authResult.cleanupInterval);
|
|
176
|
+
logBuffer.restoreConsole();
|
|
177
|
+
};
|
|
178
|
+
return { router, dashboardRouter, authMiddleware, logBuffer, dispose };
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Set the path to the dashboard dist directory.
|
|
182
|
+
* If not set, the builder will try to resolve it automatically.
|
|
183
|
+
*/
|
|
184
|
+
setDashboardDir(dir) {
|
|
185
|
+
this._dashboardDir = dir;
|
|
186
|
+
return this;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Resolve the dashboard dist directory. Looks for:
|
|
190
|
+
* 1. Explicitly set path
|
|
191
|
+
* 2. @qodalis/cli-server-dashboard/dist (npm package)
|
|
192
|
+
* 3. Relative paths from this file and cwd (development)
|
|
193
|
+
*/
|
|
194
|
+
_resolveDashboardDir() {
|
|
195
|
+
// Explicit override
|
|
196
|
+
if (this._dashboardDir && (0, fs_1.existsSync)(this._dashboardDir)) {
|
|
197
|
+
return (0, path_1.resolve)(this._dashboardDir);
|
|
198
|
+
}
|
|
199
|
+
// Try bundled dashboard directory (embedded in this package)
|
|
200
|
+
const bundledPath = (0, path_1.resolve)(__dirname, '..', 'dashboard');
|
|
201
|
+
if ((0, fs_1.existsSync)(bundledPath))
|
|
202
|
+
return bundledPath;
|
|
203
|
+
// Try resolving from node_modules (published package — legacy fallback)
|
|
204
|
+
try {
|
|
205
|
+
const pkgDir = require.resolve('@qodalis/cli-server-dashboard/package.json');
|
|
206
|
+
const distDir = (0, path_1.join)(pkgDir, '..', 'dist');
|
|
207
|
+
if ((0, fs_1.existsSync)(distDir))
|
|
208
|
+
return (0, path_1.resolve)(distDir);
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
// Package not installed
|
|
212
|
+
}
|
|
213
|
+
// Try relative path from this file (development)
|
|
214
|
+
const devPath = (0, path_1.resolve)(__dirname, '../../../../cli-server-dashboard/dist');
|
|
215
|
+
if ((0, fs_1.existsSync)(devPath))
|
|
216
|
+
return devPath;
|
|
217
|
+
// Try relative path from cwd (workspace root)
|
|
218
|
+
const cwdPath = (0, path_1.resolve)(process.cwd(), '../cli-server-dashboard/dist');
|
|
219
|
+
if ((0, fs_1.existsSync)(cwdPath))
|
|
220
|
+
return cwdPath;
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
exports.CliAdminBuilder = CliAdminBuilder;
|
|
225
|
+
//# sourceMappingURL=cli-admin-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-admin-builder.js","sourceRoot":"","sources":["../cli-admin-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { AdminConfig } from '../services/admin-config';
|
|
3
|
+
/**
|
|
4
|
+
* Creates the config controller router.
|
|
5
|
+
*
|
|
6
|
+
* Routes:
|
|
7
|
+
* - GET / — return structured config sections
|
|
8
|
+
* - PUT / — update mutable settings
|
|
9
|
+
*/
|
|
10
|
+
export declare function createConfigController(config: AdminConfig): Router;
|
|
11
|
+
//# sourceMappingURL=config-controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-controller.d.ts","sourceRoot":"","sources":["../../controllers/config-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAuBlE"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createConfigController = createConfigController;
|
|
4
|
+
const express_1 = require("express");
|
|
5
|
+
/**
|
|
6
|
+
* Creates the config controller router.
|
|
7
|
+
*
|
|
8
|
+
* Routes:
|
|
9
|
+
* - GET / — return structured config sections
|
|
10
|
+
* - PUT / — update mutable settings
|
|
11
|
+
*/
|
|
12
|
+
function createConfigController(config) {
|
|
13
|
+
const router = (0, express_1.Router)();
|
|
14
|
+
router.get('/', (_req, res) => {
|
|
15
|
+
res.json({ sections: config.getConfigSections() });
|
|
16
|
+
});
|
|
17
|
+
router.put('/', (req, res) => {
|
|
18
|
+
const body = req.body;
|
|
19
|
+
if (!body || typeof body !== 'object' || Array.isArray(body)) {
|
|
20
|
+
res.status(400).json({ error: 'Request body must be a JSON object' });
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
config.updateMutableSettings(body);
|
|
24
|
+
res.json({
|
|
25
|
+
message: 'Settings updated',
|
|
26
|
+
settings: config.getMutableSettings(),
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
return router;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=config-controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-controller.js","sourceRoot":"","sources":["../../controllers/config-controller.ts"],"names":[],"mappings":";;AAUA,wDAuBC;AAjCD,qCAAoD;AAGpD;;;;;;GAMG;AACH,SAAgB,sBAAsB,CAAC,MAAmB;IACtD,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;IAExB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAa,EAAE,GAAa,EAAQ,EAAE;QACnD,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAY,EAAE,GAAa,EAAQ,EAAE;QAClD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;QAEtB,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3D,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,oCAAoC,EAAE,CAAC,CAAC;YACtE,OAAO;QACX,CAAC;QAED,MAAM,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC;QACnC,GAAG,CAAC,IAAI,CAAC;YACL,OAAO,EAAE,kBAAkB;YAC3B,QAAQ,EAAE,MAAM,CAAC,kBAAkB,EAAE;SACxC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { LogRingBuffer } from '../services/log-ring-buffer';
|
|
3
|
+
/**
|
|
4
|
+
* Creates the logs controller router.
|
|
5
|
+
*
|
|
6
|
+
* Routes:
|
|
7
|
+
* - GET / — query log entries with optional filtering
|
|
8
|
+
* Query params: level, search, limit, offset
|
|
9
|
+
*/
|
|
10
|
+
export declare function createLogsController(logBuffer: LogRingBuffer): Router;
|
|
11
|
+
//# sourceMappingURL=logs-controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs-controller.d.ts","sourceRoot":"","sources":["../../controllers/logs-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE5D;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,aAAa,GAAG,MAAM,CAsBrE"}
|