@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.
Files changed (54) hide show
  1. package/dist/auth/auth-controller.d.ts +15 -0
  2. package/dist/auth/auth-controller.d.ts.map +1 -0
  3. package/dist/auth/auth-controller.js +90 -0
  4. package/dist/auth/auth-controller.js.map +1 -0
  5. package/dist/auth/auth-middleware.d.ts +17 -0
  6. package/dist/auth/auth-middleware.d.ts.map +1 -0
  7. package/dist/auth/auth-middleware.js +35 -0
  8. package/dist/auth/auth-middleware.js.map +1 -0
  9. package/dist/auth/jwt-service.d.ts +15 -0
  10. package/dist/auth/jwt-service.d.ts.map +1 -0
  11. package/dist/auth/jwt-service.js +55 -0
  12. package/dist/auth/jwt-service.js.map +1 -0
  13. package/dist/cli-admin-builder.d.ts +85 -0
  14. package/dist/cli-admin-builder.d.ts.map +1 -0
  15. package/dist/cli-admin-builder.js +225 -0
  16. package/dist/cli-admin-builder.js.map +1 -0
  17. package/dist/controllers/config-controller.d.ts +11 -0
  18. package/dist/controllers/config-controller.d.ts.map +1 -0
  19. package/dist/controllers/config-controller.js +31 -0
  20. package/dist/controllers/config-controller.js.map +1 -0
  21. package/dist/controllers/logs-controller.d.ts +11 -0
  22. package/dist/controllers/logs-controller.d.ts.map +1 -0
  23. package/dist/controllers/logs-controller.js +32 -0
  24. package/dist/controllers/logs-controller.js.map +1 -0
  25. package/dist/controllers/plugins-controller.d.ts +11 -0
  26. package/dist/controllers/plugins-controller.d.ts.map +1 -0
  27. package/dist/controllers/plugins-controller.js +29 -0
  28. package/dist/controllers/plugins-controller.js.map +1 -0
  29. package/dist/controllers/status-controller.d.ts +16 -0
  30. package/dist/controllers/status-controller.d.ts.map +1 -0
  31. package/dist/controllers/status-controller.js +33 -0
  32. package/dist/controllers/status-controller.js.map +1 -0
  33. package/dist/controllers/ws-clients-controller.d.ts +17 -0
  34. package/dist/controllers/ws-clients-controller.d.ts.map +1 -0
  35. package/dist/controllers/ws-clients-controller.js +18 -0
  36. package/dist/controllers/ws-clients-controller.js.map +1 -0
  37. package/dist/index.d.ts +8 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +17 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/services/admin-config.d.ts +34 -0
  42. package/dist/services/admin-config.d.ts.map +1 -0
  43. package/dist/services/admin-config.js +94 -0
  44. package/dist/services/admin-config.js.map +1 -0
  45. package/dist/services/log-ring-buffer.d.ts +52 -0
  46. package/dist/services/log-ring-buffer.d.ts.map +1 -0
  47. package/dist/services/log-ring-buffer.js +119 -0
  48. package/dist/services/log-ring-buffer.js.map +1 -0
  49. package/dist/services/module-registry.d.ts +54 -0
  50. package/dist/services/module-registry.d.ts.map +1 -0
  51. package/dist/services/module-registry.js +84 -0
  52. package/dist/services/module-registry.js.map +1 -0
  53. package/dist/tsconfig.tsbuildinfo +1 -0
  54. 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"}