@jsbot-tellus/core 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/bot.config.example.json +3 -0
- package/dist/app.js +215 -98
- package/dist/app.js.map +1 -1
- package/dist/core/client.d.ts +1 -0
- package/dist/core/client.d.ts.map +1 -1
- package/dist/core/client.js +3 -0
- package/dist/core/client.js.map +1 -1
- package/dist/core/config/schema.d.ts +19 -0
- package/dist/core/config/schema.d.ts.map +1 -1
- package/dist/core/config/schema.js +37 -0
- package/dist/core/config/schema.js.map +1 -1
- package/dist/core/dispatch/router.d.ts +3 -0
- package/dist/core/dispatch/router.d.ts.map +1 -1
- package/dist/core/dispatch/router.js +13 -0
- package/dist/core/dispatch/router.js.map +1 -1
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/kernel.d.ts +8 -0
- package/dist/core/kernel.d.ts.map +1 -1
- package/dist/core/kernel.js +17 -0
- package/dist/core/kernel.js.map +1 -1
- package/dist/core/logging/log-buffer.d.ts +27 -0
- package/dist/core/logging/log-buffer.d.ts.map +1 -0
- package/dist/core/logging/log-buffer.js +71 -0
- package/dist/core/logging/log-buffer.js.map +1 -0
- package/dist/core/logging/logger.d.ts +3 -0
- package/dist/core/logging/logger.d.ts.map +1 -1
- package/dist/core/logging/logger.js +6 -3
- package/dist/core/logging/logger.js.map +1 -1
- package/dist/core/plugin/command-params.d.ts +2 -2
- package/dist/core/plugin/command-params.d.ts.map +1 -1
- package/dist/core/plugin/command-params.js +35 -0
- package/dist/core/plugin/command-params.js.map +1 -1
- package/dist/core/storage/session.d.ts +15 -0
- package/dist/core/storage/session.d.ts.map +1 -1
- package/dist/core/storage/session.js +55 -0
- package/dist/core/storage/session.js.map +1 -1
- package/dist/core/web/api.d.ts +16 -0
- package/dist/core/web/api.d.ts.map +1 -0
- package/dist/core/web/api.js +617 -0
- package/dist/core/web/api.js.map +1 -0
- package/dist/core/web/auth.d.ts +43 -0
- package/dist/core/web/auth.d.ts.map +1 -0
- package/dist/core/web/auth.js +161 -0
- package/dist/core/web/auth.js.map +1 -0
- package/dist/core/web/config-store.d.ts +30 -0
- package/dist/core/web/config-store.d.ts.map +1 -0
- package/dist/core/web/config-store.js +216 -0
- package/dist/core/web/config-store.js.map +1 -0
- package/dist/core/web/event-feed.d.ts +26 -0
- package/dist/core/web/event-feed.d.ts.map +1 -0
- package/dist/core/web/event-feed.js +107 -0
- package/dist/core/web/event-feed.js.map +1 -0
- package/dist/core/web/http.d.ts +39 -0
- package/dist/core/web/http.d.ts.map +1 -0
- package/dist/core/web/http.js +233 -0
- package/dist/core/web/http.js.map +1 -0
- package/dist/core/web/index.d.ts +11 -0
- package/dist/core/web/index.d.ts.map +1 -0
- package/dist/core/web/index.js +6 -0
- package/dist/core/web/index.js.map +1 -0
- package/dist/core/web/server.d.ts +30 -0
- package/dist/core/web/server.d.ts.map +1 -0
- package/dist/core/web/server.js +437 -0
- package/dist/core/web/server.js.map +1 -0
- package/dist/core/web/types.d.ts +84 -0
- package/dist/core/web/types.d.ts.map +1 -0
- package/dist/core/web/types.js +2 -0
- package/dist/core/web/types.js.map +1 -0
- package/dist/webui/assets/ActionsView-BDuXBWG1.js +1 -0
- package/dist/webui/assets/ActionsView-Ciib5lC6.css +1 -0
- package/dist/webui/assets/ConfigView-B3Gv2uRG.js +1 -0
- package/dist/webui/assets/ConfigView-CrEpss2y.css +1 -0
- package/dist/webui/assets/DashboardView-DR6yCaqs.css +1 -0
- package/dist/webui/assets/DashboardView-n9LGPmQL.js +1 -0
- package/dist/webui/assets/EventsView-DhO8twWb.js +1 -0
- package/dist/webui/assets/EventsView-PMkYKxZ-.css +1 -0
- package/dist/webui/assets/KvView-BCz_dOVC.js +1 -0
- package/dist/webui/assets/KvView-CaMvbxUz.css +1 -0
- package/dist/webui/assets/LoginView-BVnFkwSW.css +1 -0
- package/dist/webui/assets/LoginView-Br3_AC5z.js +1 -0
- package/dist/webui/assets/LogsView-Ba_12frI.js +1 -0
- package/dist/webui/assets/LogsView-NR4L1-XY.css +1 -0
- package/dist/webui/assets/MainLayout-D2LTc57u.js +1 -0
- package/dist/webui/assets/MainLayout-glfVNbMz.css +1 -0
- package/dist/webui/assets/PluginsView-DL9OxGph.css +1 -0
- package/dist/webui/assets/PluginsView-vQKBSCU8.js +1 -0
- package/dist/webui/assets/SessionsView-DSl37qpo.js +1 -0
- package/dist/webui/assets/SessionsView-p-u3JGTV.css +1 -0
- package/dist/webui/assets/api-CNzxhTWe.js +3 -0
- package/dist/webui/assets/index-CUvpnClx.js +50 -0
- package/dist/webui/assets/index-CePlRZX6.css +1 -0
- package/dist/webui/index.html +110 -0
- package/docs/plugin-api.md +1 -0
- package/docs/webui.md +142 -0
- package/package.json +14 -3
- package/src/app.ts +286 -118
- package/src/core/client.ts +4 -0
- package/src/core/config/schema.ts +40 -0
- package/src/core/dispatch/router.ts +15 -0
- package/src/core/index.ts +3 -0
- package/src/core/kernel.ts +25 -1
- package/src/core/logging/log-buffer.ts +109 -0
- package/src/core/logging/logger.ts +7 -3
- package/src/core/plugin/command-params.ts +48 -2
- package/src/core/storage/session.ts +95 -0
- package/src/core/web/api.ts +932 -0
- package/src/core/web/auth.ts +245 -0
- package/src/core/web/config-store.ts +333 -0
- package/src/core/web/event-feed.ts +163 -0
- package/src/core/web/http.ts +340 -0
- package/src/core/web/index.ts +25 -0
- package/src/core/web/server.ts +621 -0
- package/src/core/web/types.ts +100 -0
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
import { createServer, } from 'node:http';
|
|
2
|
+
import { createReadStream, readFileSync } from 'node:fs';
|
|
3
|
+
import { stat } from 'node:fs/promises';
|
|
4
|
+
import { extname, join, resolve, sep } from 'node:path';
|
|
5
|
+
import { createHash } from 'node:crypto';
|
|
6
|
+
import { AuthManager } from './auth.js';
|
|
7
|
+
import { handleApiRoute } from './api.js';
|
|
8
|
+
import { assertCsrf, assertSameOrigin, clearCookie, clientIp, isImmutableAsset, mimeType, parseCookies, readJsonBody, respondWithError, safeStringify, sendError, sendData, serializeCookie, withTimeout, } from './http.js';
|
|
9
|
+
import { HttpError } from './http.js';
|
|
10
|
+
const SESSION_COOKIE = 'jsbot_webui';
|
|
11
|
+
const WRITE_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);
|
|
12
|
+
const SECURITY_HEADERS = {
|
|
13
|
+
'x-content-type-options': 'nosniff',
|
|
14
|
+
'x-frame-options': 'DENY',
|
|
15
|
+
'referrer-policy': 'no-referrer',
|
|
16
|
+
'cross-origin-opener-policy': 'same-origin',
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* CSP for the WebUI. webui/index.html ships a single authorized inline
|
|
20
|
+
* script (the no-flash appearance bootstrap for the first paint); its exact
|
|
21
|
+
* hash is derived from the built index.html on disk so editing the bootstrap
|
|
22
|
+
* only needs a rebuild, never a source edit. Every other inline script
|
|
23
|
+
* stays blocked.
|
|
24
|
+
*/
|
|
25
|
+
function buildCsp(scriptSrc) {
|
|
26
|
+
return `default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src ${scriptSrc}; connect-src 'self'; frame-ancestors 'none'; base-uri 'none'; form-action 'self'`;
|
|
27
|
+
}
|
|
28
|
+
/** Extracts the bootstrap script's sha256 from a built index.html. */
|
|
29
|
+
function cspForStaticDir(staticDir) {
|
|
30
|
+
try {
|
|
31
|
+
const html = readFileSync(join(staticDir, 'index.html'), 'utf8');
|
|
32
|
+
const match = /<script>([\s\S]*?)<\/script>/.exec(html);
|
|
33
|
+
const bootstrap = match?.[1];
|
|
34
|
+
if (bootstrap === undefined)
|
|
35
|
+
return null;
|
|
36
|
+
const hash = createHash('sha256')
|
|
37
|
+
.update(bootstrap, 'utf8')
|
|
38
|
+
.digest('base64');
|
|
39
|
+
return buildCsp(`'self' 'sha256-${hash}'`);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const SSE_HEARTBEAT_MS = 15_000;
|
|
46
|
+
const DEFAULT_MAX_SSE_CLIENTS = 20;
|
|
47
|
+
const SSE_TIMEOUT_MS = 60_000;
|
|
48
|
+
const FALLBACK_BODY = (options) => `<!doctype html>
|
|
49
|
+
<html lang="zh-CN"><head><meta charset="utf-8">
|
|
50
|
+
<title>JsBot WebUI</title>
|
|
51
|
+
<style>body{font-family:system-ui,sans-serif;max-width:36em;margin:4rem auto;padding:0 1rem;color:#333}</style>
|
|
52
|
+
</head><body>
|
|
53
|
+
<h1>WebUI 前端未构建</h1>
|
|
54
|
+
<p>管理 API 正常运行,但静态资源缺失。请在项目根目录执行:</p>
|
|
55
|
+
<pre><code>npm run build:webui</code></pre>
|
|
56
|
+
<p>然后重启进程,访问 <code>${options.listening}</code>。</p>
|
|
57
|
+
<p>API 仍可通过 <code>/api/health</code>、登录和各接口访问。</p>
|
|
58
|
+
</body></html>
|
|
59
|
+
`;
|
|
60
|
+
function errorPayload(error) {
|
|
61
|
+
if (error instanceof HttpError) {
|
|
62
|
+
return {
|
|
63
|
+
status: error.status,
|
|
64
|
+
message: error.message,
|
|
65
|
+
details: error.details,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
status: 500,
|
|
70
|
+
message: error instanceof Error ? error.message : 'internal error',
|
|
71
|
+
details: undefined,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function parseSearch(req) {
|
|
75
|
+
const index = (req.url ?? '').indexOf('?');
|
|
76
|
+
const query = index >= 0 ? (req.url ?? '').slice(index + 1) : '';
|
|
77
|
+
return new URLSearchParams(query);
|
|
78
|
+
}
|
|
79
|
+
function segmentsOf(pathname) {
|
|
80
|
+
return pathname
|
|
81
|
+
.split('/')
|
|
82
|
+
.filter((segment) => segment.length > 0)
|
|
83
|
+
.map((segment) => {
|
|
84
|
+
try {
|
|
85
|
+
return decodeURIComponent(segment);
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return segment;
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function pathnameOf(req) {
|
|
93
|
+
const url = req.url ?? '/';
|
|
94
|
+
const index = url.indexOf('?');
|
|
95
|
+
const raw = index >= 0 ? url.slice(0, index) : url;
|
|
96
|
+
if (raw.includes('%')) {
|
|
97
|
+
try {
|
|
98
|
+
return decodeURIComponent(raw);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return raw;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return raw;
|
|
105
|
+
}
|
|
106
|
+
export class WebUiServer {
|
|
107
|
+
deps;
|
|
108
|
+
maxSseClients;
|
|
109
|
+
bodyLimit;
|
|
110
|
+
loginMaxFailures;
|
|
111
|
+
loginWindowMs;
|
|
112
|
+
auth;
|
|
113
|
+
sse = new Set();
|
|
114
|
+
fallbackBody;
|
|
115
|
+
httpServer = null;
|
|
116
|
+
listening = null;
|
|
117
|
+
cspCache = null;
|
|
118
|
+
constructor(options) {
|
|
119
|
+
const { config, deps } = options;
|
|
120
|
+
this.deps = deps;
|
|
121
|
+
this.maxSseClients = options.maxSseClients ?? DEFAULT_MAX_SSE_CLIENTS;
|
|
122
|
+
this.bodyLimit = options.bodyLimitBytes ?? 1_048_576;
|
|
123
|
+
this.loginMaxFailures = options.loginMaxFailures;
|
|
124
|
+
this.loginWindowMs = options.loginWindowMs;
|
|
125
|
+
this.fallbackBody = FALLBACK_BODY({
|
|
126
|
+
listening: `http://${config.host}:${config.port}`,
|
|
127
|
+
});
|
|
128
|
+
this.auth = new AuthManager({
|
|
129
|
+
getConfig: () => deps.getWebUiConfig(),
|
|
130
|
+
...(options.loginMaxFailures !== undefined
|
|
131
|
+
? { maxFailures: options.loginMaxFailures }
|
|
132
|
+
: {}),
|
|
133
|
+
...(options.loginWindowMs !== undefined
|
|
134
|
+
? { windowMs: options.loginWindowMs }
|
|
135
|
+
: {}),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
get address() {
|
|
139
|
+
return this.listening;
|
|
140
|
+
}
|
|
141
|
+
async start(config) {
|
|
142
|
+
if (this.httpServer !== null)
|
|
143
|
+
return this.listening;
|
|
144
|
+
const server = createServer(this.handleRequest.bind(this));
|
|
145
|
+
try {
|
|
146
|
+
await new Promise((resolvePromise, reject) => {
|
|
147
|
+
server.once('error', reject);
|
|
148
|
+
server.listen(config.port, config.host, () => {
|
|
149
|
+
server.off('error', reject);
|
|
150
|
+
resolvePromise();
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
const address = server.address();
|
|
154
|
+
if (address === null) {
|
|
155
|
+
this.listening = {
|
|
156
|
+
host: config.host,
|
|
157
|
+
port: config.port,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
else if (typeof address === 'string') {
|
|
161
|
+
this.listening = { host: address, port: config.port };
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
this.listening = {
|
|
165
|
+
host: config.host,
|
|
166
|
+
port: address.port,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
this.httpServer = server;
|
|
170
|
+
this.deps.logger.info(`webui listening on http://${config.host}:${this.listening.port}`);
|
|
171
|
+
return this.listening;
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
this.deps.logger.error('webui listen failed', error);
|
|
175
|
+
server.close();
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
get requiresRestart() {
|
|
180
|
+
return this.httpServer !== null;
|
|
181
|
+
}
|
|
182
|
+
async stop() {
|
|
183
|
+
for (const connection of [...this.sse])
|
|
184
|
+
connection.close();
|
|
185
|
+
this.sse.clear();
|
|
186
|
+
this.auth.invalidateAll();
|
|
187
|
+
const server = this.httpServer;
|
|
188
|
+
if (server === null)
|
|
189
|
+
return;
|
|
190
|
+
this.httpServer = null;
|
|
191
|
+
this.listening = null;
|
|
192
|
+
await new Promise((resolvePromise) => {
|
|
193
|
+
server.close(() => resolvePromise());
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
invalidateSessions() {
|
|
197
|
+
this.auth.invalidateAll();
|
|
198
|
+
}
|
|
199
|
+
applySecurityHeaders(res) {
|
|
200
|
+
for (const [key, value] of Object.entries(SECURITY_HEADERS)) {
|
|
201
|
+
res.setHeader(key, value);
|
|
202
|
+
}
|
|
203
|
+
if (this.cspCache === null) {
|
|
204
|
+
// Derived once per server instance from the built index.html.
|
|
205
|
+
const staticDir = this.deps.paths.staticDir;
|
|
206
|
+
this.cspCache =
|
|
207
|
+
staticDir !== null
|
|
208
|
+
? (cspForStaticDir(staticDir) ?? buildCsp("'self'"))
|
|
209
|
+
: buildCsp("'self'");
|
|
210
|
+
}
|
|
211
|
+
res.setHeader('content-security-policy', this.cspCache);
|
|
212
|
+
}
|
|
213
|
+
async handleRequest(req, res) {
|
|
214
|
+
this.applySecurityHeaders(res);
|
|
215
|
+
try {
|
|
216
|
+
const pathname = pathnameOf(req);
|
|
217
|
+
if (pathname === '/api/health') {
|
|
218
|
+
res.setHeader('cache-control', 'no-store');
|
|
219
|
+
sendData(res, 200, { ok: true });
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (!pathname.startsWith('/api/') && pathname !== '/api') {
|
|
223
|
+
await this.serveStatic(req, res, pathname);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
if (!WRITE_METHODS.has(req.method ?? 'GET')) {
|
|
227
|
+
assertSameOrigin(req, this.deps.getWebUiConfig().trustProxy);
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
assertSameOrigin(req, this.deps.getWebUiConfig().trustProxy);
|
|
231
|
+
assertCsrf(req);
|
|
232
|
+
}
|
|
233
|
+
const segments = segmentsOf(pathname);
|
|
234
|
+
if (segments[1] === 'auth') {
|
|
235
|
+
await this.handleAuth(req, res, segments[2]);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
const session = this.authenticate(req);
|
|
239
|
+
if (session === null) {
|
|
240
|
+
throw new HttpError(401, '未登录或会话已过期');
|
|
241
|
+
}
|
|
242
|
+
if (segments[1] === 'logs' && segments[2] === 'stream') {
|
|
243
|
+
this.openSse(req, res, (listener) => this.deps.logs.subscribe(listener), Date.now());
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (segments[1] === 'events' && segments[2] === 'stream') {
|
|
247
|
+
this.openSse(req, res, (listener) => this.deps.events.subscribe(listener), Date.now());
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const handled = await handleApiRoute({
|
|
251
|
+
deps: this.deps,
|
|
252
|
+
req,
|
|
253
|
+
res,
|
|
254
|
+
method: req.method ?? 'GET',
|
|
255
|
+
pathname,
|
|
256
|
+
segments,
|
|
257
|
+
search: parseSearch(req),
|
|
258
|
+
session,
|
|
259
|
+
});
|
|
260
|
+
if (handled)
|
|
261
|
+
return;
|
|
262
|
+
throw new HttpError(404, `not found: ${req.method} ${pathname}`);
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
respondWithError(res, error);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
authenticate(req) {
|
|
269
|
+
const cookies = parseCookies(req.headers.cookie);
|
|
270
|
+
return this.auth.authenticate(cookies[SESSION_COOKIE]);
|
|
271
|
+
}
|
|
272
|
+
async handleAuth(req, res, action) {
|
|
273
|
+
const method = req.method ?? 'GET';
|
|
274
|
+
if (action === 'login' && method === 'POST') {
|
|
275
|
+
const body = await readJsonBody(req, this.bodyLimit);
|
|
276
|
+
const value = typeof body === 'object' && body !== null
|
|
277
|
+
? body
|
|
278
|
+
: {};
|
|
279
|
+
const ip = clientIp(req, this.deps.getWebUiConfig().trustProxy);
|
|
280
|
+
const result = await this.auth.login(value['username'], value['password'], ip);
|
|
281
|
+
if (!result.ok || !result.session) {
|
|
282
|
+
const headers = {};
|
|
283
|
+
if (result.retryAfterSeconds !== undefined) {
|
|
284
|
+
headers['retry-after'] = String(result.retryAfterSeconds);
|
|
285
|
+
}
|
|
286
|
+
sendError(res, result.status, result.message ?? 'login failed', undefined, headers);
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
res.setHeader('set-cookie', serializeCookie(SESSION_COOKIE, result.session.token, {
|
|
290
|
+
maxAgeSeconds: this.deps.getWebUiConfig().sessionTtlHours * 3600,
|
|
291
|
+
secure: this.isSecure(req),
|
|
292
|
+
}));
|
|
293
|
+
sendData(res, result.status, {
|
|
294
|
+
username: result.session.username,
|
|
295
|
+
expiresAt: result.session.expiresAt,
|
|
296
|
+
});
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
if (action === 'logout' && method === 'POST') {
|
|
300
|
+
const session = this.authenticate(req);
|
|
301
|
+
this.auth.logout(this.tokenOf(req));
|
|
302
|
+
this.deps.logger.info(`webui logout: ${session?.username ?? 'unknown'}`);
|
|
303
|
+
res.setHeader('set-cookie', clearCookie(SESSION_COOKIE));
|
|
304
|
+
sendData(res, 200, { ok: true });
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (action === 'me' && method === 'GET') {
|
|
308
|
+
const session = this.authenticate(req);
|
|
309
|
+
if (session === null) {
|
|
310
|
+
throw new HttpError(401, '未登录或会话已过期');
|
|
311
|
+
}
|
|
312
|
+
sendData(res, 200, {
|
|
313
|
+
username: session.username,
|
|
314
|
+
expiresAt: session.expiresAt,
|
|
315
|
+
});
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
throw new HttpError(404, `not found: ${method} /api/auth/${action ?? ''}`);
|
|
319
|
+
}
|
|
320
|
+
tokenOf(req) {
|
|
321
|
+
const cookies = parseCookies(req.headers.cookie);
|
|
322
|
+
return cookies[SESSION_COOKIE];
|
|
323
|
+
}
|
|
324
|
+
isSecure(req) {
|
|
325
|
+
if (!this.deps.getWebUiConfig().trustProxy)
|
|
326
|
+
return false;
|
|
327
|
+
const proto = req.headers['x-forwarded-proto'];
|
|
328
|
+
return (typeof proto === 'string' && proto.split(',')[0]?.trim() === 'https');
|
|
329
|
+
}
|
|
330
|
+
openSse(req, res, subscribe, openedAt) {
|
|
331
|
+
if (this.sse.size >= this.maxSseClients) {
|
|
332
|
+
throw new HttpError(503, '实时连接数量已达上限');
|
|
333
|
+
}
|
|
334
|
+
res.writeHead(200, {
|
|
335
|
+
'content-type': 'text/event-stream; charset=utf-8',
|
|
336
|
+
'cache-control': 'no-store, no-transform',
|
|
337
|
+
connection: 'keep-alive',
|
|
338
|
+
});
|
|
339
|
+
res.write(':ok\n\n');
|
|
340
|
+
const connection = {
|
|
341
|
+
res,
|
|
342
|
+
close: () => {
|
|
343
|
+
unsubscribe();
|
|
344
|
+
clearInterval(heartbeat);
|
|
345
|
+
this.sse.delete(connection);
|
|
346
|
+
try {
|
|
347
|
+
res.end();
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
// Already closed.
|
|
351
|
+
}
|
|
352
|
+
},
|
|
353
|
+
};
|
|
354
|
+
let closing = false;
|
|
355
|
+
const unsubscribe = subscribe((entry) => {
|
|
356
|
+
if (closing)
|
|
357
|
+
return;
|
|
358
|
+
res.write(`data: ${safeStringify(entry)}\n\n`);
|
|
359
|
+
});
|
|
360
|
+
const heartbeat = setInterval(() => {
|
|
361
|
+
res.write(`:keepalive ${Date.now() - openedAt}\n\n`);
|
|
362
|
+
}, SSE_HEARTBEAT_MS);
|
|
363
|
+
req.on('close', () => {
|
|
364
|
+
if (closing)
|
|
365
|
+
return;
|
|
366
|
+
closing = true;
|
|
367
|
+
unsubscribe();
|
|
368
|
+
clearInterval(heartbeat);
|
|
369
|
+
this.sse.delete(connection);
|
|
370
|
+
});
|
|
371
|
+
this.sse.add(connection);
|
|
372
|
+
}
|
|
373
|
+
async serveStatic(req, res, pathname) {
|
|
374
|
+
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
|
375
|
+
throw new HttpError(405, `method not allowed: ${req.method}`);
|
|
376
|
+
}
|
|
377
|
+
const staticDir = this.deps.paths.staticDir;
|
|
378
|
+
if (staticDir === null) {
|
|
379
|
+
res.setHeader('content-type', 'text/html; charset=utf-8');
|
|
380
|
+
res.setHeader('cache-control', 'no-store');
|
|
381
|
+
res.writeHead(503);
|
|
382
|
+
res.end(this.fallbackBody);
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
const cleaned = pathname.replace(/\/+$/, '') || '/';
|
|
386
|
+
let filePath = cleaned === '/'
|
|
387
|
+
? join(staticDir, 'index.html')
|
|
388
|
+
: resolve(staticDir, `.${cleaned}`);
|
|
389
|
+
if (!filePath.startsWith(staticDir + sep) && filePath !== staticDir) {
|
|
390
|
+
throw new HttpError(403, 'forbidden');
|
|
391
|
+
}
|
|
392
|
+
let fileStat = await this.statOrNull(filePath);
|
|
393
|
+
if (fileStat?.isDirectory()) {
|
|
394
|
+
filePath = join(filePath, 'index.html');
|
|
395
|
+
fileStat = await this.statOrNull(filePath);
|
|
396
|
+
}
|
|
397
|
+
if (fileStat === null) {
|
|
398
|
+
// SPA fallback: only routes without a file extension.
|
|
399
|
+
if (extname(cleaned) === '') {
|
|
400
|
+
filePath = join(staticDir, 'index.html');
|
|
401
|
+
fileStat = await this.statOrNull(filePath);
|
|
402
|
+
}
|
|
403
|
+
if (fileStat === null)
|
|
404
|
+
throw new HttpError(404, 'not found');
|
|
405
|
+
}
|
|
406
|
+
const cacheControl = isImmutableAsset(cleaned)
|
|
407
|
+
? 'public, max-age=31536000, immutable'
|
|
408
|
+
: 'no-cache';
|
|
409
|
+
res.setHeader('content-type', mimeType(filePath));
|
|
410
|
+
res.setHeader('cache-control', cacheControl);
|
|
411
|
+
res.setHeader('content-length', String(fileStat.size));
|
|
412
|
+
res.writeHead(200);
|
|
413
|
+
if (req.method === 'HEAD') {
|
|
414
|
+
res.end();
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
const stream = createReadStream(filePath);
|
|
418
|
+
stream.on('error', () => {
|
|
419
|
+
try {
|
|
420
|
+
res.end();
|
|
421
|
+
}
|
|
422
|
+
catch {
|
|
423
|
+
// Already closed.
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
stream.pipe(res);
|
|
427
|
+
}
|
|
428
|
+
async statOrNull(filePath) {
|
|
429
|
+
try {
|
|
430
|
+
return await withTimeout(stat(filePath), 1_000);
|
|
431
|
+
}
|
|
432
|
+
catch {
|
|
433
|
+
return null;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/core/web/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { BotApi } from '../api.js';
|
|
2
|
+
import type { AppConfig, WebUiConfig } from '../config/schema.js';
|
|
3
|
+
import type { Kernel } from '../kernel.js';
|
|
4
|
+
import type { LogBuffer } from '../logging/log-buffer.js';
|
|
5
|
+
import type { Logger } from '../logging/logger.js';
|
|
6
|
+
import type { AnyPluginDefinition, PluginInstaller } from '../plugin/types.js';
|
|
7
|
+
import type { Database } from '../storage/database.js';
|
|
8
|
+
import type { EventFeed } from './event-feed.js';
|
|
9
|
+
export interface WebUiRuntime {
|
|
10
|
+
generation: number;
|
|
11
|
+
config: AppConfig;
|
|
12
|
+
kernel: Kernel;
|
|
13
|
+
api: BotApi;
|
|
14
|
+
database: Database;
|
|
15
|
+
installer: PluginInstaller;
|
|
16
|
+
plugins: AnyPluginDefinition[];
|
|
17
|
+
}
|
|
18
|
+
export interface WebUiPaths {
|
|
19
|
+
configPath: string;
|
|
20
|
+
dataDir: string;
|
|
21
|
+
pluginDir: string;
|
|
22
|
+
staticDir: string | null;
|
|
23
|
+
}
|
|
24
|
+
export interface WebUiAddress {
|
|
25
|
+
host: string;
|
|
26
|
+
port: number;
|
|
27
|
+
}
|
|
28
|
+
export interface ConfigDocument {
|
|
29
|
+
path: string;
|
|
30
|
+
raw: string;
|
|
31
|
+
hash: string;
|
|
32
|
+
config: AppConfig;
|
|
33
|
+
}
|
|
34
|
+
export interface ConfigValidationIssue {
|
|
35
|
+
path: string;
|
|
36
|
+
message: string;
|
|
37
|
+
}
|
|
38
|
+
export interface ConfigValidationResult {
|
|
39
|
+
ok: boolean;
|
|
40
|
+
issues: ConfigValidationIssue[];
|
|
41
|
+
config?: AppConfig;
|
|
42
|
+
}
|
|
43
|
+
export interface ConfigApplyResult {
|
|
44
|
+
ok: boolean;
|
|
45
|
+
hash?: string;
|
|
46
|
+
issues?: ConfigValidationIssue[];
|
|
47
|
+
error?: string;
|
|
48
|
+
}
|
|
49
|
+
export interface WebUiDeps {
|
|
50
|
+
logger: Logger;
|
|
51
|
+
paths: WebUiPaths;
|
|
52
|
+
version: string;
|
|
53
|
+
logs: LogBuffer;
|
|
54
|
+
events: EventFeed;
|
|
55
|
+
/** Current webui settings; picked up after runtime restarts. */
|
|
56
|
+
getWebUiConfig(): WebUiConfig;
|
|
57
|
+
readConfig(): Promise<ConfigDocument>;
|
|
58
|
+
validateConfig(value: unknown): Promise<ConfigValidationResult>;
|
|
59
|
+
applyConfig(value: unknown, baseHash?: string | undefined): Promise<ConfigApplyResult>;
|
|
60
|
+
restart(): Promise<boolean>;
|
|
61
|
+
requestRestart(): void;
|
|
62
|
+
pause(): void;
|
|
63
|
+
resume(): void;
|
|
64
|
+
getListening(): WebUiAddress | null;
|
|
65
|
+
invalidateSessions(): void;
|
|
66
|
+
runExclusive<T>(task: () => Promise<T>): Promise<T>;
|
|
67
|
+
getRuntime(): WebUiRuntime | null;
|
|
68
|
+
isRestarting(): boolean;
|
|
69
|
+
getStartupError(): string | null;
|
|
70
|
+
getRequiresProcessRestart(): boolean;
|
|
71
|
+
}
|
|
72
|
+
export interface WebUiServerOptions {
|
|
73
|
+
config: WebUiConfig;
|
|
74
|
+
deps: WebUiDeps;
|
|
75
|
+
/** Maximum number of concurrent SSE clients. Defaults to 20. */
|
|
76
|
+
maxSseClients?: number | undefined;
|
|
77
|
+
/** Maximum JSON request body size. Defaults to 1 MiB. */
|
|
78
|
+
bodyLimitBytes?: number | undefined;
|
|
79
|
+
/** Login failures allowed per IP inside the window. Defaults to 5. */
|
|
80
|
+
loginMaxFailures?: number | undefined;
|
|
81
|
+
/** Login failure window. Defaults to 15 minutes. */
|
|
82
|
+
loginWindowMs?: number | undefined;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/web/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/web/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Ki as e,Ri as t,Si as n,Ti as r,c as i,ci as a,d as o,f as s,ga as c,ii as l,ki as u,li as d,p as f,r as p,si as m,ti as h}from"./api-CNzxhTWe.js";var g={class:`result`},_=s(d({__name:`ActionsView`,setup(s){let d=e(`get_login_info`),_=e(`{}`),v=e(``),y=e(!1),b=e(!0),x=async()=>{let e={};if(_.value.trim().length>0&&_.value.trim()!==`{}`)try{e=JSON.parse(_.value)}catch{f.error(`params 必须是合法 JSON`);return}y.value=!0;try{let t=await p(`/api/actions`,{action:d.value,params:e});v.value=JSON.stringify(t.result,void 0,2)}catch(e){o(e)}finally{y.value=!1}};return n(()=>{i().then(e=>{b.value=e.runtime===null}).catch(()=>{b.value=!0})}),(e,n)=>{let i=u(`el-alert`),o=u(`el-input`),s=u(`el-form-item`),f=u(`el-button`),p=u(`el-form`),S=u(`el-divider`),C=u(`el-card`);return r(),l(`div`,null,[a(i,{title:`直接向 OneBot 调用任意 action。此功能等同完全特权接口,请谨慎使用。`,type:`warning`,closable:!1,class:`block`}),a(C,{class:`block`},{default:t(()=>[a(p,{"label-width":`100px`,size:`small`},{default:t(()=>[a(s,{label:`action`},{default:t(()=>[a(o,{modelValue:d.value,"onUpdate:modelValue":n[0]||=e=>d.value=e,placeholder:`如 get_login_info / send_private_msg`,style:{width:`320px`}},null,8,[`modelValue`])]),_:1}),a(s,{label:`params (JSON)`},{default:t(()=>[a(o,{modelValue:_.value,"onUpdate:modelValue":n[1]||=e=>_.value=e,type:`textarea`,rows:5,spellcheck:`false`,placeholder:`{}`},null,8,[`modelValue`])]),_:1}),a(s,null,{default:t(()=>[a(f,{type:`primary`,loading:y.value,disabled:b.value,onClick:x},{default:t(()=>[...n[2]||=[m(` 调用 `,-1)]]),_:1},8,[`loading`,`disabled`])]),_:1})]),_:1}),a(S,null,{default:t(()=>[...n[3]||=[m(`结果`,-1)]]),_:1}),h(`pre`,g,c(v.value),1)]),_:1})])}}}),[[`__scopeId`,`data-v-ceeaf662`]]);export{_ as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.block[data-v-ceeaf662]{margin-bottom:16px}.result[data-v-ceeaf662]{background:var(--app-bg);border:1px solid var(--app-border);color:var(--app-text);white-space:pre-wrap;border-radius:10px;min-height:80px;margin:0;padding:12px;font-family:SF Mono,ui-monospace,Menlo,Consolas,monospace;font-size:12px}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Di as e,Ki as t,Ri as n,Si as r,Ti as i,Xr as a,ci as o,d as s,f as c,ga as l,i as u,ii as d,ki as f,li as p,n as m,ni as h,p as g,r as _,ri as v,si as y,ti as b}from"./api-CNzxhTWe.js";var x={class:`block`},S={class:`issues`},C=c(p({__name:`ConfigView`,setup(c){let p=t(`form`),C=t({url:``,accessToken:``,roles:{superadmin:[],admin:[]},message:{charThreshold:50,lineThreshold:3},webui:{enabled:!1,host:`127.0.0.1`,port:8787,username:``,password:``,sessionTtlHours:12,trustProxy:!1},installer:{enabled:!1,registry:`https://registry.npmjs.org/`,allowedPackages:[],allowScripts:!1,timeoutMs:12e4}}),w=t(``),T=t({path:``,hash:``,accessTokenSet:!1,webuiPasswordSet:!1}),E=t(``),D=t([]),O=t(!1),k=()=>{let e=JSON.parse(JSON.stringify(C.value)),t=e.webui;return w.value===``?delete t.password:t.password=w.value,e.accessToken===``&&delete e.accessToken,e},A=()=>{E.value=JSON.stringify(k(),null,4)},j=()=>{try{let e=JSON.parse(E.value),t=e.webui??{};typeof t.password==`string`&&(w.value=t.password===``?``:`00000000`),typeof e.accessToken==`string`&&e.accessToken===``?e.accessToken=``:typeof e.accessToken==`string`&&(e.accessToken=`00000000`),C.value=e,g.success(`已应用到表单`)}catch(e){g.error(`JSON 格式错误`),console.warn(e)}},M=async e=>{let t=await _(`/api/config/validate`,{config:e});return D.value=t.issues,t.ok},N=async()=>{O.value=!0;try{await M(k())&&g.success(`校验通过`)}catch(e){s(e)}finally{O.value=!1}},P=async()=>{let e;try{e=JSON.parse(E.value)}catch{g.error(`JSON 格式错误`);return}await I(e,w.value)},F=async()=>{let e=k();w.value=e.webui.password,await I(e,w.value),D.value=[]},I=async(e,t)=>{O.value=!0;try{if(!await M(e)&&D.value.length>0){g.error(`校验失败`);return}let t=await u(`/api/config`,{config:e,baseHash:T.value.hash});if(!t.ok){g.error(t.error??`保存失败`);return}g.success(`已保存并重启运行时`),await L()}catch(e){s(e)}finally{O.value=!1}},L=async()=>{try{let e=await m(`/api/config`);C.value=e.config,T.value=e.meta,w.value=(e.meta.webuiPasswordSet&&e.config.webui.password,``),E.value=JSON.stringify(e.config,null,4)}catch(e){s(e)}},R=e=>e.join(`, `);function z(e,t,n,r){let i=n.split(/[,,]/).map(e=>e.trim()).filter(e=>e.length>0);e[t]=r?i.map(r):i}return r(()=>void L()),(t,r)=>{let s=f(`el-divider`),c=f(`el-input`),u=f(`el-form-item`),m=f(`el-switch`),g=f(`el-input-number`),_=f(`el-space`),k=f(`el-button`),M=f(`el-form`),I=f(`el-tab-pane`),L=f(`el-tabs`),B=f(`el-alert`);return i(),d(`div`,null,[o(L,{modelValue:p.value,"onUpdate:modelValue":r[19]||=e=>p.value=e},{default:n(()=>[o(I,{label:`常用设置`,name:`form`},{default:n(()=>[o(M,{"label-width":`140px`,size:`small`,class:`form`},{default:n(()=>[o(s,{"content-position":`left`},{default:n(()=>[...r[20]||=[y(`连接`,-1)]]),_:1}),o(u,{label:`ws url`},{default:n(()=>[o(c,{modelValue:C.value.url,"onUpdate:modelValue":r[0]||=e=>C.value.url=e},null,8,[`modelValue`])]),_:1}),o(u,{label:`accessToken`},{default:n(()=>[o(c,{modelValue:C.value.accessToken,"onUpdate:modelValue":r[1]||=e=>C.value.accessToken=e,placeholder:T.value.accessTokenSet?`留空保持不变`:`未设置`},null,8,[`modelValue`,`placeholder`])]),_:1}),o(s,{"content-position":`left`},{default:n(()=>[...r[21]||=[y(`WebUI`,-1)]]),_:1}),o(u,{label:`enabled`},{default:n(()=>[o(m,{modelValue:C.value.webui.enabled,"onUpdate:modelValue":r[2]||=e=>C.value.webui.enabled=e},null,8,[`modelValue`])]),_:1}),o(u,{label:`host / port`},{default:n(()=>[o(_,null,{default:n(()=>[o(c,{modelValue:C.value.webui.host,"onUpdate:modelValue":r[3]||=e=>C.value.webui.host=e,style:{width:`160px`}},null,8,[`modelValue`]),o(g,{modelValue:C.value.webui.port,"onUpdate:modelValue":r[4]||=e=>C.value.webui.port=e,min:1,max:65535},null,8,[`modelValue`])]),_:1})]),_:1}),o(u,{label:`username`},{default:n(()=>[o(c,{modelValue:C.value.webui.username,"onUpdate:modelValue":r[5]||=e=>C.value.webui.username=e,style:{width:`200px`}},null,8,[`modelValue`])]),_:1}),o(u,{label:`password`},{default:n(()=>[o(c,{modelValue:w.value,"onUpdate:modelValue":r[6]||=e=>w.value=e,"show-password":``,placeholder:T.value.webuiPasswordSet?`留空保持不变`:`未设置`,style:{width:`240px`}},null,8,[`modelValue`,`placeholder`])]),_:1}),o(u,{label:`sessionTtlHours`},{default:n(()=>[o(g,{modelValue:C.value.webui.sessionTtlHours,"onUpdate:modelValue":r[7]||=e=>C.value.webui.sessionTtlHours=e,min:1,max:720},null,8,[`modelValue`])]),_:1}),o(u,{label:`trustProxy`},{default:n(()=>[o(m,{modelValue:C.value.webui.trustProxy,"onUpdate:modelValue":r[8]||=e=>C.value.webui.trustProxy=e},null,8,[`modelValue`])]),_:1}),o(s,{"content-position":`left`},{default:n(()=>[...r[22]||=[y(`消息聚合`,-1)]]),_:1}),o(u,{label:`charThreshold`},{default:n(()=>[o(g,{modelValue:C.value.message.charThreshold,"onUpdate:modelValue":r[9]||=e=>C.value.message.charThreshold=e,min:1},null,8,[`modelValue`])]),_:1}),o(u,{label:`lineThreshold`},{default:n(()=>[o(g,{modelValue:C.value.message.lineThreshold,"onUpdate:modelValue":r[10]||=e=>C.value.message.lineThreshold=e,min:1},null,8,[`modelValue`])]),_:1}),o(s,{"content-position":`left`},{default:n(()=>[...r[23]||=[y(`安装器`,-1)]]),_:1}),o(u,{label:`enabled`},{default:n(()=>[o(m,{modelValue:C.value.installer.enabled,"onUpdate:modelValue":r[11]||=e=>C.value.installer.enabled=e},null,8,[`modelValue`])]),_:1}),o(u,{label:`registry`},{default:n(()=>[o(c,{modelValue:C.value.installer.registry,"onUpdate:modelValue":r[12]||=e=>C.value.installer.registry=e},null,8,[`modelValue`])]),_:1}),o(u,{label:`allowedPackages`},{default:n(()=>[o(c,{"model-value":R(C.value.installer.allowedPackages),"onUpdate:modelValue":r[13]||=e=>z(C.value.installer,`allowedPackages`,e)},null,8,[`model-value`])]),_:1}),o(u,{label:`allowScripts`},{default:n(()=>[o(m,{modelValue:C.value.installer.allowScripts,"onUpdate:modelValue":r[14]||=e=>C.value.installer.allowScripts=e},null,8,[`modelValue`])]),_:1}),o(u,{label:`timeoutMs`},{default:n(()=>[o(g,{modelValue:C.value.installer.timeoutMs,"onUpdate:modelValue":r[15]||=e=>C.value.installer.timeoutMs=e,min:1e3,max:6e5},null,8,[`modelValue`])]),_:1}),o(s,{"content-position":`left`},{default:n(()=>[...r[24]||=[y(`角色`,-1)]]),_:1}),o(u,{label:`superadmin`},{default:n(()=>[o(c,{"model-value":R(C.value.roles.superadmin),placeholder:`逗号分隔的 QQ 号`,"onUpdate:modelValue":r[16]||=e=>z(C.value.roles,`superadmin`,e,Number)},null,8,[`model-value`])]),_:1}),o(u,{label:`admin`},{default:n(()=>[o(c,{"model-value":R(C.value.roles.admin),placeholder:`逗号分隔的 QQ 号`,"onUpdate:modelValue":r[17]||=e=>z(C.value.roles,`admin`,e,Number)},null,8,[`model-value`])]),_:1}),o(u,null,{default:n(()=>[o(_,null,{default:n(()=>[o(k,{type:`primary`,loading:O.value,onClick:F},{default:n(()=>[...r[25]||=[y(` 校验并保存 `,-1)]]),_:1},8,[`loading`]),o(k,{onClick:N},{default:n(()=>[...r[26]||=[y(` 仅校验 `,-1)]]),_:1})]),_:1})]),_:1})]),_:1})]),_:1}),o(I,{label:`JSON 编辑器`,name:`json`},{default:n(()=>[o(c,{modelValue:E.value,"onUpdate:modelValue":r[18]||=e=>E.value=e,type:`textarea`,rows:24,spellcheck:`false`,class:`json-editor`},null,8,[`modelValue`]),b(`div`,x,[o(_,null,{default:n(()=>[o(k,{onClick:A},{default:n(()=>[...r[27]||=[y(`从表单生成`,-1)]]),_:1}),o(k,{onClick:j},{default:n(()=>[...r[28]||=[y(`应用到表单`,-1)]]),_:1}),o(k,{type:`primary`,loading:O.value,onClick:P},{default:n(()=>[...r[29]||=[y(` 校验并保存 `,-1)]]),_:1},8,[`loading`])]),_:1})])]),_:1})]),_:1},8,[`modelValue`]),D.value.length>0?(i(),h(B,{key:0,type:`error`,closable:!1,class:`block`},{default:n(()=>[b(`ul`,S,[(i(!0),d(a,null,e(D.value,(e,t)=>(i(),d(`li`,{key:t},l(e.path?e.path+`: `:``)+l(e.message),1))),128))])]),_:1})):v(``,!0)])}}}),[[`__scopeId`,`data-v-3e321bed`]]);export{C as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.form[data-v-3e321bed]{max-width:640px}.block[data-v-3e321bed]{margin-top:12px}.json-editor[data-v-3e321bed]{font-family:monospace}.issues[data-v-3e321bed]{margin:0;padding-left:18px;font-size:12px}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.block[data-v-5b803405]{margin-bottom:16px}.stat[data-v-5b803405]{align-items:flex-start;gap:14px;display:flex}.chip[data-v-5b803405]{border-radius:11px;flex:none;justify-content:center;align-items:center;width:40px;height:40px;display:flex}.chip.sky[data-v-5b803405]{color:color-mix(in oklab, var(--app-accent) 85%, black);background:color-mix(in oklab, var(--app-accent) 12%, transparent)}.chip.emerald[data-v-5b803405]{color:var(--app-ok);background:color-mix(in oklab, var(--app-ok) 12%, transparent)}.chip.violet[data-v-5b803405]{color:var(--app-violet);background:color-mix(in oklab, var(--app-violet) 12%, transparent)}.chip.amber[data-v-5b803405]{color:var(--app-warn);background:color-mix(in oklab, var(--app-warn) 12%, transparent)}.label[data-v-5b803405]{color:var(--app-muted);margin:0;font-size:12.5px}.value[data-v-5b803405]{color:var(--app-text);margin:6px 0 0;font-size:21px;font-weight:700;line-height:1.25}.value.small[data-v-5b803405]{font-size:16px}.unit[data-v-5b803405]{color:var(--app-muted);font-size:12px;font-weight:500}.sub[data-v-5b803405]{color:var(--app-muted);word-break:break-all;margin:4px 0 0;font-size:11.5px}.warn-text[data-v-5b803405]{color:var(--app-warn)}.error-text[data-v-5b803405]{white-space:pre-wrap;margin:8px 0 0;font-size:12px}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Ci as e,I as t,Ki as n,M as r,Q as i,Ri as a,Si as o,Ti as s,a as c,bt as l,c as u,ci as d,d as f,ea as p,ei as m,f as h,ga as g,ii as _,ki as v,l as y,li as b,ni as x,r as S,ri as C,s as w,si as T,ti as E,u as D}from"./api-CNzxhTWe.js";var O={class:`error-text`},k={class:`stat`},ee={class:`chip sky`},te={class:`value small`},A={class:`sub`},j={class:`stat`},M={class:`chip emerald`},N={class:`value`},P={class:`sub`},F={class:`stat`},I={class:`chip violet`},L={class:`value`},R={class:`unit`},z={class:`sub`},B={class:`stat`},V={class:`chip amber`},H={class:`value`},U={class:`unit`},W={class:`sub`},G={key:0,class:`sub warn-text`},K=h(b({__name:`DashboardView`,setup(h){let b=n(null),K=n([]),q=n([]),J=n(!1),Y=m(()=>b.value?.runtime??null),X=m(()=>Y.value?D(Y.value.uptimeMs):`-`),Z=async()=>{try{b.value=await u()}catch(e){f(e)}},ne=async()=>{J.value=!0;try{await S(`/api/runtime/restart`),await Z()}catch(e){f(e)}finally{J.value=!1}},re=async()=>{try{await S(`/api/runtime/pause`),await Z()}catch(e){f(e)}},ie=async()=>{try{await S(`/api/runtime/resume`),await Z()}catch(e){f(e)}},Q=null,$=null;return o(async()=>{await Z(),K.value=await w().catch(()=>[]),Q=c(`/api/events/stream?limit=20`,e=>{q.value.unshift(e),q.value.length>30&&q.value.pop()});let e=setInterval(()=>void Z(),1e4);$=()=>clearInterval(e)}),e(()=>{Q?.(),$?.()}),(e,n)=>{let o=v(`el-alert`),c=v(`el-icon`),u=v(`el-card`),f=v(`el-col`),m=v(`el-row`),h=v(`el-button`),S=v(`el-space`),w=v(`el-table-column`),D=v(`el-table`);return s(),_(`div`,null,[b.value?.startupError?(s(),x(o,{key:0,title:`运行时启动失败`,type:`error`,closable:!1,class:`block`},{default:a(()=>[E(`pre`,O,g(b.value.startupError),1)]),_:1})):b.value?.restarting?(s(),x(o,{key:1,title:`运行时正在重启…`,type:`warning`,closable:!1,class:`block`})):C(``,!0),d(m,{gutter:16,class:`block`},{default:a(()=>[d(f,{span:6},{default:a(()=>[d(u,{class:`stat-card`},{default:a(()=>[E(`div`,k,[E(`div`,ee,[d(c,{size:18},{default:a(()=>[d(p(i))]),_:1})]),E(`div`,null,[n[0]||=E(`p`,{class:`label`},`连接状态`,-1),E(`p`,te,g(Y.value?.connected?`已连接`:`未连接`),1),E(`p`,A,g(Y.value?.login?`${Y.value.login.nickname} · ${Y.value.login.userId}`:`—`),1)])])]),_:1})]),_:1}),d(f,{span:6},{default:a(()=>[d(u,{class:`stat-card`},{default:a(()=>[E(`div`,j,[E(`div`,M,[d(c,{size:18},{default:a(()=>[d(p(l))]),_:1})]),E(`div`,null,[n[1]||=E(`p`,{class:`label`},`运行时长`,-1),E(`p`,N,g(X.value),1),E(`p`,P,` state: `+g(Y.value?.state??`—`)+` · gen `+g(Y.value?.generation??`—`),1)])])]),_:1})]),_:1}),d(f,{span:6},{default:a(()=>[d(u,{class:`stat-card`},{default:a(()=>[E(`div`,F,[E(`div`,I,[d(c,{size:18},{default:a(()=>[d(p(r))]),_:1})]),E(`div`,null,[n[2]||=E(`p`,{class:`label`},`插件`,-1),E(`p`,L,[T(g(Y.value?.counts.loadedPlugins??`—`),1),E(`span`,R,` / `+g(Y.value?.counts.plugins??`—`)+` 已加载`,1)]),E(`p`,z,` 启用 `+g(Y.value?.counts.enabledPlugins??`—`),1)])])]),_:1})]),_:1}),d(f,{span:6},{default:a(()=>[d(u,{class:`stat-card`},{default:a(()=>[E(`div`,B,[E(`div`,V,[d(c,{size:18},{default:a(()=>[d(p(t))]),_:1})]),E(`div`,null,[n[3]||=E(`p`,{class:`label`},`会话`,-1),E(`p`,H,[T(g(Y.value?.counts.sessions??`—`),1),E(`span`,U,` · `+g(Y.value?.counts.kvPlugins??`—`)+` KV 插件`,1)]),n[4]||=E(`p`,{class:`sub`},`session 记录数`,-1)])])]),_:1})]),_:1})]),_:1}),d(u,{class:`block`},{header:a(()=>[...n[5]||=[T(`运行时控制`,-1)]]),default:a(()=>[d(S,null,{default:a(()=>[d(h,{type:`danger`,loading:J.value,onClick:ne},{default:a(()=>[...n[6]||=[T(` 重启运行时 `,-1)]]),_:1},8,[`loading`]),d(h,{onClick:re},{default:a(()=>[...n[7]||=[T(`暂停`,-1)]]),_:1}),d(h,{onClick:ie},{default:a(()=>[...n[8]||=[T(`恢复`,-1)]]),_:1})]),_:1}),E(`p`,W,` version: `+g(b.value?.version??`-`)+` · paths: `+g(b.value?.paths.config),1),b.value?.webui.requiresProcessRestart?(s(),_(`p`,G,` webui 绑定配置已修改,需要重启进程生效。 `)):C(``,!0)]),_:1}),d(u,{class:`block`},{header:a(()=>[...n[9]||=[T(`命令列表`,-1)]]),default:a(()=>[d(D,{data:K.value,size:`small`,"max-height":`320`},{default:a(()=>[d(w,{prop:`id`,label:`命令`,width:`220`}),d(w,{prop:`pluginId`,label:`插件`,width:`180`}),d(w,{prop:`description`,label:`说明`})]),_:1},8,[`data`])]),_:1}),d(u,{class:`block`},{header:a(()=>[...n[10]||=[T(`最近事件`,-1)]]),default:a(()=>[d(D,{data:q.value,size:`small`,"max-height":`320`},{default:a(()=>[d(w,{label:`时间`,width:`170`},{default:a(({row:e})=>[T(g(p(y)(e.time)),1)]),_:1}),d(w,{prop:`type`,label:`类型`,width:`100`}),d(w,{prop:`summary`,label:`摘要`})]),_:1},8,[`data`])]),_:1})])}}}),[[`__scopeId`,`data-v-5b803405`]]);export{K as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Ci as e,Ii as t,Ki as n,Ri as r,Si as i,Ti as a,a as o,ci as s,d as c,ea as l,f as u,ga as d,ii as f,ki as p,l as m,li as h,n as g,si as _,ti as v}from"./api-CNzxhTWe.js";var y={class:`json`},b=u(h({__name:`EventsView`,setup(u){let h=n(``),b=n(`on`),x=n([]),S=n(!1),C=n(``),w=async()=>{try{let e=new URLSearchParams({limit:`300`});h.value&&e.set(`type`,h.value),x.value=await g(`/api/events?${e.toString()}`)}catch(e){c(e)}},T=null,E=()=>{T?.(),T=null,b.value===`on`&&(T=o(`/api/events/stream`,e=>{let t=e;h.value&&t.type!==h.value||(x.value.unshift(t),x.value.length>500&&(x.value.length=500))}))};t(b,E),t(h,async()=>{await w(),E()});let D=e=>{C.value=JSON.stringify(e.event,void 0,2),S.value=!0};return i(async()=>{await w(),E()}),e(()=>{T?.()}),(e,t)=>{let n=p(`el-option`),i=p(`el-select`),o=p(`el-button`),c=p(`el-space`),u=p(`el-card`),g=p(`el-table-column`),T=p(`el-table`),E=p(`el-drawer`);return a(),f(`div`,null,[s(u,{class:`block`},{default:r(()=>[s(c,null,{default:r(()=>[s(i,{modelValue:h.value,"onUpdate:modelValue":t[0]||=e=>h.value=e,placeholder:`全部类型`,style:{width:`140px`},clearable:``},{default:r(()=>[s(n,{label:`message`,value:`message`}),s(n,{label:`notice`,value:`notice`}),s(n,{label:`request`,value:`request`}),s(n,{label:`meta`,value:`meta`}),s(n,{label:`other`,value:`other`})]),_:1},8,[`modelValue`]),s(i,{modelValue:b.value,"onUpdate:modelValue":t[1]||=e=>b.value=e,style:{width:`90px`}},{default:r(()=>[s(n,{label:`实时`,value:`on`}),s(n,{label:`暂停`,value:`off`})]),_:1},8,[`modelValue`]),s(o,{type:`primary`,onClick:w},{default:r(()=>[...t[3]||=[_(`刷新`,-1)]]),_:1})]),_:1})]),_:1}),s(u,null,{default:r(()=>[s(T,{data:x.value,size:`small`,"max-height":`640`},{default:r(()=>[s(g,{label:`时间`,width:`170`},{default:r(({row:e})=>[_(d(l(m)(e.time)),1)]),_:1}),s(g,{prop:`type`,label:`类型`,width:`100`}),s(g,{prop:`summary`,label:`摘要`,"show-overflow-tooltip":``}),s(g,{label:`详情`,width:`90`},{default:r(({row:e})=>[s(o,{size:`small`,onClick:t=>D(e)},{default:r(()=>[...t[4]||=[_(` 查看 `,-1)]]),_:1},8,[`onClick`])]),_:1})]),_:1},8,[`data`])]),_:1}),s(E,{modelValue:S.value,"onUpdate:modelValue":t[2]||=e=>S.value=e,title:`事件详情`,size:`50%`},{default:r(()=>[v(`pre`,y,d(C.value),1)]),_:1},8,[`modelValue`])])}}}),[[`__scopeId`,`data-v-ffa9bb28`]]);export{b as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.block[data-v-ffa9bb28]{margin-bottom:16px}.json[data-v-ffa9bb28]{white-space:pre-wrap;font-size:12px}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Ai as e,Di as t,Ki as n,Ri as r,Si as i,Ti as a,Xr as o,ci as s,d as c,ea as l,f as u,ga as d,i as f,ii as p,ki as m,l as h,li as g,n as _,ni as v,p as y,qr as b,ri as x,si as S,t as C,zi as w}from"./api-CNzxhTWe.js";var T=50,E=u(g({__name:`KvView`,setup(u){let g=n([]),E=n(``),D=n(``),O=n([]),k=n(0),A=n(1),j=n(!1),M=n(!1),N=n(``),P=n(``),F=n(`create`),I=async()=>{if(E.value){j.value=!0;try{let e=(A.value-1)*T,t=new URLSearchParams({pluginId:E.value,limit:String(T),offset:String(e)});D.value&&t.set(`prefix`,D.value);let n=await _(`/api/kv?${t.toString()}`);O.value=n.items,k.value=n.total}catch(e){c(e)}finally{j.value=!1}}},L=e=>{A.value=e,I()},R=()=>{F.value=`create`,N.value=``,P.value=`null`,M.value=!0},z=e=>{F.value=`update`,N.value=e.key,P.value=JSON.stringify(e.value,void 0,2),M.value=!0},B=async()=>{let e;try{e=JSON.parse(P.value)}catch{y.error(`不是合法的 JSON`);return}try{await f(`/api/kv`,{pluginId:E.value,key:N.value,value:e}),M.value=!1,await I()}catch(e){c(e)}},V=async e=>{try{await C(`/api/kv?pluginId=${encodeURIComponent(E.value)}&key=${encodeURIComponent(e.key)}`),await I()}catch(e){c(e)}},H=e=>typeof e==`string`?e.length>120?e.slice(0,120)+`…`:e:JSON.stringify(e)?.slice(0,120)??``;return i(async()=>{try{g.value=await _(`/api/kv/plugins`),g.value.length>0&&(E.value=g.value[0]?.pluginId??``,await I())}catch(e){c(e)}}),(n,i)=>{let c=m(`el-option`),u=m(`el-select`),f=m(`el-card`),_=m(`el-input`),y=m(`el-button`),C=m(`el-space`),U=m(`el-table-column`),W=m(`el-table`),G=m(`el-pagination`),K=m(`el-form-item`),q=m(`el-form`),J=m(`el-dialog`),Y=e(`loading`);return a(),p(`div`,null,[s(f,{class:`block`},{default:r(()=>[s(u,{modelValue:E.value,"onUpdate:modelValue":i[0]||=e=>E.value=e,placeholder:`选择插件`,style:{width:`240px`},onChange:I},{default:r(()=>[(a(!0),p(o,null,t(g.value,e=>(a(),v(c,{key:e.pluginId,label:`${e.pluginId} (${e.count})`,value:e.pluginId},null,8,[`label`,`value`]))),128))]),_:1},8,[`modelValue`])]),_:1}),E.value?(a(),v(f,{key:0},{default:r(()=>[s(C,{class:`block`},{default:r(()=>[s(_,{modelValue:D.value,"onUpdate:modelValue":i[1]||=e=>D.value=e,placeholder:`key 前缀过滤`,style:{width:`200px`},onKeyup:b(I,[`enter`])},null,8,[`modelValue`]),s(y,{onClick:I},{default:r(()=>[...i[6]||=[S(`过滤`,-1)]]),_:1}),s(y,{type:`primary`,onClick:R},{default:r(()=>[...i[7]||=[S(`新增 KV`,-1)]]),_:1})]),_:1}),w((a(),v(W,{data:O.value,size:`small`},{default:r(()=>[s(U,{prop:`key`,label:`Key`,"show-overflow-tooltip":``}),s(U,{label:`Value`,"show-overflow-tooltip":``},{default:r(({row:e})=>[S(d(H(e.value)),1)]),_:1}),s(U,{label:`更新时间`,width:`180`},{default:r(({row:e})=>[S(d(l(h)(e.updatedAt)),1)]),_:1}),s(U,{label:`操作`,width:`150`},{default:r(({row:e})=>[s(y,{size:`small`,onClick:t=>z(e)},{default:r(()=>[...i[8]||=[S(`编辑`,-1)]]),_:1},8,[`onClick`]),s(y,{size:`small`,type:`danger`,onClick:t=>V(e)},{default:r(()=>[...i[9]||=[S(`删除`,-1)]]),_:1},8,[`onClick`])]),_:1})]),_:1},8,[`data`])),[[Y,j.value]]),s(G,{class:`pager`,layout:`total, prev, pager, next`,total:k.value,"page-size":T,"current-page":A.value,onCurrentChange:L},null,8,[`total`,`current-page`])]),_:1})):x(``,!0),s(J,{modelValue:M.value,"onUpdate:modelValue":i[5]||=e=>M.value=e,title:`KV 编辑`,width:`560px`},{footer:r(()=>[s(y,{onClick:i[4]||=e=>M.value=!1},{default:r(()=>[...i[10]||=[S(`取消`,-1)]]),_:1}),s(y,{type:`primary`,onClick:B},{default:r(()=>[...i[11]||=[S(`保存`,-1)]]),_:1})]),default:r(()=>[s(q,{"label-width":`80px`},{default:r(()=>[s(K,{label:`key`},{default:r(()=>[s(_,{modelValue:N.value,"onUpdate:modelValue":i[2]||=e=>N.value=e,disabled:F.value===`update`},null,8,[`modelValue`,`disabled`])]),_:1}),s(K,{label:`value (JSON)`},{default:r(()=>[s(_,{modelValue:P.value,"onUpdate:modelValue":i[3]||=e=>P.value=e,type:`textarea`,rows:6,spellcheck:`false`},null,8,[`modelValue`])]),_:1})]),_:1})]),_:1},8,[`modelValue`])])}}}),[[`__scopeId`,`data-v-6e1ecb0b`]]);export{E as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.block[data-v-6e1ecb0b]{margin-bottom:12px}.pager[data-v-6e1ecb0b]{margin-top:12px}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.login-page[data-v-57590040]{background:var(--app-bg);justify-content:center;align-items:center;height:100%;min-height:100%;display:flex;position:relative;overflow:hidden}.login-card[data-v-57590040]{z-index:1;background:var(--app-glass);-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px);width:372px;box-shadow:var(--card-shadow), 0 32px 80px -40px oklch(0% 0 0/.35);position:relative}.brand[data-v-57590040]{text-align:center;margin-bottom:26px}.logo[data-v-57590040]{width:52px;height:52px;color:var(--app-accent-fg);background:linear-gradient(135deg,oklch(68.5% .155 230),oklch(56% .15 250));border-radius:15px;justify-content:center;align-items:center;margin-bottom:16px;font-size:22px;font-weight:700;display:inline-flex;box-shadow:inset 0 1px oklch(100% 0 0/.22),0 12px 28px oklch(68.5% .155 230/.4)}.brand h2[data-v-57590040]{color:var(--app-text);letter-spacing:.02em;margin:0;font-size:18px}.brand p[data-v-57590040]{color:var(--app-muted);margin:6px 0 0;font-size:13px}.submit[data-v-57590040]{letter-spacing:.35em;width:100%;margin-top:6px;font-weight:600}
|