mioku-service-webui 4.3.0 → 4.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/config-page-loader.ts +24 -11
- package/index.ts +2 -0
- package/package.json +1 -1
- package/routes/db.ts +100 -1
- package/routes/index.ts +1 -1
package/config-page-loader.ts
CHANGED
|
@@ -27,25 +27,40 @@ export interface ConfigPageManifest {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export function loadPluginConfigPage(pluginName: string): ConfigPageManifest | null {
|
|
30
|
-
// 支持两种路径:本地 plugins 目录和 npm 包
|
|
31
30
|
const possiblePaths = [
|
|
32
31
|
path.join(process.cwd(), "plugins", pluginName),
|
|
33
32
|
path.join(process.cwd(), "node_modules", `mioku-plugin-${pluginName}`),
|
|
34
33
|
];
|
|
35
34
|
|
|
35
|
+
return loadConfigPage(pluginName, possiblePaths);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function loadServiceConfigPage(serviceName: string): ConfigPageManifest | null {
|
|
39
|
+
const possiblePaths = [
|
|
40
|
+
path.join(process.cwd(), "services", serviceName),
|
|
41
|
+
path.join(process.cwd(), "node_modules", `mioku-service-${serviceName}`),
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
return loadConfigPage(serviceName, possiblePaths);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function loadConfigPage(
|
|
48
|
+
packageName: string,
|
|
49
|
+
possiblePaths: string[],
|
|
50
|
+
): ConfigPageManifest | null {
|
|
36
51
|
let configMdPath: string | null = null;
|
|
37
|
-
let
|
|
52
|
+
let packageDir: string | null = null;
|
|
38
53
|
|
|
39
54
|
for (const dir of possiblePaths) {
|
|
40
55
|
const candidate = path.join(dir, "config.md");
|
|
41
56
|
if (fs.existsSync(candidate)) {
|
|
42
57
|
configMdPath = candidate;
|
|
43
|
-
|
|
58
|
+
packageDir = dir;
|
|
44
59
|
break;
|
|
45
60
|
}
|
|
46
61
|
}
|
|
47
62
|
|
|
48
|
-
if (!configMdPath || !
|
|
63
|
+
if (!configMdPath || !packageDir) {
|
|
49
64
|
return null;
|
|
50
65
|
}
|
|
51
66
|
|
|
@@ -56,29 +71,27 @@ export function loadPluginConfigPage(pluginName: string): ConfigPageManifest | n
|
|
|
56
71
|
const frontmatter = parsed.data as any;
|
|
57
72
|
const fields = (frontmatter.fields || []) as ConfigField[];
|
|
58
73
|
|
|
59
|
-
// Validate fields
|
|
60
74
|
for (const field of fields) {
|
|
61
75
|
if (!field.key || !field.label || !field.type) {
|
|
62
|
-
logger.warn(`Invalid field in ${
|
|
76
|
+
logger.warn(`Invalid field in ${packageName}/config.md: missing key, label, or type`);
|
|
63
77
|
continue;
|
|
64
78
|
}
|
|
65
79
|
|
|
66
|
-
// Validate key format: <configName>.<jsonPath>
|
|
67
80
|
if (!field.key.includes(".")) {
|
|
68
|
-
logger.warn(`Invalid field key in ${
|
|
81
|
+
logger.warn(`Invalid field key in ${packageName}/config.md: ${field.key} (must be <configName>.<path>)`);
|
|
69
82
|
}
|
|
70
83
|
}
|
|
71
84
|
|
|
72
85
|
return {
|
|
73
|
-
plugin:
|
|
74
|
-
title: frontmatter.title || `${
|
|
86
|
+
plugin: packageName,
|
|
87
|
+
title: frontmatter.title || `${packageName} Configuration`,
|
|
75
88
|
description: frontmatter.description,
|
|
76
89
|
markdown: parsed.content,
|
|
77
90
|
fields,
|
|
78
91
|
hasCustomPage: true,
|
|
79
92
|
};
|
|
80
93
|
} catch (error: any) {
|
|
81
|
-
logger.error(`Failed to load config page for ${
|
|
94
|
+
logger.error(`Failed to load config page for ${packageName}: ${error.message}`);
|
|
82
95
|
return null;
|
|
83
96
|
}
|
|
84
97
|
}
|
package/index.ts
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
createAIRoutes,
|
|
23
23
|
createDBRoutes,
|
|
24
24
|
createPluginConfigRoutes,
|
|
25
|
+
createServiceConfigRoutes,
|
|
25
26
|
createMemeRoutes,
|
|
26
27
|
createManageRoutes,
|
|
27
28
|
createStoreRoutes,
|
|
@@ -105,6 +106,7 @@ class WebUIRuntime {
|
|
|
105
106
|
this.app.route("/api/store", createStoreRoutes());
|
|
106
107
|
this.app.route("/api/db", createDBRoutes());
|
|
107
108
|
this.app.route("/api/plugin-config", createPluginConfigRoutes());
|
|
109
|
+
this.app.route("/api/service-config", createServiceConfigRoutes());
|
|
108
110
|
this.app.route("/api/meme", createMemeRoutes());
|
|
109
111
|
this.app.route("/api/data-management", createDataManagementRoutes());
|
|
110
112
|
this.app.route("/api/stranger", createStrangerRoutes());
|
package/package.json
CHANGED
package/routes/db.ts
CHANGED
|
@@ -14,8 +14,12 @@ import {
|
|
|
14
14
|
updateMessage,
|
|
15
15
|
} from "../database";
|
|
16
16
|
import { CHAT_DATA_DIR } from "../utils";
|
|
17
|
-
import { loadPluginConfigPage } from "../config-page-loader";
|
|
17
|
+
import { loadPluginConfigPage, loadServiceConfigPage } from "../config-page-loader";
|
|
18
18
|
import { getDatasource } from "../datasources";
|
|
19
|
+
import {
|
|
20
|
+
getServiceConfigs,
|
|
21
|
+
updateServiceConfig,
|
|
22
|
+
} from "mioku";
|
|
19
23
|
|
|
20
24
|
export function createDBRoutes() {
|
|
21
25
|
const app = new Hono();
|
|
@@ -219,3 +223,98 @@ export function createMemeRoutes() {
|
|
|
219
223
|
|
|
220
224
|
return app;
|
|
221
225
|
}
|
|
226
|
+
|
|
227
|
+
export function createServiceConfigRoutes() {
|
|
228
|
+
const app = new Hono();
|
|
229
|
+
const SERVICE_CONFIG_ROOT = path.join(process.cwd(), "config", "service");
|
|
230
|
+
|
|
231
|
+
app.get("/overview", (c) => {
|
|
232
|
+
const modulesPath = path.join(process.cwd(), "node_modules");
|
|
233
|
+
if (!fs.existsSync(modulesPath)) {
|
|
234
|
+
return c.json({ ok: true, data: [] });
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const services: string[] = [];
|
|
238
|
+
const entries = fs.readdirSync(modulesPath, { withFileTypes: true });
|
|
239
|
+
for (const entry of entries) {
|
|
240
|
+
if (entry.name.startsWith("mioku-service-")) {
|
|
241
|
+
services.push(entry.name.replace(/^mioku-service-/, ""));
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const overview = services
|
|
246
|
+
.map((name) => {
|
|
247
|
+
const configDir = path.join(SERVICE_CONFIG_ROOT, name);
|
|
248
|
+
const manifest = loadServiceConfigPage(name);
|
|
249
|
+
const existingConfigFiles =
|
|
250
|
+
fs.existsSync(configDir)
|
|
251
|
+
? fs
|
|
252
|
+
.readdirSync(configDir)
|
|
253
|
+
.filter((f) => f.endsWith(".json"))
|
|
254
|
+
.map((f) => f.replace(".json", ""))
|
|
255
|
+
: [];
|
|
256
|
+
const declaredConfigFiles = manifest
|
|
257
|
+
? Array.from(
|
|
258
|
+
new Set(
|
|
259
|
+
(manifest.fields || [])
|
|
260
|
+
.map((field) => String(field.key || ""))
|
|
261
|
+
.filter((key) => key.includes("."))
|
|
262
|
+
.map((key) => key.split(".")[0]),
|
|
263
|
+
),
|
|
264
|
+
)
|
|
265
|
+
: [];
|
|
266
|
+
const configFiles = Array.from(
|
|
267
|
+
new Set([...existingConfigFiles, ...declaredConfigFiles]),
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
return {
|
|
271
|
+
name,
|
|
272
|
+
title: manifest?.title || name,
|
|
273
|
+
description: manifest?.description,
|
|
274
|
+
hasPage: manifest?.hasCustomPage || false,
|
|
275
|
+
configFiles,
|
|
276
|
+
};
|
|
277
|
+
})
|
|
278
|
+
.filter((p) => p.hasPage);
|
|
279
|
+
|
|
280
|
+
return c.json({ ok: true, data: overview });
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
app.get("/:name/page", (c) => {
|
|
284
|
+
const name = c.req.param("name");
|
|
285
|
+
const manifest = loadServiceConfigPage(name);
|
|
286
|
+
const configs = getServiceConfigs(name);
|
|
287
|
+
|
|
288
|
+
if (!manifest) {
|
|
289
|
+
return c.json({ ok: true, data: null });
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return c.json({
|
|
293
|
+
ok: true,
|
|
294
|
+
data: {
|
|
295
|
+
plugin: manifest.plugin,
|
|
296
|
+
title: manifest.title,
|
|
297
|
+
description: manifest.description,
|
|
298
|
+
markdown: manifest.markdown,
|
|
299
|
+
fields: manifest.fields,
|
|
300
|
+
hasCustomPage: manifest.hasCustomPage,
|
|
301
|
+
configs,
|
|
302
|
+
},
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
app.get("/:name", (c) => {
|
|
307
|
+
const name = c.req.param("name");
|
|
308
|
+
return c.json({ ok: true, data: getServiceConfigs(name) });
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
app.put("/:name/:config", async (c) => {
|
|
312
|
+
const serviceName = c.req.param("name");
|
|
313
|
+
const configName = c.req.param("config");
|
|
314
|
+
const body = await c.req.json();
|
|
315
|
+
updateServiceConfig(serviceName, configName, body);
|
|
316
|
+
return c.json({ ok: true });
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
return app;
|
|
320
|
+
}
|
package/routes/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { createConfigRoutes } from "./config";
|
|
2
2
|
export { createWebUISettingsRoutes } from "./webui";
|
|
3
3
|
export { createAIRoutes } from "./ai";
|
|
4
|
-
export { createDBRoutes, createPluginConfigRoutes, createMemeRoutes } from "./db";
|
|
4
|
+
export { createDBRoutes, createPluginConfigRoutes, createMemeRoutes, createServiceConfigRoutes } from "./db";
|
|
5
5
|
export { createManageRoutes } from "./manage";
|
|
6
6
|
export { createStoreRoutes } from "./store";
|
|
7
7
|
export { createDataManagementRoutes } from "./data-management";
|