@qodalis/cli-server-plugin-admin 1.0.0-beta.1 → 1.0.0-beta.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +226 -0
- package/dashboard/assets/index-BVWEEAZ_.js +248 -0
- package/dashboard/assets/index-DDYjltKc.css +32 -0
- package/dashboard/assets/wasm/qodalis_cli_wasm_bg.wasm +0 -0
- package/dashboard/index.html +14 -0
- package/dist/auth/auth-controller.d.ts +11 -2
- package/dist/auth/auth-controller.d.ts.map +1 -1
- package/dist/auth/auth-controller.js +59 -6
- package/dist/auth/auth-controller.js.map +1 -1
- package/dist/auth/auth-middleware.d.ts +2 -1
- package/dist/auth/auth-middleware.d.ts.map +1 -1
- package/dist/auth/auth-middleware.js +64 -1
- package/dist/auth/auth-middleware.js.map +1 -1
- package/dist/auth/auth-provider.d.ts +42 -0
- package/dist/auth/auth-provider.d.ts.map +1 -0
- package/dist/auth/auth-provider.js +16 -0
- package/dist/auth/auth-provider.js.map +1 -0
- package/dist/auth/jwt-service.d.ts +12 -2
- package/dist/auth/jwt-service.d.ts.map +1 -1
- package/dist/auth/jwt-service.js +11 -2
- package/dist/auth/jwt-service.js.map +1 -1
- package/dist/cli-admin-builder.d.ts +49 -9
- package/dist/cli-admin-builder.d.ts.map +1 -1
- package/dist/cli-admin-builder.js +87 -51
- package/dist/cli-admin-builder.js.map +1 -1
- package/dist/controllers/plugins-controller.d.ts.map +1 -1
- package/dist/controllers/plugins-controller.js +1 -2
- package/dist/controllers/plugins-controller.js.map +1 -1
- package/dist/controllers/status-controller.d.ts +1 -0
- package/dist/controllers/status-controller.d.ts.map +1 -1
- package/dist/controllers/status-controller.js.map +1 -1
- package/dist/controllers/ws-clients-controller.d.ts +1 -0
- package/dist/controllers/ws-clients-controller.d.ts.map +1 -1
- package/dist/controllers/ws-clients-controller.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/dist/services/admin-config.d.ts +32 -3
- package/dist/services/admin-config.d.ts.map +1 -1
- package/dist/services/admin-config.js +56 -3
- package/dist/services/admin-config.js.map +1 -1
- package/dist/services/admin-theme.d.ts +31 -0
- package/dist/services/admin-theme.d.ts.map +1 -0
- package/dist/services/admin-theme.js +94 -0
- package/dist/services/admin-theme.js.map +1 -0
- package/dist/services/dashboard-dir.d.ts +10 -0
- package/dist/services/dashboard-dir.d.ts.map +1 -0
- package/dist/services/dashboard-dir.js +51 -0
- package/dist/services/dashboard-dir.js.map +1 -0
- package/dist/services/log-ring-buffer.d.ts +6 -0
- package/dist/services/log-ring-buffer.d.ts.map +1 -1
- package/dist/services/log-ring-buffer.js +13 -0
- package/dist/services/log-ring-buffer.js.map +1 -1
- package/dist/services/module-registry.d.ts +20 -7
- package/dist/services/module-registry.d.ts.map +1 -1
- package/dist/services/module-registry.js +22 -10
- package/dist/services/module-registry.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -2
|
@@ -11,35 +11,85 @@ function safeCompare(a, b) {
|
|
|
11
11
|
const hashB = (0, crypto_1.createHash)('sha256').update(b).digest();
|
|
12
12
|
return (0, crypto_1.timingSafeEqual)(hashA, hashB);
|
|
13
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Manages admin credentials and mutable runtime settings.
|
|
16
|
+
* Reads defaults from environment variables on construction.
|
|
17
|
+
*/
|
|
14
18
|
class AdminConfig {
|
|
15
19
|
_username;
|
|
16
20
|
_password;
|
|
17
21
|
_jwtSecret;
|
|
22
|
+
_signInUrl;
|
|
18
23
|
_mutableSettings = {};
|
|
24
|
+
/**
|
|
25
|
+
* Where the host application signs users in, shown by the dashboard in external
|
|
26
|
+
* sign-in mode (users plugin with an external auth adapter) and returned by
|
|
27
|
+
* `GET /api/v1/qcli/auth/mode`. An absolute `http(s)` URL or a root-relative path
|
|
28
|
+
* (`/sign-in`). Undefined: the dashboard tells users to sign in through the host application.
|
|
29
|
+
*/
|
|
30
|
+
get signInUrl() {
|
|
31
|
+
return this._signInUrl;
|
|
32
|
+
}
|
|
33
|
+
set signInUrl(value) {
|
|
34
|
+
this._signInUrl = value;
|
|
35
|
+
}
|
|
36
|
+
/** Validates the options set by the host. Throws on an invalid {@link signInUrl}. */
|
|
37
|
+
validate() {
|
|
38
|
+
if (this._signInUrl !== undefined && !AdminConfig.isValidSignInUrl(this._signInUrl)) {
|
|
39
|
+
throw new Error(`signInUrl must be an absolute http(s) URL or a root-relative path, got '${this._signInUrl}'.`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* True for an absolute `http`/`https` URL with a host, or a root-relative path
|
|
44
|
+
* (`/sign-in`; not protocol-relative `//host` or `/\host`). Rejects other schemes
|
|
45
|
+
* such as `javascript:`, and control characters or whitespace.
|
|
46
|
+
*/
|
|
47
|
+
static isValidSignInUrl(value) {
|
|
48
|
+
// eslint-disable-next-line no-control-regex
|
|
49
|
+
if (typeof value !== 'string' || value.length === 0 || /[\s\x00-\x1f\x7f-\x9f]/.test(value)) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
if (value.startsWith('/')) {
|
|
53
|
+
return value.length === 1 || (value[1] !== '/' && value[1] !== '\\');
|
|
54
|
+
}
|
|
55
|
+
let url;
|
|
56
|
+
try {
|
|
57
|
+
url = new URL(value);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return (url.protocol === 'http:' || url.protocol === 'https:') && url.hostname.length > 0;
|
|
63
|
+
}
|
|
19
64
|
constructor() {
|
|
20
65
|
this._username = process.env.QCLI_ADMIN_USERNAME ?? 'admin';
|
|
21
66
|
this._password = process.env.QCLI_ADMIN_PASSWORD ?? 'admin';
|
|
22
67
|
this._jwtSecret = process.env.QCLI_ADMIN_JWT_SECRET;
|
|
23
|
-
if (this._username === 'admin' && this._password === 'admin') {
|
|
24
|
-
console.warn('[qcli-admin] WARNING: Using default admin credentials. Set QCLI_ADMIN_USERNAME and QCLI_ADMIN_PASSWORD environment variables.');
|
|
25
|
-
}
|
|
26
68
|
}
|
|
69
|
+
/** True while the well-known `admin` / `admin` credentials are in effect. */
|
|
70
|
+
usesDefaultCredentials() {
|
|
71
|
+
return this._username === 'admin' && this._password === 'admin';
|
|
72
|
+
}
|
|
73
|
+
/** Override the admin username and password. */
|
|
27
74
|
setCredentials(username, password) {
|
|
28
75
|
this._username = username;
|
|
29
76
|
this._password = password;
|
|
30
77
|
}
|
|
78
|
+
/** Set the JWT signing secret explicitly. */
|
|
31
79
|
setJwtSecret(secret) {
|
|
32
80
|
this._jwtSecret = secret;
|
|
33
81
|
}
|
|
34
82
|
get jwtSecret() {
|
|
35
83
|
return this._jwtSecret;
|
|
36
84
|
}
|
|
85
|
+
/** Validate credentials using timing-safe comparison. */
|
|
37
86
|
validateCredentials(username, password) {
|
|
38
87
|
// Evaluate both comparisons to avoid short-circuit timing leaks
|
|
39
88
|
const usernameMatch = safeCompare(username, this._username);
|
|
40
89
|
const passwordMatch = safeCompare(password, this._password);
|
|
41
90
|
return usernameMatch && passwordMatch;
|
|
42
91
|
}
|
|
92
|
+
/** Return all configuration sections (server, auth, custom) for the dashboard. */
|
|
43
93
|
getConfigSections() {
|
|
44
94
|
const customEntries = Object.entries(this._mutableSettings).map(([key, val]) => ({
|
|
45
95
|
key,
|
|
@@ -74,14 +124,17 @@ class AdminConfig {
|
|
|
74
124
|
},
|
|
75
125
|
];
|
|
76
126
|
}
|
|
127
|
+
/** Return a shallow copy of all mutable (custom) settings. */
|
|
77
128
|
getMutableSettings() {
|
|
78
129
|
return { ...this._mutableSettings };
|
|
79
130
|
}
|
|
131
|
+
/** Merge the provided key-value pairs into mutable settings. */
|
|
80
132
|
updateMutableSettings(values) {
|
|
81
133
|
Object.assign(this._mutableSettings, values);
|
|
82
134
|
}
|
|
83
135
|
}
|
|
84
136
|
exports.AdminConfig = AdminConfig;
|
|
137
|
+
/** Infer the ConfigEntry type string from a runtime value. */
|
|
85
138
|
function inferType(val) {
|
|
86
139
|
if (typeof val === 'boolean')
|
|
87
140
|
return 'boolean';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-config.js","sourceRoot":"","sources":["../../services/admin-config.ts"],"names":[],"mappings":";;;AAAA,mCAAqD;AAErD;;;GAGG;AACH,SAAS,WAAW,CAAC,CAAS,EAAE,CAAS;IACrC,MAAM,KAAK,GAAG,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACtD,MAAM,KAAK,GAAG,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACtD,OAAO,IAAA,wBAAe,EAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AACzC,CAAC;AAwBD,MAAa,WAAW;IACZ,SAAS,CAAS;IAClB,SAAS,CAAS;IAClB,UAAU,CAAqB;IACtB,gBAAgB,GAA4B,EAAE,CAAC;IAEhE;
|
|
1
|
+
{"version":3,"file":"admin-config.js","sourceRoot":"","sources":["../../services/admin-config.ts"],"names":[],"mappings":";;;AAAA,mCAAqD;AAErD;;;GAGG;AACH,SAAS,WAAW,CAAC,CAAS,EAAE,CAAS;IACrC,MAAM,KAAK,GAAG,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACtD,MAAM,KAAK,GAAG,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACtD,OAAO,IAAA,wBAAe,EAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AACzC,CAAC;AAwBD;;;GAGG;AACH,MAAa,WAAW;IACZ,SAAS,CAAS;IAClB,SAAS,CAAS;IAClB,UAAU,CAAqB;IAC/B,UAAU,CAAqB;IACtB,gBAAgB,GAA4B,EAAE,CAAC;IAEhE;;;;;OAKG;IACH,IAAI,SAAS;QACT,OAAO,IAAI,CAAC,UAAU,CAAC;IAC3B,CAAC;IAED,IAAI,SAAS,CAAC,KAAyB;QACnC,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;IAC5B,CAAC;IAED,qFAAqF;IACrF,QAAQ;QACJ,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,IAAI,CAAC,WAAW,CAAC,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YAClF,MAAM,IAAI,KAAK,CAAC,2EAA2E,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC;QACpH,CAAC;IACL,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,gBAAgB,CAAC,KAAgC;QACpD,4CAA4C;QAC5C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1F,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;QACzE,CAAC;QACD,IAAI,GAAQ,CAAC;QACb,IAAI,CAAC;YACD,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;IAC9F,CAAC;IAED;QACI,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,OAAO,CAAC;QAC5D,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,OAAO,CAAC;QAC5D,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;IACxD,CAAC;IAED,6EAA6E;IAC7E,sBAAsB;QAClB,OAAO,IAAI,CAAC,SAAS,KAAK,OAAO,IAAI,IAAI,CAAC,SAAS,KAAK,OAAO,CAAC;IACpE,CAAC;IAED,gDAAgD;IAChD,cAAc,CAAC,QAAgB,EAAE,QAAgB;QAC7C,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC1B,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;IAC9B,CAAC;IAED,6CAA6C;IAC7C,YAAY,CAAC,MAAc;QACvB,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC;IAC7B,CAAC;IAED,IAAI,SAAS;QACT,OAAO,IAAI,CAAC,UAAU,CAAC;IAC3B,CAAC;IAED,yDAAyD;IACzD,mBAAmB,CAAC,QAAgB,EAAE,QAAgB;QAClD,gEAAgE;QAChE,MAAM,aAAa,GAAG,WAAW,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAC5D,MAAM,aAAa,GAAG,WAAW,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAC5D,OAAO,aAAa,IAAI,aAAa,CAAC;IAC1C,CAAC;IAED,kFAAkF;IAClF,iBAAiB;QACb,MAAM,aAAa,GAAkB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,GAAG,CAC1E,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;YACb,GAAG;YACH,KAAK,EAAE,GAA2C;YAClD,IAAI,EAAE,SAAS,CAAC,GAAG,CAAC;YACpB,WAAW,EAAE,EAAE;YACf,OAAO,EAAE,IAAI;SAChB,CAAC,CACL,CAAC;QAEF,OAAO;YACH;gBACI,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,KAAK;gBACd,QAAQ,EAAE;oBACN,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,iBAAiB,EAAE,OAAO,EAAE,KAAK,EAAE;oBAClG,EAAE,GAAG,EAAE,iBAAiB,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,iBAAiB,EAAE,OAAO,EAAE,KAAK,EAAE;oBAClH,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE;oBACzH,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE;iBAChG;aACJ;YACD;gBACI,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,KAAK;gBACd,QAAQ,EAAE;oBACN,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,gBAAgB,EAAE,OAAO,EAAE,KAAK,EAAE;oBACzG,EAAE,GAAG,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,sCAAsC,EAAE,OAAO,EAAE,KAAK,EAAE;iBACxL;aACJ;YACD;gBACI,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,IAAI;gBACb,QAAQ,EAAE,aAAa;aAC1B;SACJ,CAAC;IACN,CAAC;IAED,8DAA8D;IAC9D,kBAAkB;QACd,OAAO,EAAE,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;IACxC,CAAC;IAED,gEAAgE;IAChE,qBAAqB,CAAC,MAA+B;QACjD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;IACjD,CAAC;CACJ;AApID,kCAoIC;AAED,8DAA8D;AAC9D,SAAS,SAAS,CAAC,GAAY;IAC3B,IAAI,OAAO,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC/C,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC7C,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,UAAU,CAAC;IAC1C,OAAO,QAAQ,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Color scheme of the admin dashboard. The dashboard reads it from
|
|
3
|
+
* `GET /qcli/admin/theme.json` before its first render; every token left out
|
|
4
|
+
* keeps the dashboard's default (see the README for the list and defaults).
|
|
5
|
+
*/
|
|
6
|
+
/** Color tokens of the dashboard, the same names on every server. */
|
|
7
|
+
export declare const ADMIN_THEME_TOKENS: readonly ["primary", "primaryHover", "onPrimary", "accent", "background", "backgroundAccent", "sidebar", "surface", "popover", "control", "controlHover", "border", "overlay", "heading", "text", "muted", "subtle", "success", "warning", "error", "info"];
|
|
8
|
+
export type AdminThemeToken = (typeof ADMIN_THEME_TOKENS)[number];
|
|
9
|
+
/** Overrides for one scheme: any subset of the tokens, as CSS colors. */
|
|
10
|
+
export type AdminThemeColors = Partial<Record<AdminThemeToken, string>>;
|
|
11
|
+
/** `dark` (default), `light`, or `system` to follow the browser's preference. */
|
|
12
|
+
export type AdminThemeMode = 'dark' | 'light' | 'system';
|
|
13
|
+
export interface AdminTheme {
|
|
14
|
+
mode?: AdminThemeMode;
|
|
15
|
+
dark?: AdminThemeColors;
|
|
16
|
+
light?: AdminThemeColors;
|
|
17
|
+
}
|
|
18
|
+
/** What `theme.json` returns: the validated theme with the mode filled in. */
|
|
19
|
+
export interface AdminThemeDocument {
|
|
20
|
+
mode: AdminThemeMode;
|
|
21
|
+
dark: AdminThemeColors;
|
|
22
|
+
light: AdminThemeColors;
|
|
23
|
+
}
|
|
24
|
+
/** True when `value` is a color the dashboard accepts. */
|
|
25
|
+
export declare function isThemeColor(value: unknown): value is string;
|
|
26
|
+
/**
|
|
27
|
+
* Validates a theme and returns the document served as `theme.json`.
|
|
28
|
+
* Throws on an unknown mode or token, or a value that is not a plain color.
|
|
29
|
+
*/
|
|
30
|
+
export declare function validateAdminTheme(theme: AdminTheme | undefined | null): AdminThemeDocument;
|
|
31
|
+
//# sourceMappingURL=admin-theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-theme.d.ts","sourceRoot":"","sources":["../../services/admin-theme.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,qEAAqE;AACrE,eAAO,MAAM,kBAAkB,6PAsBrB,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAElE,yEAAyE;AACzE,MAAM,MAAM,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;AAExE,iFAAiF;AACjF,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEzD,MAAM,WAAW,UAAU;IACvB,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,KAAK,CAAC,EAAE,gBAAgB,CAAC;CAC5B;AAED,8EAA8E;AAC9E,MAAM,WAAW,kBAAkB;IAC/B,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,gBAAgB,CAAC;CAC3B;AAiBD,0DAA0D;AAC1D,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAI5D;AAyBD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,GAAG,IAAI,GAAG,kBAAkB,CAc3F"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Color scheme of the admin dashboard. The dashboard reads it from
|
|
4
|
+
* `GET /qcli/admin/theme.json` before its first render; every token left out
|
|
5
|
+
* keeps the dashboard's default (see the README for the list and defaults).
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.ADMIN_THEME_TOKENS = void 0;
|
|
9
|
+
exports.isThemeColor = isThemeColor;
|
|
10
|
+
exports.validateAdminTheme = validateAdminTheme;
|
|
11
|
+
/** Color tokens of the dashboard, the same names on every server. */
|
|
12
|
+
exports.ADMIN_THEME_TOKENS = [
|
|
13
|
+
'primary',
|
|
14
|
+
'primaryHover',
|
|
15
|
+
'onPrimary',
|
|
16
|
+
'accent',
|
|
17
|
+
'background',
|
|
18
|
+
'backgroundAccent',
|
|
19
|
+
'sidebar',
|
|
20
|
+
'surface',
|
|
21
|
+
'popover',
|
|
22
|
+
'control',
|
|
23
|
+
'controlHover',
|
|
24
|
+
'border',
|
|
25
|
+
'overlay',
|
|
26
|
+
'heading',
|
|
27
|
+
'text',
|
|
28
|
+
'muted',
|
|
29
|
+
'subtle',
|
|
30
|
+
'success',
|
|
31
|
+
'warning',
|
|
32
|
+
'error',
|
|
33
|
+
'info',
|
|
34
|
+
];
|
|
35
|
+
const MODES = ['dark', 'light', 'system'];
|
|
36
|
+
const TOKENS = new Set(exports.ADMIN_THEME_TOKENS);
|
|
37
|
+
const MAX_COLOR_LENGTH = 100;
|
|
38
|
+
/**
|
|
39
|
+
* Accepted color syntax: a hex color, a color function with plain numeric
|
|
40
|
+
* arguments, or a named color. Nothing that could end the declaration
|
|
41
|
+
* (`;`, `{`, `}`, quotes) or load anything (`url(`, `var(`) gets through.
|
|
42
|
+
*/
|
|
43
|
+
const COLOR_PATTERNS = [
|
|
44
|
+
/^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i,
|
|
45
|
+
/^(?:rgba?|hsla?|hwb|lab|lch|oklab|oklch)\([0-9a-z.,%+\-\s/]*\)$/i,
|
|
46
|
+
/^[a-z]{3,30}$/i,
|
|
47
|
+
];
|
|
48
|
+
/** True when `value` is a color the dashboard accepts. */
|
|
49
|
+
function isThemeColor(value) {
|
|
50
|
+
if (typeof value !== 'string')
|
|
51
|
+
return false;
|
|
52
|
+
const v = value.trim();
|
|
53
|
+
return v.length > 0 && v.length <= MAX_COLOR_LENGTH && COLOR_PATTERNS.some((p) => p.test(v));
|
|
54
|
+
}
|
|
55
|
+
function validateColors(colors, scheme) {
|
|
56
|
+
if (colors === undefined || colors === null)
|
|
57
|
+
return {};
|
|
58
|
+
if (typeof colors !== 'object' || Array.isArray(colors)) {
|
|
59
|
+
throw new Error(`Invalid admin theme: "${scheme}" must be an object of colors`);
|
|
60
|
+
}
|
|
61
|
+
const result = {};
|
|
62
|
+
for (const [key, value] of Object.entries(colors)) {
|
|
63
|
+
if (!TOKENS.has(key)) {
|
|
64
|
+
throw new Error(`Invalid admin theme: unknown token "${scheme}.${key}" (expected one of ${exports.ADMIN_THEME_TOKENS.join(', ')})`);
|
|
65
|
+
}
|
|
66
|
+
if (value === undefined || value === null)
|
|
67
|
+
continue;
|
|
68
|
+
if (!isThemeColor(value)) {
|
|
69
|
+
throw new Error(`Invalid admin theme color for "${scheme}.${key}": ${JSON.stringify(value)} (use a hex, rgb()/hsl()/oklch() or named color)`);
|
|
70
|
+
}
|
|
71
|
+
result[key] = value.trim();
|
|
72
|
+
}
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Validates a theme and returns the document served as `theme.json`.
|
|
77
|
+
* Throws on an unknown mode or token, or a value that is not a plain color.
|
|
78
|
+
*/
|
|
79
|
+
function validateAdminTheme(theme) {
|
|
80
|
+
const t = (theme ?? {});
|
|
81
|
+
if (typeof t !== 'object' || Array.isArray(t)) {
|
|
82
|
+
throw new Error('Invalid admin theme: expected an object');
|
|
83
|
+
}
|
|
84
|
+
const mode = t.mode ?? 'dark';
|
|
85
|
+
if (typeof mode !== 'string' || !MODES.includes(mode)) {
|
|
86
|
+
throw new Error(`Invalid admin theme mode ${JSON.stringify(mode)} (expected dark, light or system)`);
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
mode: mode,
|
|
90
|
+
dark: validateColors(t.dark, 'dark'),
|
|
91
|
+
light: validateColors(t.light, 'light'),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=admin-theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-theme.js","sourceRoot":"","sources":["../../services/admin-theme.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the dashboard dist directory. Looks for:
|
|
3
|
+
* 1. The explicitly set path
|
|
4
|
+
* 2. The sibling cli-server-dashboard repo (development), so a fresh build is served
|
|
5
|
+
* 3. The dashboard bundled into this package (copy-dashboard)
|
|
6
|
+
* 4. ../cli-server-dashboard/dist relative to the working directory
|
|
7
|
+
* 5. @qodalis/cli-server-dashboard/dist (npm package)
|
|
8
|
+
*/
|
|
9
|
+
export declare function resolveDashboardDir(explicitDir?: string, moduleDir?: string, cwd?: string): string | null;
|
|
10
|
+
//# sourceMappingURL=dashboard-dir.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-dir.d.ts","sourceRoot":"","sources":["../../services/dashboard-dir.ts"],"names":[],"mappings":"AAyBA;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAC/B,WAAW,CAAC,EAAE,MAAM,EACpB,SAAS,GAAE,MAAkB,EAC7B,GAAG,GAAE,MAAsB,GAC5B,MAAM,GAAG,IAAI,CAcf"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveDashboardDir = resolveDashboardDir;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
/**
|
|
7
|
+
* The plugin's package root: the nearest directory with a package.json,
|
|
8
|
+
* whether this code runs compiled (dist/) or from source (tsx, vitest).
|
|
9
|
+
*/
|
|
10
|
+
function findPackageRoot(moduleDir) {
|
|
11
|
+
let dir = (0, path_1.resolve)(moduleDir);
|
|
12
|
+
for (let i = 0; i < 3; i++) {
|
|
13
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(dir, 'package.json')))
|
|
14
|
+
return dir;
|
|
15
|
+
dir = (0, path_1.dirname)(dir);
|
|
16
|
+
}
|
|
17
|
+
return (0, path_1.resolve)(moduleDir);
|
|
18
|
+
}
|
|
19
|
+
function resolveNpmDashboard() {
|
|
20
|
+
try {
|
|
21
|
+
const pkgPath = require.resolve('@qodalis/cli-server-dashboard/package.json');
|
|
22
|
+
return (0, path_1.join)((0, path_1.dirname)(pkgPath), 'dist');
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return null; // Package not installed
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Resolve the dashboard dist directory. Looks for:
|
|
30
|
+
* 1. The explicitly set path
|
|
31
|
+
* 2. The sibling cli-server-dashboard repo (development), so a fresh build is served
|
|
32
|
+
* 3. The dashboard bundled into this package (copy-dashboard)
|
|
33
|
+
* 4. ../cli-server-dashboard/dist relative to the working directory
|
|
34
|
+
* 5. @qodalis/cli-server-dashboard/dist (npm package)
|
|
35
|
+
*/
|
|
36
|
+
function resolveDashboardDir(explicitDir, moduleDir = __dirname, cwd = process.cwd()) {
|
|
37
|
+
const root = findPackageRoot(moduleDir);
|
|
38
|
+
const candidates = [
|
|
39
|
+
explicitDir,
|
|
40
|
+
(0, path_1.resolve)(root, '..', '..', '..', 'cli-server-dashboard', 'dist'),
|
|
41
|
+
(0, path_1.join)(root, 'dashboard'),
|
|
42
|
+
(0, path_1.resolve)(cwd, '..', 'cli-server-dashboard', 'dist'),
|
|
43
|
+
resolveNpmDashboard(),
|
|
44
|
+
];
|
|
45
|
+
for (const dir of candidates) {
|
|
46
|
+
if (dir && (0, fs_1.existsSync)((0, path_1.join)(dir, 'index.html')))
|
|
47
|
+
return (0, path_1.resolve)(dir);
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=dashboard-dir.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-dir.js","sourceRoot":"","sources":["../../services/dashboard-dir.ts"],"names":[],"mappings":";;AAiCA,kDAkBC;AAnDD,2BAAgC;AAChC,+BAA8C;AAE9C;;;GAGG;AACH,SAAS,eAAe,CAAC,SAAiB;IACtC,IAAI,GAAG,GAAG,IAAA,cAAO,EAAC,SAAS,CAAC,CAAC;IAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACzB,IAAI,IAAA,eAAU,EAAC,IAAA,WAAI,EAAC,GAAG,EAAE,cAAc,CAAC,CAAC;YAAE,OAAO,GAAG,CAAC;QACtD,GAAG,GAAG,IAAA,cAAO,EAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,IAAA,cAAO,EAAC,SAAS,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,mBAAmB;IACxB,IAAI,CAAC;QACD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,4CAA4C,CAAC,CAAC;QAC9E,OAAO,IAAA,WAAI,EAAC,IAAA,cAAO,EAAC,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,IAAI,CAAC,CAAC,wBAAwB;IACzC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,mBAAmB,CAC/B,WAAoB,EACpB,YAAoB,SAAS,EAC7B,MAAc,OAAO,CAAC,GAAG,EAAE;IAE3B,MAAM,IAAI,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IACxC,MAAM,UAAU,GAAG;QACf,WAAW;QACX,IAAA,cAAO,EAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,sBAAsB,EAAE,MAAM,CAAC;QAC/D,IAAA,WAAI,EAAC,IAAI,EAAE,WAAW,CAAC;QACvB,IAAA,cAAO,EAAC,GAAG,EAAE,IAAI,EAAE,sBAAsB,EAAE,MAAM,CAAC;QAClD,mBAAmB,EAAE;KACxB,CAAC;IAEF,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC3B,IAAI,GAAG,IAAI,IAAA,eAAU,EAAC,IAAA,WAAI,EAAC,GAAG,EAAE,YAAY,CAAC,CAAC;YAAE,OAAO,IAAA,cAAO,EAAC,GAAG,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC"}
|
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Circular buffer capturing application logs for the admin dashboard.
|
|
3
3
|
*/
|
|
4
|
+
/** A single log entry captured by the ring buffer. */
|
|
4
5
|
export interface LogEntry {
|
|
5
6
|
timestamp: string;
|
|
6
7
|
level: 'INFO' | 'WARN' | 'ERROR' | 'DEBUG';
|
|
7
8
|
message: string;
|
|
8
9
|
source: string;
|
|
9
10
|
}
|
|
11
|
+
/** Filtering and pagination parameters for querying the log buffer. */
|
|
10
12
|
export interface LogQueryParams {
|
|
11
13
|
level?: string;
|
|
12
14
|
search?: string;
|
|
13
15
|
limit?: number;
|
|
14
16
|
offset?: number;
|
|
15
17
|
}
|
|
18
|
+
/** Result of a log buffer query, including matched entries and total count. */
|
|
16
19
|
export interface LogQueryResult {
|
|
17
20
|
entries: LogEntry[];
|
|
18
21
|
total: number;
|
|
19
22
|
}
|
|
23
|
+
/** Replaces values that look like secrets (see {@link SECRET_PATTERN}) with `[REDACTED]`. */
|
|
24
|
+
export declare function redactSecrets(message: string): string;
|
|
20
25
|
export declare class LogRingBuffer {
|
|
21
26
|
private readonly _buffer;
|
|
22
27
|
private readonly _capacity;
|
|
@@ -27,6 +32,7 @@ export declare class LogRingBuffer {
|
|
|
27
32
|
private _origWarn?;
|
|
28
33
|
private _origError?;
|
|
29
34
|
constructor(capacity?: number);
|
|
35
|
+
/** Set the function used to broadcast new log entries (e.g. via WebSocket). */
|
|
30
36
|
setBroadcastFn(fn: (message: Record<string, unknown>) => void): void;
|
|
31
37
|
/**
|
|
32
38
|
* Add a log entry to the buffer.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-ring-buffer.d.ts","sourceRoot":"","sources":["../../services/log-ring-buffer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,QAAQ;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC3B,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,aAAa;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,YAAY,CAAC,CAA6C;IAElE,OAAO,CAAC,QAAQ,CAAC,CAAqB;IACtC,OAAO,CAAC,SAAS,CAAC,CAAsB;IACxC,OAAO,CAAC,UAAU,CAAC,CAAuB;gBAE9B,QAAQ,SAAO;IAK3B,cAAc,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,IAAI;IAIpE;;OAEG;IACH,IAAI,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"log-ring-buffer.d.ts","sourceRoot":"","sources":["../../services/log-ring-buffer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,sDAAsD;AACtD,MAAM,WAAW,QAAQ;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,uEAAuE;AACvE,MAAM,WAAW,cAAc;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC3B,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACjB;AAQD,6FAA6F;AAC7F,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,qBAAa,aAAa;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,YAAY,CAAC,CAA6C;IAElE,OAAO,CAAC,QAAQ,CAAC,CAAqB;IACtC,OAAO,CAAC,SAAS,CAAC,CAAsB;IACxC,OAAO,CAAC,UAAU,CAAC,CAAuB;gBAE9B,QAAQ,SAAO;IAK3B,+EAA+E;IAC/E,cAAc,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,IAAI;IAIpE;;OAEG;IACH,IAAI,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAkB3B;;OAEG;IACH,KAAK,CAAC,MAAM,GAAE,cAAmB,GAAG,cAAc;IAqBlD;;OAEG;IACH,OAAO,CAAC,MAAM;IAWd;;OAEG;IACH,gBAAgB,IAAI,IAAI;IAoCxB;;OAEG;IACH,cAAc,IAAI,IAAI;CAKzB"}
|
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.LogRingBuffer = void 0;
|
|
7
|
+
exports.redactSecrets = redactSecrets;
|
|
8
|
+
/**
|
|
9
|
+
* Matches a secret written after a `password`/`secret`/`token` label
|
|
10
|
+
* (`password: x`, `token=x`, `password for user "root": x`).
|
|
11
|
+
*/
|
|
12
|
+
const SECRET_PATTERN = /\b((?:password|passwd|secret|token)\b(?:\s+for\s+user\s+"[^"]*")?\s*[:=]\s*)("[^"]*"|'[^']*'|\S+)/gi;
|
|
13
|
+
/** Replaces values that look like secrets (see {@link SECRET_PATTERN}) with `[REDACTED]`. */
|
|
14
|
+
function redactSecrets(message) {
|
|
15
|
+
return message.replace(SECRET_PATTERN, '$1[REDACTED]');
|
|
16
|
+
}
|
|
7
17
|
class LogRingBuffer {
|
|
8
18
|
_buffer;
|
|
9
19
|
_capacity;
|
|
@@ -17,6 +27,7 @@ class LogRingBuffer {
|
|
|
17
27
|
this._capacity = capacity;
|
|
18
28
|
this._buffer = new Array(capacity);
|
|
19
29
|
}
|
|
30
|
+
/** Set the function used to broadcast new log entries (e.g. via WebSocket). */
|
|
20
31
|
setBroadcastFn(fn) {
|
|
21
32
|
this._broadcastFn = fn;
|
|
22
33
|
}
|
|
@@ -24,6 +35,8 @@ class LogRingBuffer {
|
|
|
24
35
|
* Add a log entry to the buffer.
|
|
25
36
|
*/
|
|
26
37
|
push(entry) {
|
|
38
|
+
// Safety net: entries are served to the dashboard and broadcast to sockets
|
|
39
|
+
entry.message = redactSecrets(entry.message);
|
|
27
40
|
entry.level = entry.level.toUpperCase();
|
|
28
41
|
this._buffer[this._head] = entry;
|
|
29
42
|
this._head = (this._head + 1) % this._capacity;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-ring-buffer.js","sourceRoot":"","sources":["../../services/log-ring-buffer.ts"],"names":[],"mappings":";AAAA;;GAEG;;;
|
|
1
|
+
{"version":3,"file":"log-ring-buffer.js","sourceRoot":"","sources":["../../services/log-ring-buffer.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ICliModule, ICliCommandProcessor } from '@qodalis/cli-server-abstractions';
|
|
1
|
+
import { ICliModule, ICliCommandProcessor, ICliProcessorFilter } from '@qodalis/cli-server-abstractions';
|
|
2
2
|
/**
|
|
3
3
|
* Provides information about a tracked module for the admin dashboard.
|
|
4
4
|
*/
|
|
@@ -27,27 +27,40 @@ export interface IBuilderLike {
|
|
|
27
27
|
readonly modules: ReadonlyArray<ICliModule>;
|
|
28
28
|
readonly fileStorageProvider?: unknown;
|
|
29
29
|
readonly fileSystemOptions?: unknown;
|
|
30
|
+
/**
|
|
31
|
+
* The server's runtime options (`CliServerRuntimeOptions` of `@qodalis/cli-server-node`):
|
|
32
|
+
* `externalAuthentication` selects the dashboard's sign-in mode, `jobsEnabled` reports "jobs".
|
|
33
|
+
*/
|
|
34
|
+
readonly serverOptions?: {
|
|
35
|
+
readonly externalAuthentication?: boolean;
|
|
36
|
+
readonly jobsEnabled?: boolean;
|
|
37
|
+
};
|
|
30
38
|
}
|
|
31
39
|
/**
|
|
32
40
|
* Tracks registered CLI modules and allows toggling them on/off.
|
|
41
|
+
* Implements {@link ICliProcessorFilter} to block execution of processors belonging to disabled modules.
|
|
33
42
|
*/
|
|
34
|
-
export declare class ModuleRegistry {
|
|
43
|
+
export declare class ModuleRegistry implements ICliProcessorFilter {
|
|
35
44
|
private readonly _tracked;
|
|
45
|
+
private readonly _processorToModuleId;
|
|
36
46
|
private readonly _registry;
|
|
37
47
|
private readonly _builder;
|
|
38
48
|
constructor(registry: IRegistryLike, builder: IBuilderLike);
|
|
49
|
+
/**
|
|
50
|
+
* Determines whether the given command processor is allowed to execute.
|
|
51
|
+
* Returns false when the processor belongs to a disabled module.
|
|
52
|
+
*/
|
|
53
|
+
isAllowed(processor: ICliCommandProcessor): boolean;
|
|
39
54
|
/**
|
|
40
55
|
* List all tracked modules with their current status.
|
|
41
56
|
*/
|
|
42
57
|
list(): ModuleInfo[];
|
|
43
58
|
/**
|
|
44
59
|
* Toggle a module's enabled/disabled state.
|
|
45
|
-
* When disabled,
|
|
46
|
-
* When enabled, they are re-registered.
|
|
60
|
+
* When disabled, processors are blocked at execution time via the filter.
|
|
61
|
+
* When enabled, they are re-registered if needed.
|
|
47
62
|
*/
|
|
48
|
-
toggle(id: string):
|
|
49
|
-
warning?: string;
|
|
50
|
-
}) | undefined;
|
|
63
|
+
toggle(id: string): ModuleInfo | undefined;
|
|
51
64
|
private moduleId;
|
|
52
65
|
private toInfo;
|
|
53
66
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-registry.d.ts","sourceRoot":"","sources":["../../services/module-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"module-registry.d.ts","sourceRoot":"","sources":["../../services/module-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAEzG;;GAEG;AACH,MAAM,WAAW,UAAU;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,EAAE,CAAC;CACxB;AAQD;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC1B,QAAQ,CAAC,SAAS,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAChD,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAAC;CAC5D;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IACzB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IAC5C,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IACvC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IACrC;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE;QAAE,QAAQ,CAAC,sBAAsB,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAC1G;AAED;;;GAGG;AACH,qBAAa,cAAe,YAAW,mBAAmB;IACtD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoC;IAC7D,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAA2C;IAChF,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgB;IAC1C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;gBAE5B,QAAQ,EAAE,aAAa,EAAE,OAAO,EAAE,YAAY;IAkB1D;;;OAGG;IACH,SAAS,CAAC,SAAS,EAAE,oBAAoB,GAAG,OAAO;IAUnD;;OAEG;IACH,IAAI,IAAI,UAAU,EAAE;IAepB;;;;OAIG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAgB1C,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,MAAM;CAcjB"}
|
|
@@ -3,9 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ModuleRegistry = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Tracks registered CLI modules and allows toggling them on/off.
|
|
6
|
+
* Implements {@link ICliProcessorFilter} to block execution of processors belonging to disabled modules.
|
|
6
7
|
*/
|
|
7
8
|
class ModuleRegistry {
|
|
8
9
|
_tracked = new Map();
|
|
10
|
+
_processorToModuleId = new Map();
|
|
9
11
|
_registry;
|
|
10
12
|
_builder;
|
|
11
13
|
constructor(registry, builder) {
|
|
@@ -19,7 +21,23 @@ class ModuleRegistry {
|
|
|
19
21
|
enabled: true,
|
|
20
22
|
processors: [...mod.processors],
|
|
21
23
|
});
|
|
24
|
+
for (const processor of mod.processors) {
|
|
25
|
+
this._processorToModuleId.set(processor, id);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Determines whether the given command processor is allowed to execute.
|
|
31
|
+
* Returns false when the processor belongs to a disabled module.
|
|
32
|
+
*/
|
|
33
|
+
isAllowed(processor) {
|
|
34
|
+
const moduleId = this._processorToModuleId.get(processor);
|
|
35
|
+
if (!moduleId) {
|
|
36
|
+
// Processor is not part of any tracked module — allow by default
|
|
37
|
+
return true;
|
|
22
38
|
}
|
|
39
|
+
const tracked = this._tracked.get(moduleId);
|
|
40
|
+
return tracked ? tracked.enabled : true;
|
|
23
41
|
}
|
|
24
42
|
/**
|
|
25
43
|
* List all tracked modules with their current status.
|
|
@@ -40,27 +58,21 @@ class ModuleRegistry {
|
|
|
40
58
|
}
|
|
41
59
|
/**
|
|
42
60
|
* Toggle a module's enabled/disabled state.
|
|
43
|
-
* When disabled,
|
|
44
|
-
* When enabled, they are re-registered.
|
|
61
|
+
* When disabled, processors are blocked at execution time via the filter.
|
|
62
|
+
* When enabled, they are re-registered if needed.
|
|
45
63
|
*/
|
|
46
64
|
toggle(id) {
|
|
47
65
|
const tracked = this._tracked.get(id);
|
|
48
66
|
if (!tracked)
|
|
49
67
|
return undefined;
|
|
50
68
|
tracked.enabled = !tracked.enabled;
|
|
51
|
-
let warning;
|
|
52
69
|
if (tracked.enabled) {
|
|
53
|
-
// Re-register processors
|
|
70
|
+
// Re-register processors in case they were removed
|
|
54
71
|
for (const processor of tracked.processors) {
|
|
55
72
|
this._registry.register(processor);
|
|
56
73
|
}
|
|
57
74
|
}
|
|
58
|
-
|
|
59
|
-
// We can't "unregister" from the current CliCommandRegistry directly
|
|
60
|
-
// since it only has register(). We track the state but processors remain active.
|
|
61
|
-
warning = 'Module state tracked but command unregistration is not yet supported. Processors remain active.';
|
|
62
|
-
}
|
|
63
|
-
return { ...this.toInfo(tracked), warning };
|
|
75
|
+
return this.toInfo(tracked);
|
|
64
76
|
}
|
|
65
77
|
moduleId(mod) {
|
|
66
78
|
return mod.name.toLowerCase().replace(/\s+/g, '-');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-registry.js","sourceRoot":"","sources":["../../services/module-registry.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"module-registry.js","sourceRoot":"","sources":["../../services/module-registry.ts"],"names":[],"mappings":"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"}
|