typespeed 2.6.1 → 2.6.3

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/CHANGELOG.md CHANGED
@@ -4,6 +4,8 @@ typespeed 版本演进记录。本文件 2026-09-06 从 git 历史反推建立
4
4
 
5
5
  ## 2.6.x
6
6
 
7
+ - **2.6.3**:框架内建优雅停机——`ExpressServer` 存储 `httpServer` + 新增 `stop()`(Promise 化 graceful close);SIGTERM/SIGINT 优雅停机(close 后 exit 0,30s 兜底强制退出),停机时关闭 Redis;socket 模式一并处理(2026-09-07)
8
+ - **2.6.2**:框架内建健康检查——新增 `HealthFactory`(abstract `ready()`)+ `HealthDefault`(默认恒就绪);`ExpressServer` 内建 `GET /health`(liveness)与 `GET /ready`(readiness,读 HealthFactory,200/503),路径可经 config 覆盖(2026-09-07)
7
9
  - **2.6.1**:Node/TS 升级——TypeScript 4.9 → 5.9.3(legacy 装饰器零改动兼容,标准装饰器双轨同步验证);`@types/node` 对齐 22;声明 `engines`(node >=18)(2026-09-07)
8
10
 
9
11
  ## 2.5.x
@@ -22,9 +22,14 @@ const route_decorator_1 = require("../route.decorator");
22
22
  const socket_io_class_1 = require("../default/socket-io.class");
23
23
  const typespeed_1 = require("../typespeed");
24
24
  const core_decorator_1 = require("../core.decorator");
25
+ const health_factory_class_1 = require("../factory/health-factory.class");
25
26
  const redis_class_1 = require("./redis.class");
26
27
  const authentication_factory_class_1 = require("../factory/authentication-factory.class");
27
28
  class ExpressServer extends server_factory_class_1.default {
29
+ constructor() {
30
+ super(...arguments);
31
+ this.httpServer = null;
32
+ }
28
33
  getSever() {
29
34
  const server = new ExpressServer();
30
35
  server.app = express();
@@ -38,13 +43,46 @@ class ExpressServer extends server_factory_class_1.default {
38
43
  this.app.use(middleware);
39
44
  });
40
45
  this.setDefaultMiddleware();
46
+ let server;
41
47
  if (this.socketIoConfig) {
42
48
  const newSocketApp = socket_io_class_1.SocketIo.setIoServer(this.app, this.socketIoConfig);
43
- return newSocketApp.listen(port);
49
+ server = newSocketApp.listen(port);
44
50
  }
45
51
  else {
46
- return this.app.listen(port);
52
+ server = this.app.listen(port);
47
53
  }
54
+ this.httpServer = server;
55
+ this.registerGracefulShutdown();
56
+ return server;
57
+ }
58
+ stop() {
59
+ return new Promise((resolve) => {
60
+ if (this.httpServer) {
61
+ this.httpServer.close(() => resolve());
62
+ }
63
+ else {
64
+ resolve();
65
+ }
66
+ });
67
+ }
68
+ registerGracefulShutdown() {
69
+ const shutdown = (signal) => {
70
+ (0, core_decorator_1.log)(`received ${signal}, gracefully shutting down...`);
71
+ // 30 秒兜底强制退出,防止连接迟迟不关闭
72
+ const forceExit = setTimeout(() => {
73
+ (0, core_decorator_1.log)("forced shutdown after timeout");
74
+ process.exit(1);
75
+ }, 30000);
76
+ forceExit.unref();
77
+ redis_class_1.Redis.close().catch(() => { });
78
+ this.httpServer.close(() => {
79
+ clearTimeout(forceExit);
80
+ (0, core_decorator_1.log)("server closed");
81
+ process.exit(0);
82
+ });
83
+ };
84
+ process.on("SIGTERM", () => shutdown("SIGTERM"));
85
+ process.on("SIGINT", () => shutdown("SIGINT"));
48
86
  }
