@zhongqian97-code/ecode 0.5.17 → 0.5.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +142 -7
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5234,15 +5234,145 @@ function generateAccessToken() {
|
|
|
5234
5234
|
}
|
|
5235
5235
|
function createAuthHook(token) {
|
|
5236
5236
|
return function authHook(request, reply, done) {
|
|
5237
|
-
const
|
|
5238
|
-
|
|
5239
|
-
|
|
5237
|
+
const headerToken = request.headers["x-ecode-token"];
|
|
5238
|
+
const queryToken = request.query?.["token"];
|
|
5239
|
+
if (headerToken === token || queryToken === token) {
|
|
5240
|
+
done();
|
|
5240
5241
|
return;
|
|
5241
5242
|
}
|
|
5242
|
-
|
|
5243
|
+
reply.code(401).send({ success: false, error: "Unauthorized" });
|
|
5243
5244
|
};
|
|
5244
5245
|
}
|
|
5245
5246
|
|
|
5247
|
+
// src/web/admin-html.ts
|
|
5248
|
+
function generateAdminHtml(version2) {
|
|
5249
|
+
return `<!DOCTYPE html>
|
|
5250
|
+
<html lang="zh">
|
|
5251
|
+
<head>
|
|
5252
|
+
<meta charset="UTF-8">
|
|
5253
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
5254
|
+
<title>ecode web admin</title>
|
|
5255
|
+
<style>
|
|
5256
|
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
5257
|
+
body {
|
|
5258
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace;
|
|
5259
|
+
background: #0d1117; color: #c9d1d9; min-height: 100vh; padding: 24px;
|
|
5260
|
+
}
|
|
5261
|
+
header {
|
|
5262
|
+
display: flex; align-items: center; gap: 12px;
|
|
5263
|
+
padding-bottom: 16px; border-bottom: 1px solid #21262d; margin-bottom: 24px;
|
|
5264
|
+
}
|
|
5265
|
+
header h1 { font-size: 18px; font-weight: 600; color: #e6edf3; }
|
|
5266
|
+
header .version { font-size: 12px; color: #8b949e; background: #21262d;
|
|
5267
|
+
padding: 2px 8px; border-radius: 20px; }
|
|
5268
|
+
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 16px; }
|
|
5269
|
+
.card {
|
|
5270
|
+
background: #161b22; border: 1px solid #21262d; border-radius: 8px; padding: 16px;
|
|
5271
|
+
}
|
|
5272
|
+
.card h2 { font-size: 13px; font-weight: 600; color: #8b949e;
|
|
5273
|
+
text-transform: uppercase; letter-spacing: .05em; margin-bottom: 12px; }
|
|
5274
|
+
.stat { display: flex; justify-content: space-between; align-items: center;
|
|
5275
|
+
padding: 6px 0; border-bottom: 1px solid #21262d; font-size: 13px; }
|
|
5276
|
+
.stat:last-child { border-bottom: none; }
|
|
5277
|
+
.stat .label { color: #8b949e; }
|
|
5278
|
+
.stat .value { color: #e6edf3; font-weight: 500; }
|
|
5279
|
+
.badge { display: inline-block; padding: 2px 8px; border-radius: 20px;
|
|
5280
|
+
font-size: 11px; font-weight: 600; }
|
|
5281
|
+
.badge.ok { background: #1a4731; color: #3fb950; }
|
|
5282
|
+
.badge.err { background: #4d1f24; color: #f85149; }
|
|
5283
|
+
.session-item {
|
|
5284
|
+
padding: 8px 0; border-bottom: 1px solid #21262d; font-size: 13px;
|
|
5285
|
+
}
|
|
5286
|
+
.session-item:last-child { border-bottom: none; }
|
|
5287
|
+
.session-id { color: #79c0ff; font-family: monospace; font-size: 12px; }
|
|
5288
|
+
.session-title { color: #e6edf3; margin-top: 2px; }
|
|
5289
|
+
.empty { color: #8b949e; font-size: 13px; font-style: italic; }
|
|
5290
|
+
.error { color: #f85149; font-size: 13px; }
|
|
5291
|
+
.loading { color: #8b949e; font-size: 13px; font-style: italic; }
|
|
5292
|
+
.api-row { font-size: 12px; font-family: monospace; padding: 4px 0;
|
|
5293
|
+
border-bottom: 1px solid #21262d; display: flex; gap: 8px; }
|
|
5294
|
+
.api-row:last-child { border-bottom: none; }
|
|
5295
|
+
.method { color: #79c0ff; min-width: 50px; }
|
|
5296
|
+
.path { color: #e6edf3; }
|
|
5297
|
+
</style>
|
|
5298
|
+
</head>
|
|
5299
|
+
<body>
|
|
5300
|
+
<header>
|
|
5301
|
+
<h1>\u26A1 ecode web admin</h1>
|
|
5302
|
+
<span class="version">v${version2}</span>
|
|
5303
|
+
</header>
|
|
5304
|
+
|
|
5305
|
+
<div class="grid">
|
|
5306
|
+
<div class="card">
|
|
5307
|
+
<h2>\u670D\u52A1\u72B6\u6001</h2>
|
|
5308
|
+
<div id="status-content"><span class="loading">\u52A0\u8F7D\u4E2D\u2026</span></div>
|
|
5309
|
+
</div>
|
|
5310
|
+
|
|
5311
|
+
<div class="card">
|
|
5312
|
+
<h2>\u8FD0\u884C\u4E2D\u7684\u4F1A\u8BDD</h2>
|
|
5313
|
+
<div id="sessions-content"><span class="loading">\u52A0\u8F7D\u4E2D\u2026</span></div>
|
|
5314
|
+
</div>
|
|
5315
|
+
|
|
5316
|
+
<div class="card">
|
|
5317
|
+
<h2>API \u7AEF\u70B9</h2>
|
|
5318
|
+
<div class="api-row"><span class="method">GET</span><span class="path">/api/status</span></div>
|
|
5319
|
+
<div class="api-row"><span class="method">GET</span><span class="path">/api/sessions</span></div>
|
|
5320
|
+
<div class="api-row"><span class="method">GET</span><span class="path">/api/config</span></div>
|
|
5321
|
+
<div class="api-row"><span class="method">GET</span><span class="path">/api/automation/jobs</span></div>
|
|
5322
|
+
<div class="api-row"><span class="method">POST</span><span class="path">/api/chat/sessions</span></div>
|
|
5323
|
+
<div class="api-row"><span class="method">WS</span><span class="path">/api/ws/sessions/:id</span></div>
|
|
5324
|
+
</div>
|
|
5325
|
+
</div>
|
|
5326
|
+
|
|
5327
|
+
<script>
|
|
5328
|
+
const token = new URLSearchParams(location.search).get('token') || '';
|
|
5329
|
+
|
|
5330
|
+
async function apiFetch(path) {
|
|
5331
|
+
const sep = path.includes('?') ? '&' : '?';
|
|
5332
|
+
const r = await fetch(path + sep + 'token=' + encodeURIComponent(token));
|
|
5333
|
+
if (!r.ok) throw new Error(r.status + ' ' + r.statusText);
|
|
5334
|
+
return r.json();
|
|
5335
|
+
}
|
|
5336
|
+
|
|
5337
|
+
function setHtml(id, html) {
|
|
5338
|
+
document.getElementById(id).innerHTML = html;
|
|
5339
|
+
}
|
|
5340
|
+
|
|
5341
|
+
// \u72B6\u6001\u5361
|
|
5342
|
+
apiFetch('/api/status').then(d => {
|
|
5343
|
+
const rows = [
|
|
5344
|
+
['\u72B6\u6001', '<span class="badge ok">\u8FD0\u884C\u4E2D</span>'],
|
|
5345
|
+
['\u7248\u672C', d.version ?? '-'],
|
|
5346
|
+
['\u6D3B\u8DC3\u4F1A\u8BDD', d.activeSessions ?? 0],
|
|
5347
|
+
];
|
|
5348
|
+
setHtml('status-content',
|
|
5349
|
+
rows.map(([l,v]) =>
|
|
5350
|
+
'<div class="stat"><span class="label">' + l + '</span><span class="value">' + v + '</span></div>'
|
|
5351
|
+
).join('')
|
|
5352
|
+
);
|
|
5353
|
+
}).catch(e => setHtml('status-content', '<span class="error">' + e.message + '</span>'));
|
|
5354
|
+
|
|
5355
|
+
// \u4F1A\u8BDD\u5217\u8868
|
|
5356
|
+
apiFetch('/api/sessions').then(d => {
|
|
5357
|
+
const sessions = d.sessions ?? d.data ?? d ?? [];
|
|
5358
|
+
if (!sessions.length) {
|
|
5359
|
+
setHtml('sessions-content', '<span class="empty">\u6682\u65E0\u4F1A\u8BDD</span>');
|
|
5360
|
+
return;
|
|
5361
|
+
}
|
|
5362
|
+
setHtml('sessions-content',
|
|
5363
|
+
sessions.slice(0, 10).map(s =>
|
|
5364
|
+
'<div class="session-item">' +
|
|
5365
|
+
'<div class="session-id">' + s.id + '</div>' +
|
|
5366
|
+
'<div class="session-title">' + (s.title || '(\u65E0\u6807\u9898)') + '</div>' +
|
|
5367
|
+
'</div>'
|
|
5368
|
+
).join('')
|
|
5369
|
+
);
|
|
5370
|
+
}).catch(e => setHtml('sessions-content', '<span class="error">' + e.message + '</span>'));
|
|
5371
|
+
</script>
|
|
5372
|
+
</body>
|
|
5373
|
+
</html>`;
|
|
5374
|
+
}
|
|
5375
|
+
|
|
5246
5376
|
// src/web/routes/status.ts
|
|
5247
5377
|
async function statusRoutes(app, opts) {
|
|
5248
5378
|
app.get(
|
|
@@ -5550,6 +5680,10 @@ async function buildServer(opts) {
|
|
|
5550
5680
|
authHook(request, reply, done);
|
|
5551
5681
|
});
|
|
5552
5682
|
app.get("/health", async () => ({ ok: true }));
|
|
5683
|
+
const adminHtml = generateAdminHtml(opts.version);
|
|
5684
|
+
app.get("/", async (_req, reply) => {
|
|
5685
|
+
return reply.type("text/html").send(adminHtml);
|
|
5686
|
+
});
|
|
5553
5687
|
await app.register(statusRoutes, {
|
|
5554
5688
|
config: opts.config,
|
|
5555
5689
|
manager: opts.manager,
|
|
@@ -6101,11 +6235,12 @@ if (rawArgs[0] === "web") {
|
|
|
6101
6235
|
version: VERSION
|
|
6102
6236
|
});
|
|
6103
6237
|
await server.listen({ port: webPort, host: webHost });
|
|
6104
|
-
const
|
|
6238
|
+
const browserHost = webHost === "0.0.0.0" ? "localhost" : webHost;
|
|
6239
|
+
const accessUrl = `http://${browserHost}:${webPort}?token=${token}`;
|
|
6105
6240
|
console.log(`
|
|
6106
6241
|
ecode web admin started`);
|
|
6107
|
-
console.log(`
|
|
6108
|
-
console.log(`
|
|
6242
|
+
console.log(` Bind: ${webHost}:${webPort}`);
|
|
6243
|
+
console.log(` URL: ${accessUrl}`);
|
|
6109
6244
|
console.log(`
|
|
6110
6245
|
Press Ctrl+C to stop.
|
|
6111
6246
|
`);
|