imean-service-engine 1.5.0 → 1.7.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 +298 -0
- package/dist/mod.cjs +395 -35
- package/dist/mod.d.cts +100 -11
- package/dist/mod.d.ts +100 -11
- package/dist/mod.js +390 -36
- package/package.json +1 -1
package/dist/mod.js
CHANGED
@@ -6,6 +6,7 @@ import { serve } from '@hono/node-server';
|
|
6
6
|
import { Etcd3 } from 'etcd3';
|
7
7
|
import fs from 'fs-extra';
|
8
8
|
import { Hono } from 'hono';
|
9
|
+
import { timing } from 'hono/timing';
|
9
10
|
import { trace, SpanStatusCode } from '@opentelemetry/api';
|
10
11
|
import winston, { format } from 'winston';
|
11
12
|
import prettier from 'prettier';
|
@@ -17,6 +18,8 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
17
18
|
import { JSONRPCMessageSchema } from '@modelcontextprotocol/sdk/types.js';
|
18
19
|
import { streamSSE } from 'hono/streaming';
|
19
20
|
import { ulid } from 'ulid';
|
21
|
+
import { html } from 'hono/html';
|
22
|
+
import { jsx, jsxs } from 'hono/jsx/jsx-runtime';
|
20
23
|
export { default as dayjs } from 'dayjs';
|
21
24
|
|
22
25
|
// mod.ts
|
@@ -586,6 +589,62 @@ var ActionHandler = class {
|
|
586
589
|
function isAsyncIterable(obj) {
|
587
590
|
return obj != null && typeof obj[Symbol.asyncIterator] === "function";
|
588
591
|
}
|
592
|
+
|
593
|
+
// decorators/page.ts
|
594
|
+
var PAGE_METADATA = Symbol("page:metadata");
|
595
|
+
function Page(options) {
|
596
|
+
return function(_target, context) {
|
597
|
+
const methodName = context.name;
|
598
|
+
context.addInitializer(function() {
|
599
|
+
const prototype = this.constructor.prototype;
|
600
|
+
const existingMetadata = prototype[PAGE_METADATA] || {};
|
601
|
+
existingMetadata[methodName] = {
|
602
|
+
name: methodName,
|
603
|
+
description: options.description || "",
|
604
|
+
method: options.method,
|
605
|
+
path: options.path
|
606
|
+
};
|
607
|
+
prototype[PAGE_METADATA] = existingMetadata;
|
608
|
+
});
|
609
|
+
};
|
610
|
+
}
|
611
|
+
function getPageMetadata(target) {
|
612
|
+
return target.constructor.prototype[PAGE_METADATA] ?? {};
|
613
|
+
}
|
614
|
+
var tracer3 = trace.getTracer("page-handler");
|
615
|
+
var PageHandler = class {
|
616
|
+
constructor(moduleInstance, options, moduleName) {
|
617
|
+
this.moduleInstance = moduleInstance;
|
618
|
+
this.options = options;
|
619
|
+
this.moduleName = moduleName;
|
620
|
+
}
|
621
|
+
async handle(ctx) {
|
622
|
+
return await tracer3.startActiveSpan(
|
623
|
+
`handle ${this.moduleName}.${this.options.name}`,
|
624
|
+
async (span) => {
|
625
|
+
span.setAttribute("module", this.moduleName);
|
626
|
+
span.setAttribute("page", this.options.name);
|
627
|
+
span.setAttribute("path", this.options.path);
|
628
|
+
try {
|
629
|
+
const result = await this.moduleInstance[this.options.name].apply(
|
630
|
+
this.moduleInstance,
|
631
|
+
[ctx]
|
632
|
+
);
|
633
|
+
return ctx.html(result);
|
634
|
+
} catch (error) {
|
635
|
+
span.recordException(error);
|
636
|
+
span.setStatus({
|
637
|
+
code: SpanStatusCode.ERROR,
|
638
|
+
message: error.message
|
639
|
+
});
|
640
|
+
throw error;
|
641
|
+
} finally {
|
642
|
+
span.end();
|
643
|
+
}
|
644
|
+
}
|
645
|
+
);
|
646
|
+
}
|
647
|
+
};
|
589
648
|
var WebSocketHandler = class {
|
590
649
|
constructor(microservice, options) {
|
591
650
|
this.microservice = microservice;
|
@@ -770,10 +829,12 @@ var Microservice = class {
|
|
770
829
|
lease;
|
771
830
|
scheduler;
|
772
831
|
abortController;
|
773
|
-
isShuttingDown = false;
|
774
832
|
statisticsTimer;
|
775
833
|
wsHandler;
|
776
834
|
actionHandlers = /* @__PURE__ */ new Map();
|
835
|
+
pageHandlers = /* @__PURE__ */ new Map();
|
836
|
+
activeRequests = /* @__PURE__ */ new Map();
|
837
|
+
status = "running";
|
777
838
|
modules = /* @__PURE__ */ new Map();
|
778
839
|
fetch;
|
779
840
|
options;
|
@@ -781,6 +842,7 @@ var Microservice = class {
|
|
781
842
|
serviceId;
|
782
843
|
constructor(options) {
|
783
844
|
this.app = new Hono();
|
845
|
+
this.app.use(timing());
|
784
846
|
this.nodeWebSocket = createNodeWebSocket({ app: this.app });
|
785
847
|
this.serviceId = crypto.randomUUID();
|
786
848
|
this.options = {
|
@@ -796,6 +858,10 @@ var Microservice = class {
|
|
796
858
|
websocket: { enabled: false },
|
797
859
|
cacheAdapter: new MemoryCacheAdapter(),
|
798
860
|
plugins: [],
|
861
|
+
gracefulShutdown: {
|
862
|
+
timeout: 3e4,
|
863
|
+
cleanupHooks: []
|
864
|
+
},
|
799
865
|
...options
|
800
866
|
};
|
801
867
|
this.cache = this.options.cacheAdapter;
|
@@ -815,6 +881,11 @@ var Microservice = class {
|
|
815
881
|
}
|
816
882
|
await this.registerService(true);
|
817
883
|
await this.initPlugins();
|
884
|
+
this.app.get(this.options.prefix, (ctx) => {
|
885
|
+
const name = this.options.name ?? "Microservice";
|
886
|
+
const version = this.options.version ?? "1.0.0";
|
887
|
+
return ctx.text(`${name} is ${this.status}. version: ${version}`);
|
888
|
+
});
|
818
889
|
}
|
819
890
|
async initModules() {
|
820
891
|
for (const ModuleClass of this.options.modules) {
|
@@ -829,6 +900,7 @@ var Microservice = class {
|
|
829
900
|
logger_default.info(`[ \u6CE8\u518C\u6A21\u5757 ] ${moduleName} ${metadata.options.description}`);
|
830
901
|
this.modules.set(moduleName, moduleInstance);
|
831
902
|
const actions = getActionMetadata(ModuleClass.prototype);
|
903
|
+
const pages = getPageMetadata(ModuleClass.prototype);
|
832
904
|
for (const [actionName, actionMetadata] of Object.entries(actions)) {
|
833
905
|
const handler = new ActionHandler(
|
834
906
|
moduleInstance,
|
@@ -842,6 +914,18 @@ var Microservice = class {
|
|
842
914
|
`[ \u6CE8\u518C\u52A8\u4F5C ] ${moduleName}.${actionName} ${actionMetadata.description} ${actionMetadata.mcp ? "MCP:" + actionMetadata.mcp?.type : ""}`
|
843
915
|
);
|
844
916
|
}
|
917
|
+
for (const [_, page] of Object.entries(pages)) {
|
918
|
+
const handler = new PageHandler(
|
919
|
+
moduleInstance,
|
920
|
+
page,
|
921
|
+
moduleName
|
922
|
+
);
|
923
|
+
this.pageHandlers.set(`${moduleName}.${page.name}`, handler);
|
924
|
+
this.app[page.method](`${this.options.prefix}${page.path}`, (ctx) => handler.handle(ctx));
|
925
|
+
logger_default.info(
|
926
|
+
`[ \u6CE8\u518C\u9875\u9762 ] ${moduleName}.${page.name} ${page.method.toUpperCase()} ${page.path} ${page.description}`
|
927
|
+
);
|
928
|
+
}
|
845
929
|
const schedules = getScheduleMetadata(ModuleClass.prototype);
|
846
930
|
if (schedules && Object.keys(schedules).length > 0) {
|
847
931
|
if (!this.scheduler && this.etcdClient) {
|
@@ -871,11 +955,6 @@ var Microservice = class {
|
|
871
955
|
initRoutes() {
|
872
956
|
const startTime = Date.now();
|
873
957
|
const prefix = this.options.prefix || "/api";
|
874
|
-
this.app.get(prefix, (ctx) => {
|
875
|
-
const name = this.options.name ?? "Microservice";
|
876
|
-
const version = this.options.version ?? "1.0.0";
|
877
|
-
return ctx.text(`${name} is running. version: ${version}`);
|
878
|
-
});
|
879
958
|
this.app.get(`${prefix}/health`, (ctx) => {
|
880
959
|
return ctx.json({
|
881
960
|
status: "ok",
|
@@ -890,7 +969,9 @@ var Microservice = class {
|
|
890
969
|
version: this.options.version,
|
891
970
|
env: this.options.env,
|
892
971
|
modules: this.getModules(),
|
893
|
-
stats: Object.fromEntries(this.statsMap)
|
972
|
+
stats: Object.fromEntries(this.statsMap),
|
973
|
+
activeRequests: this.getActiveRequestCount(),
|
974
|
+
status: this.status
|
894
975
|
});
|
895
976
|
});
|
896
977
|
this.app.get(`${prefix}/client.ts`, async (ctx) => {
|
@@ -1087,7 +1168,12 @@ var Microservice = class {
|
|
1087
1168
|
process.on("SIGINT", () => {
|
1088
1169
|
logger_default.info(`
|
1089
1170
|
Received SIGINT signal`);
|
1090
|
-
this.
|
1171
|
+
this.shutdown();
|
1172
|
+
});
|
1173
|
+
process.on("SIGTERM", () => {
|
1174
|
+
logger_default.info(`
|
1175
|
+
Received SIGTERM signal`);
|
1176
|
+
this.shutdown();
|
1091
1177
|
});
|
1092
1178
|
process.on("unhandledrejection", (event) => {
|
1093
1179
|
logger_default.error("Unhandled rejection:", event.reason);
|
@@ -1099,14 +1185,16 @@ Received SIGINT signal`);
|
|
1099
1185
|
/**
|
1100
1186
|
* 优雅停机
|
1101
1187
|
*/
|
1102
|
-
async
|
1103
|
-
if (this.
|
1104
|
-
this.
|
1105
|
-
logger_default.info("\
|
1188
|
+
async shutdown() {
|
1189
|
+
if (this.status === "shutting_down") return;
|
1190
|
+
this.status = "shutting_down";
|
1191
|
+
logger_default.info("\nshutdown initiated...");
|
1106
1192
|
if (this.statisticsTimer) clearInterval(this.statisticsTimer);
|
1107
1193
|
try {
|
1194
|
+
await this.waitForActiveRequests();
|
1195
|
+
await this.executeCleanupHooks();
|
1108
1196
|
await this.stop();
|
1109
|
-
logger_default.info("
|
1197
|
+
logger_default.info("shutdown completed");
|
1110
1198
|
} catch (error) {
|
1111
1199
|
logger_default.error("Error during shutdown:", error);
|
1112
1200
|
process.exit(1);
|
@@ -1114,6 +1202,57 @@ Received SIGINT signal`);
|
|
1114
1202
|
process.exit(0);
|
1115
1203
|
}
|
1116
1204
|
}
|
1205
|
+
/**
|
1206
|
+
* 等待所有活跃请求完成
|
1207
|
+
*/
|
1208
|
+
async waitForActiveRequests() {
|
1209
|
+
const timeout = this.options.gracefulShutdown?.timeout || 3e4;
|
1210
|
+
const startTime = Date.now();
|
1211
|
+
logger_default.info(`Waiting for ${this.activeRequests.size} active requests to complete...`);
|
1212
|
+
return new Promise((resolve) => {
|
1213
|
+
const checkInterval = setInterval(() => {
|
1214
|
+
const elapsed = Date.now() - startTime;
|
1215
|
+
if (this.activeRequests.size === 0) {
|
1216
|
+
clearInterval(checkInterval);
|
1217
|
+
logger_default.info("All active requests completed");
|
1218
|
+
resolve();
|
1219
|
+
} else if (elapsed >= timeout) {
|
1220
|
+
clearInterval(checkInterval);
|
1221
|
+
logger_default.warn(`Timeout waiting for requests to complete. ${this.activeRequests.size} requests still active`);
|
1222
|
+
resolve();
|
1223
|
+
} else {
|
1224
|
+
logger_default.info(`Still waiting for ${this.activeRequests.size} requests... (${elapsed}ms elapsed)`);
|
1225
|
+
}
|
1226
|
+
}, 1e3);
|
1227
|
+
});
|
1228
|
+
}
|
1229
|
+
/**
|
1230
|
+
* 执行清理hook
|
1231
|
+
*/
|
1232
|
+
async executeCleanupHooks() {
|
1233
|
+
const hooks = this.options.gracefulShutdown?.cleanupHooks || [];
|
1234
|
+
if (hooks.length === 0) {
|
1235
|
+
logger_default.info("No cleanup hooks configured");
|
1236
|
+
return;
|
1237
|
+
}
|
1238
|
+
logger_default.info(`Executing ${hooks.length} cleanup hooks...`);
|
1239
|
+
for (const hook of hooks) {
|
1240
|
+
try {
|
1241
|
+
const timeout = hook.timeout || 5e3;
|
1242
|
+
logger_default.info(`Executing cleanup hook: ${hook.name}`);
|
1243
|
+
await Promise.race([
|
1244
|
+
Promise.resolve(hook.cleanup()),
|
1245
|
+
new Promise(
|
1246
|
+
(_, reject) => setTimeout(() => reject(new Error(`Cleanup hook ${hook.name} timeout`)), timeout)
|
1247
|
+
)
|
1248
|
+
]);
|
1249
|
+
logger_default.info(`Cleanup hook ${hook.name} completed successfully`);
|
1250
|
+
} catch (error) {
|
1251
|
+
logger_default.error(`Cleanup hook ${hook.name} failed:`, error);
|
1252
|
+
}
|
1253
|
+
}
|
1254
|
+
logger_default.info("All cleanup hooks completed");
|
1255
|
+
}
|
1117
1256
|
initStatsEventManager() {
|
1118
1257
|
this.statisticsTimer = setInterval(async () => {
|
1119
1258
|
await this.updateStats();
|
@@ -1155,14 +1294,54 @@ Received SIGINT signal`);
|
|
1155
1294
|
}
|
1156
1295
|
return handler;
|
1157
1296
|
}
|
1297
|
+
/**
|
1298
|
+
* 添加活跃请求跟踪
|
1299
|
+
*/
|
1300
|
+
addActiveRequest(requestId, requestInfo) {
|
1301
|
+
this.activeRequests.set(requestId, requestInfo);
|
1302
|
+
}
|
1303
|
+
/**
|
1304
|
+
* 移除活跃请求跟踪
|
1305
|
+
*/
|
1306
|
+
removeActiveRequest(requestId) {
|
1307
|
+
this.activeRequests.delete(requestId);
|
1308
|
+
}
|
1309
|
+
/**
|
1310
|
+
* 获取当前活跃请求数量
|
1311
|
+
*/
|
1312
|
+
getActiveRequestCount() {
|
1313
|
+
return this.activeRequests.size;
|
1314
|
+
}
|
1315
|
+
/**
|
1316
|
+
* 获取当前活跃请求信息
|
1317
|
+
*/
|
1318
|
+
getActiveRequests() {
|
1319
|
+
return Array.from(this.activeRequests.values());
|
1320
|
+
}
|
1158
1321
|
handleRequest = async (ctx) => {
|
1159
1322
|
const { moduleName, actionName } = ctx.req.param();
|
1160
1323
|
const handler = this.getActionHandler(moduleName, actionName);
|
1324
|
+
const requestId = crypto.randomUUID();
|
1325
|
+
const startTime = Date.now();
|
1326
|
+
if (this.status === "shutting_down") {
|
1327
|
+
return ctx.json({
|
1328
|
+
success: false,
|
1329
|
+
error: "Service is shutting down"
|
1330
|
+
}, 503);
|
1331
|
+
}
|
1161
1332
|
try {
|
1162
1333
|
const paramsText = await ctx.req.text();
|
1334
|
+
this.addActiveRequest(requestId, {
|
1335
|
+
id: requestId,
|
1336
|
+
moduleName,
|
1337
|
+
actionName,
|
1338
|
+
startTime,
|
1339
|
+
params: paramsText
|
1340
|
+
});
|
1163
1341
|
const result = await handler.handle(paramsText);
|
1164
1342
|
if (handler.metadata.stream) {
|
1165
1343
|
const encoder = new TextEncoder();
|
1344
|
+
const microservice = this;
|
1166
1345
|
const stream = new ReadableStream({
|
1167
1346
|
async start(controller) {
|
1168
1347
|
try {
|
@@ -1186,6 +1365,8 @@ Received SIGINT signal`);
|
|
1186
1365
|
encoder.encode(ejson4.stringify(response) + "\n")
|
1187
1366
|
);
|
1188
1367
|
controller.close();
|
1368
|
+
} finally {
|
1369
|
+
microservice.removeActiveRequest(requestId);
|
1189
1370
|
}
|
1190
1371
|
}
|
1191
1372
|
});
|
@@ -1197,8 +1378,10 @@ Received SIGINT signal`);
|
|
1197
1378
|
}
|
1198
1379
|
});
|
1199
1380
|
}
|
1381
|
+
this.removeActiveRequest(requestId);
|
1200
1382
|
return ctx.text(ejson4.stringify({ success: true, data: result }));
|
1201
1383
|
} catch (error) {
|
1384
|
+
this.removeActiveRequest(requestId);
|
1202
1385
|
return ctx.json({ success: false, error: error.message });
|
1203
1386
|
}
|
1204
1387
|
};
|
@@ -1214,28 +1397,6 @@ Received SIGINT signal`);
|
|
1214
1397
|
await this.waitingInitialization;
|
1215
1398
|
}
|
1216
1399
|
};
|
1217
|
-
|
1218
|
-
// utils/checker.ts
|
1219
|
-
async function startCheck(checkers, pass) {
|
1220
|
-
logger_default.info("[ \u9884\u68C0\u5F00\u59CB ]");
|
1221
|
-
for (const [index, checker] of checkers.entries()) {
|
1222
|
-
const seq = index + 1;
|
1223
|
-
logger_default.info(`${seq}. ${checker.name}`);
|
1224
|
-
try {
|
1225
|
-
if (checker.skip) {
|
1226
|
-
logger_default.warn(`${seq}. ${checker.name} [\u8DF3\u8FC7]`);
|
1227
|
-
continue;
|
1228
|
-
}
|
1229
|
-
await checker.check();
|
1230
|
-
logger_default.info(`${seq}. ${checker.name} [\u6210\u529F]`);
|
1231
|
-
} catch (error) {
|
1232
|
-
logger_default.error(`${seq}. ${checker.name} [\u5931\u8D25]`);
|
1233
|
-
throw error;
|
1234
|
-
}
|
1235
|
-
}
|
1236
|
-
logger_default.info("[ \u9884\u68C0\u5B8C\u6210 ]");
|
1237
|
-
if (pass) await pass();
|
1238
|
-
}
|
1239
1400
|
var HonoTransport = class {
|
1240
1401
|
constructor(url, stream, closeStream) {
|
1241
1402
|
this.url = url;
|
@@ -1351,5 +1512,198 @@ var ModelContextProtocolPlugin = class extends Plugin {
|
|
1351
1512
|
);
|
1352
1513
|
};
|
1353
1514
|
};
|
1515
|
+
var DEFAULT_FAVICON = /* @__PURE__ */ jsx(
|
1516
|
+
"link",
|
1517
|
+
{
|
1518
|
+
rel: "icon",
|
1519
|
+
href: "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' width='100' height='100'><defs><linearGradient id='nodeGradient' x1='0%' y1='0%' x2='100%' y2='100%'><stop offset='0%' stop-color='%233498db'/><stop offset='100%' stop-color='%232980b9'/></linearGradient><linearGradient id='centerNodeGradient' x1='0%' y1='0%' x2='100%' y2='100%'><stop offset='0%' stop-color='%232ecc71'/><stop offset='100%' stop-color='%2327ae60'/></linearGradient></defs><circle cx='50' cy='50' r='45' fill='%23f5f7fa'/><path d='M30,30 L50,50' stroke='%23bdc3c7' stroke-width='2' stroke-linecap='round'/><path d='M70,30 L50,50' stroke='%23bdc3c7' stroke-width='2' stroke-linecap='round'/><path d='M30,70 L50,50' stroke='%23bdc3c7' stroke-width='2' stroke-linecap='round'/><path d='M70,70 L50,50' stroke='%23bdc3c7' stroke-width='2' stroke-linecap='round'/><polygon points='30,15 45,25 45,45 30,55 15,45 15,25' fill='url(%23nodeGradient)' stroke='%232980b9' stroke-width='1.5'/><polygon points='70,15 85,25 85,45 70,55 55,45 55,25' fill='url(%23nodeGradient)' stroke='%232980b9' stroke-width='1.5'/><polygon points='30,45 45,55 45,75 30,85 15,75 15,55' fill='url(%23nodeGradient)' stroke='%232980b9' stroke-width='1.5'/><polygon points='70,45 85,55 85,75 70,85 55,75 55,55' fill='url(%23nodeGradient)' stroke='%232980b9' stroke-width='1.5'/><polygon points='50,30 65,40 65,60 50,70 35,60 35,40' fill='url(%23centerNodeGradient)' stroke='%2327ae60' stroke-width='2'/><circle cx='30' cy='30' r='3' fill='%23ffffff'/><circle cx='70' cy='30' r='3' fill='%23ffffff'/><circle cx='30' cy='70' r='3' fill='%23ffffff'/><circle cx='70' cy='70' r='3' fill='%23ffffff'/><circle cx='50' cy='50' r='4' fill='%23ffffff'/></svg>",
|
1520
|
+
type: "image/svg+xml"
|
1521
|
+
}
|
1522
|
+
);
|
1523
|
+
var BaseLayout = (props = {
|
1524
|
+
title: "Microservice Template"
|
1525
|
+
}) => html`<!DOCTYPE html>
|
1526
|
+
<html>
|
1527
|
+
<head>
|
1528
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
1529
|
+
<title>${props.title}</title>
|
1530
|
+
${props.heads}
|
1531
|
+
</head>
|
1532
|
+
<body>
|
1533
|
+
${props.children}
|
1534
|
+
</body>
|
1535
|
+
</html>`;
|
1536
|
+
var HtmxLayout = (props = {
|
1537
|
+
title: "Microservice Template"
|
1538
|
+
}) => BaseLayout({
|
1539
|
+
title: props.title,
|
1540
|
+
heads: html`
|
1541
|
+
<script src="https://unpkg.com/htmx.org@latest"></script>
|
1542
|
+
<script src="https://unpkg.com/hyperscript.org@latest"></script>
|
1543
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
1544
|
+
${props.favicon || DEFAULT_FAVICON}
|
1545
|
+
`,
|
1546
|
+
children: props.children
|
1547
|
+
});
|
1548
|
+
var InfoCard = ({
|
1549
|
+
icon,
|
1550
|
+
iconColor,
|
1551
|
+
bgColor,
|
1552
|
+
label,
|
1553
|
+
value
|
1554
|
+
}) => /* @__PURE__ */ jsxs("div", { className: `${bgColor} p-4 rounded-lg`, children: [
|
1555
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center mb-2", children: [
|
1556
|
+
/* @__PURE__ */ jsx(
|
1557
|
+
"svg",
|
1558
|
+
{
|
1559
|
+
className: `w-5 h-5 ${iconColor} mr-2`,
|
1560
|
+
fill: "none",
|
1561
|
+
stroke: "currentColor",
|
1562
|
+
viewBox: "0 0 24 24",
|
1563
|
+
children: /* @__PURE__ */ jsx(
|
1564
|
+
"path",
|
1565
|
+
{
|
1566
|
+
strokeLinecap: "round",
|
1567
|
+
strokeLinejoin: "round",
|
1568
|
+
strokeWidth: 2,
|
1569
|
+
d: icon
|
1570
|
+
}
|
1571
|
+
)
|
1572
|
+
}
|
1573
|
+
),
|
1574
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-gray-600", children: label })
|
1575
|
+
] }),
|
1576
|
+
/* @__PURE__ */ jsx("p", { className: `text-xl font-semibold text-gray-900`, children: value })
|
1577
|
+
] });
|
1578
|
+
var getEnvironmentBadgeClass = (env) => {
|
1579
|
+
switch (env) {
|
1580
|
+
case "prod":
|
1581
|
+
return "bg-red-100 text-red-800";
|
1582
|
+
case "stg":
|
1583
|
+
return "bg-yellow-100 text-yellow-800";
|
1584
|
+
case "dev":
|
1585
|
+
default:
|
1586
|
+
return "bg-blue-100 text-blue-800";
|
1587
|
+
}
|
1588
|
+
};
|
1589
|
+
var ServiceInfoCards = ({
|
1590
|
+
serviceInfo
|
1591
|
+
}) => {
|
1592
|
+
const infoCards = [
|
1593
|
+
{
|
1594
|
+
icon: "M7 4V2a1 1 0 011-1h8a1 1 0 011 1v2m-9 0h10m-10 0a2 2 0 00-2 2v14a2 2 0 002 2h10a2 2 0 002-2V6a2 2 0 00-2-2",
|
1595
|
+
iconColor: "text-blue-600",
|
1596
|
+
bgColor: "bg-blue-50",
|
1597
|
+
label: "\u670D\u52A1\u540D\u79F0",
|
1598
|
+
value: serviceInfo.name
|
1599
|
+
},
|
1600
|
+
{
|
1601
|
+
icon: "M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1",
|
1602
|
+
iconColor: "text-orange-600",
|
1603
|
+
bgColor: "bg-orange-50",
|
1604
|
+
label: "\u670D\u52A1\u8DEF\u5F84",
|
1605
|
+
value: serviceInfo.prefix || "/",
|
1606
|
+
isMonospace: true
|
1607
|
+
},
|
1608
|
+
{
|
1609
|
+
icon: "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z",
|
1610
|
+
iconColor: "text-green-600",
|
1611
|
+
bgColor: "bg-green-50",
|
1612
|
+
label: "\u8FD0\u884C\u73AF\u5883",
|
1613
|
+
value: /* @__PURE__ */ jsx(
|
1614
|
+
"span",
|
1615
|
+
{
|
1616
|
+
className: `px-2 py-1 rounded-full text-sm ${getEnvironmentBadgeClass(serviceInfo.env ?? "dev")}`,
|
1617
|
+
children: serviceInfo.env ?? "dev"
|
1618
|
+
}
|
1619
|
+
)
|
1620
|
+
},
|
1621
|
+
{
|
1622
|
+
icon: "M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z",
|
1623
|
+
iconColor: "text-purple-600",
|
1624
|
+
bgColor: "bg-purple-50",
|
1625
|
+
label: "\u7248\u672C\u53F7",
|
1626
|
+
value: serviceInfo.version || "unknown"
|
1627
|
+
}
|
1628
|
+
];
|
1629
|
+
return /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg shadow-md p-6 mb-8", children: [
|
1630
|
+
/* @__PURE__ */ jsxs("h2", { className: "text-2xl font-semibold text-gray-800 mb-6 flex items-center", children: [
|
1631
|
+
/* @__PURE__ */ jsx(
|
1632
|
+
"svg",
|
1633
|
+
{
|
1634
|
+
className: "w-6 h-6 mr-2 text-blue-600",
|
1635
|
+
fill: "none",
|
1636
|
+
stroke: "currentColor",
|
1637
|
+
viewBox: "0 0 24 24",
|
1638
|
+
children: /* @__PURE__ */ jsx(
|
1639
|
+
"path",
|
1640
|
+
{
|
1641
|
+
strokeLinecap: "round",
|
1642
|
+
strokeLinejoin: "round",
|
1643
|
+
strokeWidth: 2,
|
1644
|
+
d: "M13 10V3L4 14h7v7l9-11h-7z"
|
1645
|
+
}
|
1646
|
+
)
|
1647
|
+
}
|
1648
|
+
),
|
1649
|
+
"\u670D\u52A1\u57FA\u672C\u4FE1\u606F"
|
1650
|
+
] }),
|
1651
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-6", children: infoCards.map((card, index) => /* @__PURE__ */ jsx(InfoCard, { ...card }, index)) })
|
1652
|
+
] });
|
1653
|
+
};
|
1654
|
+
var ServiceStatusPage = ({
|
1655
|
+
serviceInfo
|
1656
|
+
}) => {
|
1657
|
+
return /* @__PURE__ */ jsx("div", { className: "min-h-screen bg-gray-50 py-8", children: /* @__PURE__ */ jsxs("div", { className: "max-w-6xl mx-auto px-4", children: [
|
1658
|
+
/* @__PURE__ */ jsx("div", { className: "mb-8", children: /* @__PURE__ */ jsx("h1", { className: "text-4xl font-bold text-gray-900 mb-2", children: "Service Status" }) }),
|
1659
|
+
/* @__PURE__ */ jsx(ServiceInfoCards, { serviceInfo })
|
1660
|
+
] }) });
|
1661
|
+
};
|
1662
|
+
var ServiceStatusPage_default = ServiceStatusPage;
|
1663
|
+
|
1664
|
+
// core/plugins/page/mod.ts
|
1665
|
+
var PageRenderPlugin = class extends Plugin {
|
1666
|
+
initialize = async (engine) => {
|
1667
|
+
const app = engine.getApp();
|
1668
|
+
app.get(`${engine.options.prefix}`, async (ctx) => {
|
1669
|
+
return ctx.html(HtmxLayout({
|
1670
|
+
title: engine.options.name,
|
1671
|
+
children: ServiceStatusPage_default({
|
1672
|
+
serviceInfo: {
|
1673
|
+
name: engine.options.name,
|
1674
|
+
prefix: engine.options.prefix,
|
1675
|
+
version: engine.options.version,
|
1676
|
+
env: engine.options.env,
|
1677
|
+
id: engine.serviceId,
|
1678
|
+
modules: engine.getModules(false)
|
1679
|
+
}
|
1680
|
+
})
|
1681
|
+
}));
|
1682
|
+
});
|
1683
|
+
logger_default.info(`PageRenderPlugin enabled`);
|
1684
|
+
};
|
1685
|
+
};
|
1686
|
+
|
1687
|
+
// utils/checker.ts
|
1688
|
+
async function startCheck(checkers, pass) {
|
1689
|
+
logger_default.info("[ \u9884\u68C0\u5F00\u59CB ]");
|
1690
|
+
for (const [index, checker] of checkers.entries()) {
|
1691
|
+
const seq = index + 1;
|
1692
|
+
logger_default.info(`${seq}. ${checker.name}`);
|
1693
|
+
try {
|
1694
|
+
if (checker.skip) {
|
1695
|
+
logger_default.warn(`${seq}. ${checker.name} [\u8DF3\u8FC7]`);
|
1696
|
+
continue;
|
1697
|
+
}
|
1698
|
+
await checker.check();
|
1699
|
+
logger_default.info(`${seq}. ${checker.name} [\u6210\u529F]`);
|
1700
|
+
} catch (error) {
|
1701
|
+
logger_default.error(`${seq}. ${checker.name} [\u5931\u8D25]`);
|
1702
|
+
throw error;
|
1703
|
+
}
|
1704
|
+
}
|
1705
|
+
logger_default.info("[ \u9884\u68C0\u5B8C\u6210 ]");
|
1706
|
+
if (pass) await pass();
|
1707
|
+
}
|
1354
1708
|
|
1355
|
-
export { Action, CacheAdapter, MemoryCacheAdapter, Microservice, ModelContextProtocolPlugin, Module, Plugin, RedisCacheAdapter, Schedule, ScheduleMode, ServiceContext, logger_default as logger, startCheck };
|
1709
|
+
export { Action, BaseLayout, CacheAdapter, HtmxLayout, MemoryCacheAdapter, Microservice, ModelContextProtocolPlugin, Module, Page, PageRenderPlugin, Plugin, RedisCacheAdapter, Schedule, ScheduleMode, ServiceContext, ServiceInfoCards, ServiceStatusPage, logger_default as logger, startCheck };
|