49
87
  setDefaultMiddleware() {
50
88
  this.app.use(express.urlencoded({ extended: true }));
@@ -83,6 +121,23 @@ class ExpressServer extends server_factory_class_1.default {
83
121
  }
84
122
  (0, route_decorator_1.setRouter)(this.app);
85
123
  this.app.use(this.authentication.afterCompletion);
124
+ // 健康检查(k8s liveness / readiness 探针)
125
+ const healthConfig = (0, typespeed_1.config)("health") || {};
126
+ const livenessPath = healthConfig["liveness"] || "/health";
127
+ const readinessPath = healthConfig["readiness"] || "/ready";
128
+ this.app.get(livenessPath, (req, res) => {
129
+ res.status(200).json({ status: "up" });
130
+ });
131
+ this.app.get(readinessPath, (req, res) => {
132
+ let ready = true;
133
+ try {
134
+ ready = (0, core_decorator_1.getBean)(health_factory_class_1.default).ready();
135
+ }
136
+ catch (e) {
137
+ ready = false;
138
+ }
139
+ res.status(ready ? 200 : 503).json({ status: ready ? "ready" : "not-ready" });
140
+ });
86
141
  const errorPageDir = __dirname + "/pages";
87
142
  this.app.use((req, res) => {
88
143
  (0, core_decorator_1.error)("404 not found, for page: " + req.url);
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const core_decorator_1 = require("../core.decorator");
13
+ const health_factory_class_1 = require("../factory/health-factory.class");
14
+ /**
15
+ * 健康检查默认实现:恒为就绪。
16
+ * 应用继承 HealthFactory 并用 @bean 注册自定义实现,即可覆盖默认行为(如接入数据库/Redis 连通性检查)。
17
+ */
18
+ class HealthDefault extends health_factory_class_1.default {
19
+ createHealth() {
20
+ return new HealthDefault();
21
+ }
22
+ ready() {
23
+ return true;
24
+ }
25
+ }
26
+ exports.default = HealthDefault;
27
+ __decorate([
28
+ core_decorator_1.bean,
29
+ __metadata("design:type", Function),
30
+ __metadata("design:paramtypes", []),
31
+ __metadata("design:returntype", health_factory_class_1.default)
32
+ ], HealthDefault.prototype, "createHealth", null);
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * 健康检查工厂(抽象)。
5
+ * 实现 ready() 自定义「就绪检查」(readiness)——如检查数据库/Redis/MQ 连通性。
6
+ * 应用继承此类并用 @bean 注册自定义实现;默认实现见 HealthDefault(恒就绪)。
7
+ */
8
+ class HealthFactory {
9
+ }
10
+ exports.default = HealthFactory;
@@ -280,6 +280,14 @@ declare abstract class AuthenticationFactory {
280
280
  */
281
281
  afterCompletion(req: express.Request, res: express.Response, next: express.NextFunction): void;
282
282
  }
283
+ /**健康检查工厂类,实现 ready() 自定义就绪检查(readiness) */
284
+ declare abstract class HealthFactory {
285
+ abstract ready(): boolean;
286
+ }
287
+ /**健康检查默认实现类,默认恒为就绪 */
288
+ declare class HealthDefault extends HealthFactory {
289
+ ready(): boolean;
290
+ }
283
291
  /**Redis 操作类 */
284
292
  declare class Redis extends IoRedis {
285
293
  /**获取 Redis 实例 */
@@ -380,6 +388,10 @@ declare class ExpressServer extends ServerFactory {
380
388
  getSever(): ServerFactory;
381
389
  setMiddleware(middleware: any): void;
382
390
  start(port: number): void;
391
+ /**HTTP 服务实例(start 后可用) */
392
+ httpServer: any;
393
+ /**优雅停机:关闭 HTTP 服务(排空在途连接) */
394
+ stop(): Promise<void>;
383
395
  private setDefaultMiddleware;
384
396
  }
385
397
  /**Socket IO 装饰器类 */
@@ -400,4 +412,4 @@ declare class SocketIo {
400
412
  /**Socket IO 服务实现类 */
401
413
  declare const io: IoServer;
402
414
 
403
- export { ExpressServer, LogDefault, NodeCache, RabbitMQ, rabbitListener, redisSubscriber, ReadWriteDb, Redis, CacheFactory, DataSourceFactory, LogFactory, ServerFactory, AuthenticationFactory, next, reqBody, reqQuery, reqForm, reqParam, req, req as request, res, res as response, component, bean, resource, log, logx, app, before, after, value, error, config, autoware, getBean, getComponent, schedule, getMapping, postMapping, requestMapping, setRouter, upload, jwt, insert, update, remove, select, param, bind, resultType, cache, Model, SocketIo, io };
415
+ export { ExpressServer, LogDefault, NodeCache, RabbitMQ, rabbitListener, redisSubscriber, ReadWriteDb, Redis, CacheFactory, DataSourceFactory, LogFactory, ServerFactory, AuthenticationFactory, HealthFactory, HealthDefault, next, reqBody, reqQuery, reqForm, reqParam, req, req as request, res, res as response, component, bean, resource, log, logx, app, before, after, value, error, config, autoware, getBean, getComponent, schedule, getMapping, postMapping, requestMapping, setRouter, upload, jwt, insert, update, remove, select, param, bind, resultType, cache, Model, SocketIo, io };
package/dist/typespeed.js CHANGED
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.ReadWriteDb = exports.redisSubscriber = exports.Redis = exports.NodeCache = exports.LogDefault = exports.ExpressServer = exports.AuthenticationFactory = exports.ServerFactory = exports.DataSourceFactory = exports.CacheFactory = exports.LogFactory = void 0;
17
+ exports.ReadWriteDb = exports.redisSubscriber = exports.Redis = exports.NodeCache = exports.HealthDefault = exports.LogDefault = exports.ExpressServer = exports.HealthFactory = exports.AuthenticationFactory = exports.ServerFactory = exports.DataSourceFactory = exports.CacheFactory = exports.LogFactory = void 0;
18
18
  exports.app = app;
19
19
  exports.value = value;
20
20
  exports.config = config;
@@ -145,10 +145,14 @@ var server_factory_class_1 = require("./factory/server-factory.class");
145
145
  Object.defineProperty(exports, "ServerFactory", { enumerable: true, get: function () { return server_factory_class_1.default; } });
146
146
  var authentication_factory_class_1 = require("./factory/authentication-factory.class");
147
147
  Object.defineProperty(exports, "AuthenticationFactory", { enumerable: true, get: function () { return authentication_factory_class_1.default; } });
148
+ var health_factory_class_1 = require("./factory/health-factory.class");
149
+ Object.defineProperty(exports, "HealthFactory", { enumerable: true, get: function () { return health_factory_class_1.default; } });
148
150
  var express_server_class_1 = require("./default/express-server.class");
149
151
  Object.defineProperty(exports, "ExpressServer", { enumerable: true, get: function () { return express_server_class_1.default; } });
150
152
  var log_default_class_1 = require("./default/log-default.class");
151
153
  Object.defineProperty(exports, "LogDefault", { enumerable: true, get: function () { return log_default_class_1.default; } });
154
+ var health_default_class_1 = require("./default/health-default.class");
155
+ Object.defineProperty(exports, "HealthDefault", { enumerable: true, get: function () { return health_default_class_1.default; } });
152
156
  var node_cache_class_1 = require("./default/node-cache.class");
153
157
  Object.defineProperty(exports, "NodeCache", { enumerable: true, get: function () { return node_cache_class_1.default; } });
154
158
  var redis_class_1 = require("./default/redis.class");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typespeed",
3
- "version": "2.6.1",
3
+ "version": "2.6.3",
4
4
  "description": "A new Framework for TypeScript.",
5
5
  "author": "speedphp",
6
6
  "license": "MIT License",