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.cjs
CHANGED
@@ -7,6 +7,7 @@ var nodeServer = require('@hono/node-server');
|
|
7
7
|
var etcd3 = require('etcd3');
|
8
8
|
var fs = require('fs-extra');
|
9
9
|
var hono = require('hono');
|
10
|
+
var timing = require('hono/timing');
|
10
11
|
var api = require('@opentelemetry/api');
|
11
12
|
var winston = require('winston');
|
12
13
|
var prettier = require('prettier');
|
@@ -17,6 +18,8 @@ var mcp_js = require('@modelcontextprotocol/sdk/server/mcp.js');
|
|
17
18
|
var types_js = require('@modelcontextprotocol/sdk/types.js');
|
18
19
|
var streaming = require('hono/streaming');
|
19
20
|
var ulid = require('ulid');
|
21
|
+
var html = require('hono/html');
|
22
|
+
var jsxRuntime = require('hono/jsx/jsx-runtime');
|
20
23
|
var dayjs = require('dayjs');
|
21
24
|
|
22
25
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
@@ -595,6 +598,62 @@ var ActionHandler = class {
|
|
595
598
|
function isAsyncIterable(obj) {
|
596
599
|
return obj != null && typeof obj[Symbol.asyncIterator] === "function";
|
597
600
|
}
|
601
|
+
|
602
|
+
// decorators/page.ts
|
603
|
+
var PAGE_METADATA = Symbol("page:metadata");
|
604
|
+
function Page(options) {
|
605
|
+
return function(_target, context) {
|
606
|
+
const methodName = context.name;
|
607
|
+
context.addInitializer(function() {
|
608
|
+
const prototype = this.constructor.prototype;
|
609
|
+
const existingMetadata = prototype[PAGE_METADATA] || {};
|
610
|
+
existingMetadata[methodName] = {
|
611
|
+
name: methodName,
|
612
|
+
description: options.description || "",
|
613
|
+
method: options.method,
|
614
|
+
path: options.path
|
615
|
+
};
|
616
|
+
prototype[PAGE_METADATA] = existingMetadata;
|
617
|
+
});
|
618
|
+
};
|
619
|
+
}
|
620
|
+
function getPageMetadata(target) {
|
621
|
+
return target.constructor.prototype[PAGE_METADATA] ?? {};
|
622
|
+
}
|
623
|
+
var tracer3 = api.trace.getTracer("page-handler");
|
624
|
+
var PageHandler = class {
|
625
|
+
constructor(moduleInstance, options, moduleName) {
|
626
|
+
this.moduleInstance = moduleInstance;
|
627
|
+
this.options = options;
|
628
|
+
this.moduleName = moduleName;
|
629
|
+
}
|
630
|
+
async handle(ctx) {
|
631
|
+
return await tracer3.startActiveSpan(
|
632
|
+
`handle ${this.moduleName}.${this.options.name}`,
|
633
|
+
async (span) => {
|
634
|
+
span.setAttribute("module", this.moduleName);
|
635
|
+
span.setAttribute("page", this.options.name);
|
636
|
+
span.setAttribute("path", this.options.path);
|
637
|
+
try {
|
638
|
+
const result = await this.moduleInstance[this.options.name].apply(
|
639
|
+
this.moduleInstance,
|
640
|
+
[ctx]
|
641
|
+
);
|
642
|
+
return ctx.html(result);
|
643
|
+
} catch (error) {
|
644
|
+
span.recordException(error);
|
645
|
+
span.setStatus({
|
646
|
+
code: api.SpanStatusCode.ERROR,
|
647
|
+
message: error.message
|
648
|
+
});
|
649
|
+
throw error;
|
650
|
+
} finally {
|
651
|
+
span.end();
|
652
|
+
}
|
653
|
+
}
|
654
|
+
);
|
655
|
+
}
|
656
|
+
};
|
598
657
|
var WebSocketHandler = class {
|
599
658
|
constructor(microservice, options) {
|
600
659
|
this.microservice = microservice;
|
@@ -779,10 +838,12 @@ var Microservice = class {
|
|
779
838
|
lease;
|
780
839
|
scheduler;
|
781
840
|
abortController;
|
782
|
-
isShuttingDown = false;
|
783
841
|
statisticsTimer;
|
784
842
|
wsHandler;
|
785
843
|
actionHandlers = /* @__PURE__ */ new Map();
|
844
|
+
pageHandlers = /* @__PURE__ */ new Map();
|
845
|
+
activeRequests = /* @__PURE__ */ new Map();
|
846
|
+
status = "running";
|
786
847
|
modules = /* @__PURE__ */ new Map();
|
787
848
|
fetch;
|
788
849
|
options;
|
@@ -790,6 +851,7 @@ var Microservice = class {
|
|
790
851
|
serviceId;
|
791
852
|
constructor(options) {
|
792
853
|
this.app = new hono.Hono();
|
854
|
+
this.app.use(timing.timing());
|
793
855
|
this.nodeWebSocket = nodeWs.createNodeWebSocket({ app: this.app });
|
794
856
|
this.serviceId = crypto.randomUUID();
|
795
857
|
this.options = {
|
@@ -805,6 +867,10 @@ var Microservice = class {
|
|
805
867
|
websocket: { enabled: false },
|
806
868
|
cacheAdapter: new MemoryCacheAdapter(),
|
807
869
|
plugins: [],
|
870
|
+
gracefulShutdown: {
|
871
|
+
timeout: 3e4,
|
872
|
+
cleanupHooks: []
|
873
|
+
},
|
808
874
|
...options
|
809
875
|
};
|
810
876
|
this.cache = this.options.cacheAdapter;
|
@@ -824,6 +890,11 @@ var Microservice = class {
|
|
824
890
|
}
|
825
891
|
await this.registerService(true);
|
826
892
|
await this.initPlugins();
|
893
|
+
this.app.get(this.options.prefix, (ctx) => {
|
894
|
+
const name = this.options.name ?? "Microservice";
|
895
|
+
const version = this.options.version ?? "1.0.0";
|
896
|
+
return ctx.text(`${name} is ${this.status}. version: ${version}`);
|
897
|
+
});
|
827
898
|
}
|
828
899
|
async initModules() {
|
829
900
|
for (const ModuleClass of this.options.modules) {
|
@@ -838,6 +909,7 @@ var Microservice = class {
|
|
838
909
|
logger_default.info(`[ \u6CE8\u518C\u6A21\u5757 ] ${moduleName} ${metadata.options.description}`);
|
839
910
|
this.modules.set(moduleName, moduleInstance);
|
840
911
|
const actions = getActionMetadata(ModuleClass.prototype);
|
912
|
+
const pages = getPageMetadata(ModuleClass.prototype);
|
841
913
|
for (const [actionName, actionMetadata] of Object.entries(actions)) {
|
842
914
|
const handler = new ActionHandler(
|
843
915
|
moduleInstance,
|
@@ -851,6 +923,18 @@ var Microservice = class {
|
|
851
923
|
`[ \u6CE8\u518C\u52A8\u4F5C ] ${moduleName}.${actionName} ${actionMetadata.description} ${actionMetadata.mcp ? "MCP:" + actionMetadata.mcp?.type : ""}`
|
852
924
|
);
|
853
925
|
}
|
926
|
+
for (const [_, page] of Object.entries(pages)) {
|
927
|
+
const handler = new PageHandler(
|
928
|
+
moduleInstance,
|
929
|
+
page,
|
930
|
+
moduleName
|
931
|
+
);
|
932
|
+
this.pageHandlers.set(`${moduleName}.${page.name}`, handler);
|
933
|
+
this.app[page.method](`${this.options.prefix}${page.path}`, (ctx) => handler.handle(ctx));
|
934
|
+
logger_default.info(
|
935
|
+
`[ \u6CE8\u518C\u9875\u9762 ] ${moduleName}.${page.name} ${page.method.toUpperCase()} ${page.path} ${page.description}`
|
936
|
+
);
|
937
|
+
}
|
854
938
|
const schedules = getScheduleMetadata(ModuleClass.prototype);
|
855
939
|
if (schedules && Object.keys(schedules).length > 0) {
|
856
940
|
if (!this.scheduler && this.etcdClient) {
|
@@ -880,11 +964,6 @@ var Microservice = class {
|
|
880
964
|
initRoutes() {
|
881
965
|
const startTime = Date.now();
|
882
966
|
const prefix = this.options.prefix || "/api";
|
883
|
-
this.app.get(prefix, (ctx) => {
|
884
|
-
const name = this.options.name ?? "Microservice";
|
885
|
-
const version = this.options.version ?? "1.0.0";
|
886
|
-
return ctx.text(`${name} is running. version: ${version}`);
|
887
|
-
});
|
888
967
|
this.app.get(`${prefix}/health`, (ctx) => {
|
889
968
|
return ctx.json({
|
890
969
|
status: "ok",
|
@@ -899,7 +978,9 @@ var Microservice = class {
|
|
899
978
|
version: this.options.version,
|
900
979
|
env: this.options.env,
|
901
980
|
modules: this.getModules(),
|
902
|
-
stats: Object.fromEntries(this.statsMap)
|
981
|
+
stats: Object.fromEntries(this.statsMap),
|
982
|
+
activeRequests: this.getActiveRequestCount(),
|
983
|
+
status: this.status
|
903
984
|
});
|
904
985
|
});
|
905
986
|
this.app.get(`${prefix}/client.ts`, async (ctx) => {
|
@@ -1096,7 +1177,12 @@ var Microservice = class {
|
|
1096
1177
|
process.on("SIGINT", () => {
|
1097
1178
|
logger_default.info(`
|
1098
1179
|
Received SIGINT signal`);
|
1099
|
-
this.
|
1180
|
+
this.shutdown();
|
1181
|
+
});
|
1182
|
+
process.on("SIGTERM", () => {
|
1183
|
+
logger_default.info(`
|
1184
|
+
Received SIGTERM signal`);
|
1185
|
+
this.shutdown();
|
1100
1186
|
});
|
1101
1187
|
process.on("unhandledrejection", (event) => {
|
1102
1188
|
logger_default.error("Unhandled rejection:", event.reason);
|
@@ -1108,14 +1194,16 @@ Received SIGINT signal`);
|
|
1108
1194
|
/**
|
1109
1195
|
* 优雅停机
|
1110
1196
|
*/
|
1111
|
-
async
|
1112
|
-
if (this.
|
1113
|
-
this.
|
1114
|
-
logger_default.info("\
|
1197
|
+
async shutdown() {
|
1198
|
+
if (this.status === "shutting_down") return;
|
1199
|
+
this.status = "shutting_down";
|
1200
|
+
logger_default.info("\nshutdown initiated...");
|
1115
1201
|
if (this.statisticsTimer) clearInterval(this.statisticsTimer);
|
1116
1202
|
try {
|
1203
|
+
await this.waitForActiveRequests();
|
1204
|
+
await this.executeCleanupHooks();
|
1117
1205
|
await this.stop();
|
1118
|
-
logger_default.info("
|
1206
|
+
logger_default.info("shutdown completed");
|
1119
1207
|
} catch (error) {
|
1120
1208
|
logger_default.error("Error during shutdown:", error);
|
1121
1209
|
process.exit(1);
|
@@ -1123,6 +1211,57 @@ Received SIGINT signal`);
|
|
1123
1211
|
process.exit(0);
|
1124
1212
|
}
|
1125
1213
|
}
|
1214
|
+
/**
|
1215
|
+
* 等待所有活跃请求完成
|
1216
|
+
*/
|
1217
|
+
async waitForActiveRequests() {
|
1218
|
+
const timeout = this.options.gracefulShutdown?.timeout || 3e4;
|
1219
|
+
const startTime = Date.now();
|
1220
|
+
logger_default.info(`Waiting for ${this.activeRequests.size} active requests to complete...`);
|
1221
|
+
return new Promise((resolve) => {
|
1222
|
+
const checkInterval = setInterval(() => {
|
1223
|
+
const elapsed = Date.now() - startTime;
|
1224
|
+
if (this.activeRequests.size === 0) {
|
1225
|
+
clearInterval(checkInterval);
|
1226
|
+
logger_default.info("All active requests completed");
|
1227
|
+
resolve();
|
1228
|
+
} else if (elapsed >= timeout) {
|
1229
|
+
clearInterval(checkInterval);
|
1230
|
+
logger_default.warn(`Timeout waiting for requests to complete. ${this.activeRequests.size} requests still active`);
|
1231
|
+
resolve();
|
1232
|
+
} else {
|
1233
|
+
logger_default.info(`Still waiting for ${this.activeRequests.size} requests... (${elapsed}ms elapsed)`);
|
1234
|
+
}
|
1235
|
+
}, 1e3);
|
1236
|
+
});
|
1237
|
+
}
|
1238
|
+
/**
|
1239
|
+
* 执行清理hook
|
1240
|
+
*/
|
1241
|
+
async executeCleanupHooks() {
|
1242
|
+
const hooks = this.options.gracefulShutdown?.cleanupHooks || [];
|
1243
|
+
if (hooks.length === 0) {
|
1244
|
+
logger_default.info("No cleanup hooks configured");
|
1245
|
+
return;
|
1246
|
+
}
|
1247
|
+
logger_default.info(`Executing ${hooks.length} cleanup hooks...`);
|
1248
|
+
for (const hook of hooks) {
|
1249
|
+
try {
|
1250
|
+
const timeout = hook.timeout || 5e3;
|
1251
|
+
logger_default.info(`Executing cleanup hook: ${hook.name}`);
|
1252
|
+
await Promise.race([
|
1253
|
+
Promise.resolve(hook.cleanup()),
|
1254
|
+
new Promise(
|
1255
|
+
(_, reject) => setTimeout(() => reject(new Error(`Cleanup hook ${hook.name} timeout`)), timeout)
|
1256
|
+
)
|
1257
|
+
]);
|
1258
|
+
logger_default.info(`Cleanup hook ${hook.name} completed successfully`);
|
1259
|
+
} catch (error) {
|
1260
|
+
logger_default.error(`Cleanup hook ${hook.name} failed:`, error);
|
1261
|
+
}
|
1262
|
+
}
|
1263
|
+
logger_default.info("All cleanup hooks completed");
|
1264
|
+
}
|
1126
1265
|
initStatsEventManager() {
|
1127
1266
|
this.statisticsTimer = setInterval(async () => {
|
1128
1267
|
await this.updateStats();
|
@@ -1164,14 +1303,54 @@ Received SIGINT signal`);
|
|
1164
1303
|
}
|
1165
1304
|
return handler;
|
1166
1305
|
}
|
1306
|
+
/**
|
1307
|
+
* 添加活跃请求跟踪
|
1308
|
+
*/
|
1309
|
+
addActiveRequest(requestId, requestInfo) {
|
1310
|
+
this.activeRequests.set(requestId, requestInfo);
|
1311
|
+
}
|
1312
|
+
/**
|
1313
|
+
* 移除活跃请求跟踪
|
1314
|
+
*/
|
1315
|
+
removeActiveRequest(requestId) {
|
1316
|
+
this.activeRequests.delete(requestId);
|
1317
|
+
}
|
1318
|
+
/**
|
1319
|
+
* 获取当前活跃请求数量
|
1320
|
+
*/
|
1321
|
+
getActiveRequestCount() {
|
1322
|
+
return this.activeRequests.size;
|
1323
|
+
}
|
1324
|
+
/**
|
1325
|
+
* 获取当前活跃请求信息
|
1326
|
+
*/
|
1327
|
+
getActiveRequests() {
|
1328
|
+
return Array.from(this.activeRequests.values());
|
1329
|
+
}
|
1167
1330
|
handleRequest = async (ctx) => {
|
1168
1331
|
const { moduleName, actionName } = ctx.req.param();
|
1169
1332
|
const handler = this.getActionHandler(moduleName, actionName);
|
1333
|
+
const requestId = crypto.randomUUID();
|
1334
|
+
const startTime = Date.now();
|
1335
|
+
if (this.status === "shutting_down") {
|
1336
|
+
return ctx.json({
|
1337
|
+
success: false,
|
1338
|
+
error: "Service is shutting down"
|
1339
|
+
}, 503);
|
1340
|
+
}
|
1170
1341
|
try {
|
1171
1342
|
const paramsText = await ctx.req.text();
|
1343
|
+
this.addActiveRequest(requestId, {
|
1344
|
+
id: requestId,
|
1345
|
+
moduleName,
|
1346
|
+
actionName,
|
1347
|
+
startTime,
|
1348
|
+
params: paramsText
|
1349
|
+
});
|
1172
1350
|
const result = await handler.handle(paramsText);
|
1173
1351
|
if (handler.metadata.stream) {
|
1174
1352
|
const encoder = new TextEncoder();
|
1353
|
+
const microservice = this;
|
1175
1354
|
const stream = new ReadableStream({
|
1176
1355
|
async start(controller) {
|
1177
1356
|
try {
|
@@ -1195,6 +1374,8 @@ Received SIGINT signal`);
|
|
1195
1374
|
encoder.encode(ejson4__default.default.stringify(response) + "\n")
|
1196
1375
|
);
|
1197
1376
|
controller.close();
|
1377
|
+
} finally {
|
1378
|
+
microservice.removeActiveRequest(requestId);
|
1198
1379
|
}
|
1199
1380
|
}
|
1200
1381
|
});
|
@@ -1206,8 +1387,10 @@ Received SIGINT signal`);
|
|
1206
1387
|
}
|
1207
1388
|
});
|
1208
1389
|
}
|
1390
|
+
this.removeActiveRequest(requestId);
|
1209
1391
|
return ctx.text(ejson4__default.default.stringify({ success: true, data: result }));
|
1210
1392
|
} catch (error) {
|
1393
|
+
this.removeActiveRequest(requestId);
|
1211
1394
|
return ctx.json({ success: false, error: error.message });
|
1212
1395
|
}
|
1213
1396
|
};
|
@@ -1223,28 +1406,6 @@ Received SIGINT signal`);
|
|
1223
1406
|
await this.waitingInitialization;
|
1224
1407
|
}
|
1225
1408
|
};
|
1226
|
-
|
1227
|
-
// utils/checker.ts
|
1228
|
-
async function startCheck(checkers, pass) {
|
1229
|
-
logger_default.info("[ \u9884\u68C0\u5F00\u59CB ]");
|
1230
|
-
for (const [index, checker] of checkers.entries()) {
|
1231
|
-
const seq = index + 1;
|
1232
|
-
logger_default.info(`${seq}. ${checker.name}`);
|
1233
|
-
try {
|
1234
|
-
if (checker.skip) {
|
1235
|
-
logger_default.warn(`${seq}. ${checker.name} [\u8DF3\u8FC7]`);
|
1236
|
-
continue;
|
1237
|
-
}
|
1238
|
-
await checker.check();
|
1239
|
-
logger_default.info(`${seq}. ${checker.name} [\u6210\u529F]`);
|
1240
|
-
} catch (error) {
|
1241
|
-
logger_default.error(`${seq}. ${checker.name} [\u5931\u8D25]`);
|
1242
|
-
throw error;
|
1243
|
-
}
|
1244
|
-
}
|
1245
|
-
logger_default.info("[ \u9884\u68C0\u5B8C\u6210 ]");
|
1246
|
-
if (pass) await pass();
|
1247
|
-
}
|
1248
1409
|
var HonoTransport = class {
|
1249
1410
|
constructor(url, stream, closeStream) {
|
1250
1411
|
this.url = url;
|
@@ -1360,22 +1521,221 @@ var ModelContextProtocolPlugin = class extends Plugin {
|
|
1360
1521
|
);
|
1361
1522
|
};
|
1362
1523
|
};
|
1524
|
+
var DEFAULT_FAVICON = /* @__PURE__ */ jsxRuntime.jsx(
|
1525
|
+
"link",
|
1526
|
+
{
|
1527
|
+
rel: "icon",
|
1528
|
+
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>",
|
1529
|
+
type: "image/svg+xml"
|
1530
|
+
}
|
1531
|
+
);
|
1532
|
+
var BaseLayout = (props = {
|
1533
|
+
title: "Microservice Template"
|
1534
|
+
}) => html.html`<!DOCTYPE html>
|
1535
|
+
<html>
|
1536
|
+
<head>
|
1537
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
1538
|
+
<title>${props.title}</title>
|
1539
|
+
${props.heads}
|
1540
|
+
</head>
|
1541
|
+
<body>
|
1542
|
+
${props.children}
|
1543
|
+
</body>
|
1544
|
+
</html>`;
|
1545
|
+
var HtmxLayout = (props = {
|
1546
|
+
title: "Microservice Template"
|
1547
|
+
}) => BaseLayout({
|
1548
|
+
title: props.title,
|
1549
|
+
heads: html.html`
|
1550
|
+
<script src="https://unpkg.com/htmx.org@latest"></script>
|
1551
|
+
<script src="https://unpkg.com/hyperscript.org@latest"></script>
|
1552
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
1553
|
+
${props.favicon || DEFAULT_FAVICON}
|
1554
|
+
`,
|
1555
|
+
children: props.children
|
1556
|
+
});
|
1557
|
+
var InfoCard = ({
|
1558
|
+
icon,
|
1559
|
+
iconColor,
|
1560
|
+
bgColor,
|
1561
|
+
label,
|
1562
|
+
value
|
1563
|
+
}) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${bgColor} p-4 rounded-lg`, children: [
|
1564
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center mb-2", children: [
|
1565
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
1566
|
+
"svg",
|
1567
|
+
{
|
1568
|
+
className: `w-5 h-5 ${iconColor} mr-2`,
|
1569
|
+
fill: "none",
|
1570
|
+
stroke: "currentColor",
|
1571
|
+
viewBox: "0 0 24 24",
|
1572
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
1573
|
+
"path",
|
1574
|
+
{
|
1575
|
+
strokeLinecap: "round",
|
1576
|
+
strokeLinejoin: "round",
|
1577
|
+
strokeWidth: 2,
|
1578
|
+
d: icon
|
1579
|
+
}
|
1580
|
+
)
|
1581
|
+
}
|
1582
|
+
),
|
1583
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-gray-600", children: label })
|
1584
|
+
] }),
|
1585
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-xl font-semibold text-gray-900`, children: value })
|
1586
|
+
] });
|
1587
|
+
var getEnvironmentBadgeClass = (env) => {
|
1588
|
+
switch (env) {
|
1589
|
+
case "prod":
|
1590
|
+
return "bg-red-100 text-red-800";
|
1591
|
+
case "stg":
|
1592
|
+
return "bg-yellow-100 text-yellow-800";
|
1593
|
+
case "dev":
|
1594
|
+
default:
|
1595
|
+
return "bg-blue-100 text-blue-800";
|
1596
|
+
}
|
1597
|
+
};
|
1598
|
+
var ServiceInfoCards = ({
|
1599
|
+
serviceInfo
|
1600
|
+
}) => {
|
1601
|
+
const infoCards = [
|
1602
|
+
{
|
1603
|
+
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",
|
1604
|
+
iconColor: "text-blue-600",
|
1605
|
+
bgColor: "bg-blue-50",
|
1606
|
+
label: "\u670D\u52A1\u540D\u79F0",
|
1607
|
+
value: serviceInfo.name
|
1608
|
+
},
|
1609
|
+
{
|
1610
|
+
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",
|
1611
|
+
iconColor: "text-orange-600",
|
1612
|
+
bgColor: "bg-orange-50",
|
1613
|
+
label: "\u670D\u52A1\u8DEF\u5F84",
|
1614
|
+
value: serviceInfo.prefix || "/",
|
1615
|
+
isMonospace: true
|
1616
|
+
},
|
1617
|
+
{
|
1618
|
+
icon: "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z",
|
1619
|
+
iconColor: "text-green-600",
|
1620
|
+
bgColor: "bg-green-50",
|
1621
|
+
label: "\u8FD0\u884C\u73AF\u5883",
|
1622
|
+
value: /* @__PURE__ */ jsxRuntime.jsx(
|
1623
|
+
"span",
|
1624
|
+
{
|
1625
|
+
className: `px-2 py-1 rounded-full text-sm ${getEnvironmentBadgeClass(serviceInfo.env ?? "dev")}`,
|
1626
|
+
children: serviceInfo.env ?? "dev"
|
1627
|
+
}
|
1628
|
+
)
|
1629
|
+
},
|
1630
|
+
{
|
1631
|
+
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",
|
1632
|
+
iconColor: "text-purple-600",
|
1633
|
+
bgColor: "bg-purple-50",
|
1634
|
+
label: "\u7248\u672C\u53F7",
|
1635
|
+
value: serviceInfo.version || "unknown"
|
1636
|
+
}
|
1637
|
+
];
|
1638
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white rounded-lg shadow-md p-6 mb-8", children: [
|
1639
|
+
/* @__PURE__ */ jsxRuntime.jsxs("h2", { className: "text-2xl font-semibold text-gray-800 mb-6 flex items-center", children: [
|
1640
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
1641
|
+
"svg",
|
1642
|
+
{
|
1643
|
+
className: "w-6 h-6 mr-2 text-blue-600",
|
1644
|
+
fill: "none",
|
1645
|
+
stroke: "currentColor",
|
1646
|
+
viewBox: "0 0 24 24",
|
1647
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
1648
|
+
"path",
|
1649
|
+
{
|
1650
|
+
strokeLinecap: "round",
|
1651
|
+
strokeLinejoin: "round",
|
1652
|
+
strokeWidth: 2,
|
1653
|
+
d: "M13 10V3L4 14h7v7l9-11h-7z"
|
1654
|
+
}
|
1655
|
+
)
|
1656
|
+
}
|
1657
|
+
),
|
1658
|
+
"\u670D\u52A1\u57FA\u672C\u4FE1\u606F"
|
1659
|
+
] }),
|
1660
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-6", children: infoCards.map((card, index) => /* @__PURE__ */ jsxRuntime.jsx(InfoCard, { ...card }, index)) })
|
1661
|
+
] });
|
1662
|
+
};
|
1663
|
+
var ServiceStatusPage = ({
|
1664
|
+
serviceInfo
|
1665
|
+
}) => {
|
1666
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-screen bg-gray-50 py-8", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-6xl mx-auto px-4", children: [
|
1667
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-8", children: /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-4xl font-bold text-gray-900 mb-2", children: "Service Status" }) }),
|
1668
|
+
/* @__PURE__ */ jsxRuntime.jsx(ServiceInfoCards, { serviceInfo })
|
1669
|
+
] }) });
|
1670
|
+
};
|
1671
|
+
var ServiceStatusPage_default = ServiceStatusPage;
|
1672
|
+
|
1673
|
+
// core/plugins/page/mod.ts
|
1674
|
+
var PageRenderPlugin = class extends Plugin {
|
1675
|
+
initialize = async (engine) => {
|
1676
|
+
const app = engine.getApp();
|
1677
|
+
app.get(`${engine.options.prefix}`, async (ctx) => {
|
1678
|
+
return ctx.html(HtmxLayout({
|
1679
|
+
title: engine.options.name,
|
1680
|
+
children: ServiceStatusPage_default({
|
1681
|
+
serviceInfo: {
|
1682
|
+
name: engine.options.name,
|
1683
|
+
prefix: engine.options.prefix,
|
1684
|
+
version: engine.options.version,
|
1685
|
+
env: engine.options.env,
|
1686
|
+
id: engine.serviceId,
|
1687
|
+
modules: engine.getModules(false)
|
1688
|
+
}
|
1689
|
+
})
|
1690
|
+
}));
|
1691
|
+
});
|
1692
|
+
logger_default.info(`PageRenderPlugin enabled`);
|
1693
|
+
};
|
1694
|
+
};
|
1695
|
+
|
1696
|
+
// utils/checker.ts
|
1697
|
+
async function startCheck(checkers, pass) {
|
1698
|
+
logger_default.info("[ \u9884\u68C0\u5F00\u59CB ]");
|
1699
|
+
for (const [index, checker] of checkers.entries()) {
|
1700
|
+
const seq = index + 1;
|
1701
|
+
logger_default.info(`${seq}. ${checker.name}`);
|
1702
|
+
try {
|
1703
|
+
if (checker.skip) {
|
1704
|
+
logger_default.warn(`${seq}. ${checker.name} [\u8DF3\u8FC7]`);
|
1705
|
+
continue;
|
1706
|
+
}
|
1707
|
+
await checker.check();
|
1708
|
+
logger_default.info(`${seq}. ${checker.name} [\u6210\u529F]`);
|
1709
|
+
} catch (error) {
|
1710
|
+
logger_default.error(`${seq}. ${checker.name} [\u5931\u8D25]`);
|
1711
|
+
throw error;
|
1712
|
+
}
|
1713
|
+
}
|
1714
|
+
logger_default.info("[ \u9884\u68C0\u5B8C\u6210 ]");
|
1715
|
+
if (pass) await pass();
|
1716
|
+
}
|
1363
1717
|
|
1364
1718
|
Object.defineProperty(exports, "dayjs", {
|
1365
1719
|
enumerable: true,
|
1366
1720
|
get: function () { return dayjs__default.default; }
|
1367
1721
|
});
|
1368
1722
|
exports.Action = Action;
|
1723
|
+
exports.BaseLayout = BaseLayout;
|
1369
1724
|
exports.CacheAdapter = CacheAdapter;
|
1725
|
+
exports.HtmxLayout = HtmxLayout;
|
1370
1726
|
exports.MemoryCacheAdapter = MemoryCacheAdapter;
|
1371
1727
|
exports.Microservice = Microservice;
|
1372
1728
|
exports.ModelContextProtocolPlugin = ModelContextProtocolPlugin;
|
1373
1729
|
exports.Module = Module;
|
1730
|
+
exports.Page = Page;
|
1731
|
+
exports.PageRenderPlugin = PageRenderPlugin;
|
1374
1732
|
exports.Plugin = Plugin;
|
1375
1733
|
exports.RedisCacheAdapter = RedisCacheAdapter;
|
1376
1734
|
exports.Schedule = Schedule;
|
1377
1735
|
exports.ScheduleMode = ScheduleMode;
|
1378
1736
|
exports.ServiceContext = ServiceContext;
|
1737
|
+
exports.ServiceInfoCards = ServiceInfoCards;
|
1738
|
+
exports.ServiceStatusPage = ServiceStatusPage;
|
1379
1739
|
exports.logger = logger_default;
|
1380
1740
|
exports.startCheck = startCheck;
|
1381
1741
|
Object.keys(zod).forEach(function (k) {
|