@catbee/utils 2.0.4 → 2.1.1

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/server/index.cjs CHANGED
@@ -25,6 +25,7 @@
25
25
  'use strict';
26
26
 
27
27
  var express = require('express');
28
+ var http = require('http');
28
29
  var https = require('https');
29
30
  var httpStatusCodes = require('@catbee/utils/http-status-codes');
30
31
  var response = require('@catbee/utils/response');
@@ -42,6 +43,7 @@ var id = require('@catbee/utils/id');
42
43
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
43
44
 
44
45
  var express__default = /*#__PURE__*/_interopDefault(express);
46
+ var http__default = /*#__PURE__*/_interopDefault(http);
45
47
  var https__default = /*#__PURE__*/_interopDefault(https);
46
48
 
47
49
  var __defProp = Object.defineProperty;
@@ -689,6 +691,15 @@ var DependencyErrors = {
689
691
  "cookie-parser": getDependencyErrorMessage("cookie-parser"),
690
692
  "@scalar/express-api-reference": getDependencyErrorMessage("@scalar/express-api-reference")
691
693
  };
694
+ var SUPPORTED_HTTP_METHODS = /* @__PURE__ */ new Set([
695
+ "get",
696
+ "post",
697
+ "put",
698
+ "delete",
699
+ "patch",
700
+ "options",
701
+ "head"
702
+ ]);
692
703
  var ExpressServer = class {
693
704
  static {
694
705
  __name(this, "ExpressServer");
@@ -701,11 +712,11 @@ var ExpressServer = class {
701
712
  hooks;
702
713
  /** Global API prefix (from config) */
703
714
  globalPrefix;
704
- /** Internal fallback router */
715
+ /** Primary root router mounted to the application */
705
716
  rootRouter;
706
- /** User-supplied router */
707
- externalRouter;
708
- /** Internal Express app instance */
717
+ /** Set of registered sub-routers to prevent duplicate mounting */
718
+ mountedRouters = /* @__PURE__ */ new Set();
719
+ /** Express app instance */
709
720
  app;
710
721
  /** Set of active WebSocket connections */
711
722
  connections = /* @__PURE__ */ new Set();
@@ -713,6 +724,8 @@ var ExpressServer = class {
713
724
  isShuttingDown = false;
714
725
  /** Flag indicating if graceful shutdown handlers are registered */
715
726
  gracefulShutdownRegistered = false;
727
+ /** Map of registered signal listeners for clean teardown */
728
+ signalListeners = /* @__PURE__ */ new Map();
716
729
  /**
717
730
  * Collection of registered health check functions.
718
731
  * These are executed when the health check endpoint is accessed.
@@ -720,6 +733,8 @@ var ExpressServer = class {
720
733
  healthChecks = [];
721
734
  /** Promise that resolves when initialization (middleware + routes) is complete */
722
735
  initPromise;
736
+ /** In-flight start promise to protect against concurrent start() calls */
737
+ startPromise;
723
738
  /**
724
739
  * Initializes server with intelligent defaults and security best practices.
725
740
  * All settings can be customized via config and hooks.
@@ -822,6 +837,7 @@ var ExpressServer = class {
822
837
  this.setupBodyParsingMiddleware();
823
838
  this.setupCookieParsingMiddleware();
824
839
  await this.setupOpenApiMiddleware();
840
+ this.setupResponseHook();
825
841
  }
826
842
  /**
827
843
  * Set up basic middleware (trust proxy, request ID, context).
@@ -876,10 +892,15 @@ var ExpressServer = class {
876
892
  * Set up global headers middleware.
877
893
  */
878
894
  setupGlobalHeaders() {
895
+ const hasCustomHeaders = Boolean(this.config.globalHeaders && Object.keys(this.config.globalHeaders).length > 0);
896
+ const isMicroservice = Boolean(this.config.isMicroservice);
897
+ const hasServiceVersion = Boolean(this.config.serviceVersion?.enable);
898
+ if (!hasCustomHeaders && !isMicroservice && !hasServiceVersion) {
899
+ return;
900
+ }
879
901
  this.app.use((_req, res, next) => {
880
902
  if (this.config.globalHeaders) {
881
- for (const key in this.config.globalHeaders) {
882
- const value = this.config.globalHeaders[key];
903
+ for (const [key, value] of Object.entries(this.config.globalHeaders)) {
883
904
  res.setHeader(key, typeof value === "function" ? value() : value);
884
905
  }
885
906
  }
@@ -1074,6 +1095,11 @@ var ExpressServer = class {
1074
1095
  }, "Failed to mount OpenAPI docs");
1075
1096
  }
1076
1097
  }
1098
+ }
1099
+ /**
1100
+ * Set up response preprocessing hook (applies global prefix if set).
1101
+ */
1102
+ setupResponseHook() {
1077
1103
  if (this.hooks.onResponse) {
1078
1104
  this.app.use(this.globalPrefix, this.hooks.onResponse);
1079
1105
  }
@@ -1092,8 +1118,7 @@ var ExpressServer = class {
1092
1118
  this.app.get(healthCheckPath, async (_req, res) => {
1093
1119
  return this.handleHealthCheckRequest(res);
1094
1120
  });
1095
- const routerToUse = this.externalRouter || this.rootRouter;
1096
- this.app.use(this.globalPrefix, routerToUse);
1121
+ this.app.use(this.globalPrefix, this.rootRouter);
1097
1122
  await this.runHook("afterRoutes", this.app);
1098
1123
  this.app.use((req, res) => {
1099
1124
  const status = httpStatusCodes.HttpStatusCodes.NOT_FOUND;
@@ -1228,11 +1253,15 @@ var ExpressServer = class {
1228
1253
  * Start the HTTP server and begin listening for requests.
1229
1254
  *
1230
1255
  * This method:
1256
+ * - Protects against concurrent start() invocations
1257
+ * - Awaits server initialization (middleware + routes)
1231
1258
  * - Executes beforeStart hooks
1259
+ * - Creates the HTTP/HTTPS server instance
1260
+ * - Sets up error handling and connection tracking BEFORE listening
1261
+ * - Executes onServerCreated hook BEFORE listening
1232
1262
  * - Binds to the configured host/port
1233
- * - Sets up error handling for startup failures
1234
- * - Executes afterStart hooks on success
1235
- * - Logs startup information
1263
+ * - Executes afterStart hooks on successful listen
1264
+ * - Cleans up server reference and listeners on startup failure
1236
1265
  *
1237
1266
  * @returns Promise resolving to the running HTTP server instance
1238
1267
  * @throws Error if server fails to start or port is already in use
@@ -1242,33 +1271,68 @@ var ExpressServer = class {
1242
1271
  logger.getLogger().warn("Server is already running, returning existing instance");
1243
1272
  return this.server;
1244
1273
  }
1274
+ if (this.startPromise) {
1275
+ return this.startPromise;
1276
+ }
1277
+ this.startPromise = this.doStart();
1278
+ try {
1279
+ return await this.startPromise;
1280
+ } finally {
1281
+ this.startPromise = void 0;
1282
+ }
1283
+ }
1284
+ /**
1285
+ * Internal implementation of server startup.
1286
+ */
1287
+ async doStart() {
1245
1288
  await this.initPromise;
1246
1289
  await this.runHook("beforeStart", this.app);
1290
+ const server = this.createServerInstance();
1291
+ this.server = server;
1247
1292
  return new Promise((resolve, reject) => {
1248
- try {
1293
+ let isListening = false;
1294
+ server.on("error", (err) => {
1295
+ if (!isListening) {
1296
+ logger.getLogger().error({
1297
+ err
1298
+ }, "Server failed to start");
1299
+ try {
1300
+ server.removeAllListeners();
1301
+ server.close();
1302
+ } catch {
1303
+ }
1304
+ this.server = null;
1305
+ this.connections.clear();
1306
+ reject(err);
1307
+ } else {
1308
+ logger.getLogger().error({
1309
+ err
1310
+ }, "Server runtime error");
1311
+ }
1312
+ });
1313
+ this.setupConnectionTracking();
1314
+ Promise.resolve(this.runHook("onServerCreated", server)).then(() => {
1249
1315
  const onListening = /* @__PURE__ */ __name(async () => {
1316
+ isListening = true;
1250
1317
  this.logServerStartInfo();
1251
- if (this.server) await this.runHook("afterStart", this.server);
1252
- resolve(this.server);
1318
+ await this.runHook("afterStart", server);
1319
+ resolve(server);
1253
1320
  }, "onListening");
1254
- this.server = this.createServerInstance(onListening);
1255
- this.runHook("onServerCreated", this.server);
1256
- this.setupConnectionTracking();
1257
- this.setupServerErrorHandling(reject);
1258
- } catch (error) {
1259
- reject(error);
1260
- }
1321
+ const listenArgs = [
1322
+ this.config.port,
1323
+ this.config.host,
1324
+ onListening
1325
+ ];
1326
+ server.listen(...listenArgs);
1327
+ }).catch((err) => {
1328
+ server.emit("error", err instanceof Error ? err : new Error(String(err)));
1329
+ });
1261
1330
  });
1262
1331
  }
1263
1332
  /**
1264
- * Create HTTP or HTTPS server instance.
1333
+ * Create HTTP or HTTPS server instance (without listening).
1265
1334
  */
1266
- createServerInstance(onListening) {
1267
- const listenArgs = [
1268
- this.config.port,
1269
- this.config.host,
1270
- onListening
1271
- ];
1335
+ createServerInstance() {
1272
1336
  if (this.config.https) {
1273
1337
  const httpsOptions = {
1274
1338
  ...this.config.https,
@@ -1281,9 +1345,9 @@ var ExpressServer = class {
1281
1345
  if (this.config.https.passphrase) {
1282
1346
  httpsOptions.passphrase = this.config.https.passphrase;
1283
1347
  }
1284
- return https__default.default.createServer(httpsOptions, this.app).listen(...listenArgs);
1348
+ return https__default.default.createServer(httpsOptions, this.app);
1285
1349
  }
1286
- return this.app.listen(...listenArgs);
1350
+ return http__default.default.createServer(this.app);
1287
1351
  }
1288
1352
  /**
1289
1353
  * Set up connection tracking for graceful shutdown.
@@ -1295,17 +1359,6 @@ var ExpressServer = class {
1295
1359
  });
1296
1360
  }
1297
1361
  /**
1298
- * Set up error handling for server startup.
1299
- */
1300
- setupServerErrorHandling(reject) {
1301
- this.server.on("error", (err) => {
1302
- logger.getLogger().error({
1303
- err
1304
- }, "Server failed to start");
1305
- reject(err);
1306
- });
1307
- }
1308
- /**
1309
1362
  * Log server startup information.
1310
1363
  */
1311
1364
  logServerStartInfo() {
@@ -1367,6 +1420,7 @@ var ExpressServer = class {
1367
1420
  afterStopCalled = true;
1368
1421
  await this.runHook("afterStop");
1369
1422
  }, "runAfterStop");
1423
+ server.closeIdleConnections?.();
1370
1424
  const serverClosePromise = new Promise((resolve, reject) => {
1371
1425
  server.close(async (err) => {
1372
1426
  if (timer) clearTimeout(timer);
@@ -1429,7 +1483,7 @@ var ExpressServer = class {
1429
1483
  }
1430
1484
  let signalHandled = false;
1431
1485
  signals.forEach((signal) => {
1432
- process.on(signal, async () => {
1486
+ const handler = /* @__PURE__ */ __name(async () => {
1433
1487
  if (signalHandled) {
1434
1488
  logger.getLogger().warn(`Ignoring duplicate ${signal}`);
1435
1489
  return;
@@ -1437,6 +1491,7 @@ var ExpressServer = class {
1437
1491
  signalHandled = true;
1438
1492
  logger.getLogger().info(`Received ${signal}, initiating graceful shutdown...`);
1439
1493
  try {
1494
+ this.disableGracefulShutdown();
1440
1495
  await this.stop(true);
1441
1496
  process.exit(0);
1442
1497
  } catch (err) {
@@ -1445,12 +1500,29 @@ var ExpressServer = class {
1445
1500
  }, "Shutdown failed");
1446
1501
  process.exit(1);
1447
1502
  }
1448
- });
1503
+ }, "handler");
1504
+ this.signalListeners.set(signal, handler);
1505
+ process.on(signal, handler);
1449
1506
  });
1450
1507
  this.gracefulShutdownRegistered = true;
1451
1508
  return this;
1452
1509
  }
1453
1510
  /**
1511
+ * Unregister graceful shutdown signal listeners.
1512
+ * Useful for testing and dynamic server lifecycles to prevent memory and listener leaks.
1513
+ */
1514
+ disableGracefulShutdown() {
1515
+ if (!this.gracefulShutdownRegistered) {
1516
+ return this;
1517
+ }
1518
+ for (const [signal, handler] of this.signalListeners.entries()) {
1519
+ process.removeListener(signal, handler);
1520
+ }
1521
+ this.signalListeners.clear();
1522
+ this.gracefulShutdownRegistered = false;
1523
+ return this;
1524
+ }
1525
+ /**
1454
1526
  * Destroy all active connections (gracefully if possible).
1455
1527
  * If a connection does not close cleanly, it will be force-destroyed.
1456
1528
  */
@@ -1463,32 +1535,56 @@ var ExpressServer = class {
1463
1535
  ];
1464
1536
  await Promise.allSettled(sockets.map((socket) => new Promise((resolve) => {
1465
1537
  socket.end();
1466
- const timer = setTimeout(() => {
1467
- socket.destroy();
1468
- resolve();
1469
- }, 1e3);
1470
- socket.once("close", () => {
1471
- clearTimeout(timer);
1538
+ let timer;
1539
+ const cleanup = /* @__PURE__ */ __name(() => {
1540
+ if (timer) clearTimeout(timer);
1541
+ socket.removeListener("close", onClose);
1542
+ socket.removeListener("error", onError);
1472
1543
  resolve();
1473
- });
1474
- socket.once("error", () => {
1475
- clearTimeout(timer);
1544
+ }, "cleanup");
1545
+ const onClose = /* @__PURE__ */ __name(() => cleanup(), "onClose");
1546
+ const onError = /* @__PURE__ */ __name(() => {
1476
1547
  socket.destroy();
1477
- resolve();
1478
- });
1548
+ cleanup();
1549
+ }, "onError");
1550
+ timer = setTimeout(() => {
1551
+ socket.destroy();
1552
+ cleanup();
1553
+ }, 1e3);
1554
+ socket.once("close", onClose);
1555
+ socket.once("error", onError);
1479
1556
  })));
1480
1557
  this.connections.clear();
1481
1558
  logger.getLogger().info(`Closed ${sockets.length} active connection(s)`);
1482
1559
  }
1483
1560
  /**
1484
- * Set an externally created base router.
1485
- * This will override the internal rootRouter.
1561
+ * Mount a base router onto the server's root router.
1562
+ *
1563
+ * Note: This attaches the supplied router to the root router pipeline.
1564
+ * Duplicate mounting of the same router instance is ignored.
1565
+ *
1566
+ * @param router The Express router instance to mount
1567
+ * @returns This instance for method chaining
1486
1568
  */
1487
- setBaseRouter(router) {
1488
- this.externalRouter = router;
1569
+ addBaseRouter(router) {
1570
+ if (this.mountedRouters.has(router)) {
1571
+ return this;
1572
+ }
1573
+ this.mountedRouters.add(router);
1574
+ this.rootRouter.use(router);
1489
1575
  return this;
1490
1576
  }
1491
1577
  /**
1578
+ * Alias for `addBaseRouter` (maintained for backward compatibility).
1579
+ * Mounts the supplied router onto the server's root router.
1580
+ *
1581
+ * @param router The Express router instance to mount
1582
+ * @returns This instance for method chaining
1583
+ */
1584
+ setBaseRouter(router) {
1585
+ return this.addBaseRouter(router);
1586
+ }
1587
+ /**
1492
1588
  * Create and register a new router (only used if not injecting one externally - use `setBaseRouter` instead).
1493
1589
  */
1494
1590
  createRouter(prefix = "") {
@@ -1508,27 +1604,73 @@ var ExpressServer = class {
1508
1604
  */
1509
1605
  registerRoute(methods, path, ...handlers) {
1510
1606
  const fullPath = this.normalizePath(path, true);
1511
- const routerToUse = this.externalRouter || this.rootRouter;
1512
- const methodMap = {
1513
- get: routerToUse.get.bind(routerToUse),
1514
- post: routerToUse.post.bind(routerToUse),
1515
- put: routerToUse.put.bind(routerToUse),
1516
- delete: routerToUse.delete.bind(routerToUse),
1517
- patch: routerToUse.patch.bind(routerToUse),
1518
- options: routerToUse.options.bind(routerToUse),
1519
- head: routerToUse.head.bind(routerToUse)
1520
- };
1607
+ const routerToUse = this.rootRouter;
1521
1608
  methods.forEach((m) => {
1522
- const fn = methodMap[m];
1523
- if (fn) {
1524
- fn(fullPath, ...handlers);
1525
- } else {
1609
+ const method = m.toLowerCase();
1610
+ if (!SUPPORTED_HTTP_METHODS.has(method) || typeof routerToUse[method] !== "function") {
1526
1611
  throw new Error(`Unsupported HTTP method: ${m}`);
1527
1612
  }
1613
+ routerToUse[method](fullPath, ...handlers);
1528
1614
  });
1529
1615
  return this;
1530
1616
  }
1531
1617
  /**
1618
+ * Register a GET route handler.
1619
+ */
1620
+ get(path, ...handlers) {
1621
+ return this.registerRoute([
1622
+ "get"
1623
+ ], path, ...handlers);
1624
+ }
1625
+ /**
1626
+ * Register a POST route handler.
1627
+ */
1628
+ post(path, ...handlers) {
1629
+ return this.registerRoute([
1630
+ "post"
1631
+ ], path, ...handlers);
1632
+ }
1633
+ /**
1634
+ * Register a PUT route handler.
1635
+ */
1636
+ put(path, ...handlers) {
1637
+ return this.registerRoute([
1638
+ "put"
1639
+ ], path, ...handlers);
1640
+ }
1641
+ /**
1642
+ * Register a DELETE route handler.
1643
+ */
1644
+ delete(path, ...handlers) {
1645
+ return this.registerRoute([
1646
+ "delete"
1647
+ ], path, ...handlers);
1648
+ }
1649
+ /**
1650
+ * Register a PATCH route handler.
1651
+ */
1652
+ patch(path, ...handlers) {
1653
+ return this.registerRoute([
1654
+ "patch"
1655
+ ], path, ...handlers);
1656
+ }
1657
+ /**
1658
+ * Register an OPTIONS route handler.
1659
+ */
1660
+ options(path, ...handlers) {
1661
+ return this.registerRoute([
1662
+ "options"
1663
+ ], path, ...handlers);
1664
+ }
1665
+ /**
1666
+ * Register a HEAD route handler.
1667
+ */
1668
+ head(path, ...handlers) {
1669
+ return this.registerRoute([
1670
+ "head"
1671
+ ], path, ...handlers);
1672
+ }
1673
+ /**
1532
1674
  * Register custom middleware with optional path restriction.
1533
1675
  *
1534
1676
  * Use this for:
@@ -1542,7 +1684,7 @@ var ExpressServer = class {
1542
1684
  * @returns This instance for method chaining
1543
1685
  */
1544
1686
  registerMiddleware(path, middleware) {
1545
- const routerToUse = this.externalRouter || this.rootRouter;
1687
+ const routerToUse = this.rootRouter;
1546
1688
  if (typeof path === "string") {
1547
1689
  const normalizedPath = this.normalizePath(path);
1548
1690
  if (normalizedPath) {
@@ -1565,7 +1707,7 @@ var ExpressServer = class {
1565
1707
  */
1566
1708
  useMiddleware(...middlewares) {
1567
1709
  middlewares.forEach((middleware) => {
1568
- (this.externalRouter || this.rootRouter).use(middleware);
1710
+ this.rootRouter.use(middleware);
1569
1711
  });
1570
1712
  return this;
1571
1713
  }
package/server/index.d.ts CHANGED
@@ -62,11 +62,11 @@ declare class ExpressServer {
62
62
  protected hooks: CatbeeServerHooks;
63
63
  /** Global API prefix (from config) */
64
64
  protected globalPrefix: string;
65
- /** Internal fallback router */
65
+ /** Primary root router mounted to the application */
66
66
  private readonly rootRouter;
67
- /** User-supplied router */
68
- private externalRouter?;
69
- /** Internal Express app instance */
67
+ /** Set of registered sub-routers to prevent duplicate mounting */
68
+ private readonly mountedRouters;
69
+ /** Express app instance */
70
70
  private readonly app;
71
71
  /** Set of active WebSocket connections */
72
72
  private readonly connections;
@@ -74,6 +74,8 @@ declare class ExpressServer {
74
74
  private isShuttingDown;
75
75
  /** Flag indicating if graceful shutdown handlers are registered */
76
76
  private gracefulShutdownRegistered;
77
+ /** Map of registered signal listeners for clean teardown */
78
+ private readonly signalListeners;
77
79
  /**
78
80
  * Collection of registered health check functions.
79
81
  * These are executed when the health check endpoint is accessed.
@@ -81,6 +83,8 @@ declare class ExpressServer {
81
83
  private readonly healthChecks;
82
84
  /** Promise that resolves when initialization (middleware + routes) is complete */
83
85
  private readonly initPromise;
86
+ /** In-flight start promise to protect against concurrent start() calls */
87
+ private startPromise?;
84
88
  /**
85
89
  * Initializes server with intelligent defaults and security best practices.
86
90
  * All settings can be customized via config and hooks.
@@ -178,6 +182,10 @@ declare class ExpressServer {
178
182
  * Set up OpenAPI documentation middleware.
179
183
  */
180
184
  private setupOpenApiMiddleware;
185
+ /**
186
+ * Set up response preprocessing hook (applies global prefix if set).
187
+ */
188
+ private setupResponseHook;
181
189
  /**
182
190
  * Configure server routes and error handling.
183
191
  * Sets up in following order:
@@ -238,28 +246,32 @@ declare class ExpressServer {
238
246
  * Start the HTTP server and begin listening for requests.
239
247
  *
240
248
  * This method:
249
+ * - Protects against concurrent start() invocations
250
+ * - Awaits server initialization (middleware + routes)
241
251
  * - Executes beforeStart hooks
252
+ * - Creates the HTTP/HTTPS server instance
253
+ * - Sets up error handling and connection tracking BEFORE listening
254
+ * - Executes onServerCreated hook BEFORE listening
242
255
  * - Binds to the configured host/port
243
- * - Sets up error handling for startup failures
244
- * - Executes afterStart hooks on success
245
- * - Logs startup information
256
+ * - Executes afterStart hooks on successful listen
257
+ * - Cleans up server reference and listeners on startup failure
246
258
  *
247
259
  * @returns Promise resolving to the running HTTP server instance
248
260
  * @throws Error if server fails to start or port is already in use
249
261
  */
250
262
  start(): Promise<http.Server | https.Server>;
251
263
  /**
252
- * Create HTTP or HTTPS server instance.
264
+ * Internal implementation of server startup.
265
+ */
266
+ private doStart;
267
+ /**
268
+ * Create HTTP or HTTPS server instance (without listening).
253
269
  */
254
270
  private createServerInstance;
255
271
  /**
256
272
  * Set up connection tracking for graceful shutdown.
257
273
  */
258
274
  private setupConnectionTracking;
259
- /**
260
- * Set up error handling for server startup.
261
- */
262
- private setupServerErrorHandling;
263
275
  /**
264
276
  * Log server startup information.
265
277
  */
@@ -297,14 +309,32 @@ declare class ExpressServer {
297
309
  * @param signals Array of process signals to listen for (default: SIGINT, SIGTERM)
298
310
  */
299
311
  enableGracefulShutdown(signals?: NodeJS.Signals[]): this;
312
+ /**
313
+ * Unregister graceful shutdown signal listeners.
314
+ * Useful for testing and dynamic server lifecycles to prevent memory and listener leaks.
315
+ */
316
+ disableGracefulShutdown(): this;
300
317
  /**
301
318
  * Destroy all active connections (gracefully if possible).
302
319
  * If a connection does not close cleanly, it will be force-destroyed.
303
320
  */
304
321
  private destroyConnections;
305
322
  /**
306
- * Set an externally created base router.
307
- * This will override the internal rootRouter.
323
+ * Mount a base router onto the server's root router.
324
+ *
325
+ * Note: This attaches the supplied router to the root router pipeline.
326
+ * Duplicate mounting of the same router instance is ignored.
327
+ *
328
+ * @param router The Express router instance to mount
329
+ * @returns This instance for method chaining
330
+ */
331
+ addBaseRouter(router: Router): this;
332
+ /**
333
+ * Alias for `addBaseRouter` (maintained for backward compatibility).
334
+ * Mounts the supplied router onto the server's root router.
335
+ *
336
+ * @param router The Express router instance to mount
337
+ * @returns This instance for method chaining
308
338
  */
309
339
  setBaseRouter(router: Router): this;
310
340
  /**
@@ -321,6 +351,34 @@ declare class ExpressServer {
321
351
  * @returns This instance for method chaining
322
352
  */
323
353
  registerRoute(methods: Array<keyof Pick<Express, 'get' | 'post' | 'put' | 'delete' | 'patch' | 'options' | 'head'>>, path: string, ...handlers: Array<express.RequestHandler>): this;
354
+ /**
355
+ * Register a GET route handler.
356
+ */
357
+ get(path: string, ...handlers: express.RequestHandler[]): this;
358
+ /**
359
+ * Register a POST route handler.
360
+ */
361
+ post(path: string, ...handlers: express.RequestHandler[]): this;
362
+ /**
363
+ * Register a PUT route handler.
364
+ */
365
+ put(path: string, ...handlers: express.RequestHandler[]): this;
366
+ /**
367
+ * Register a DELETE route handler.
368
+ */
369
+ delete(path: string, ...handlers: express.RequestHandler[]): this;
370
+ /**
371
+ * Register a PATCH route handler.
372
+ */
373
+ patch(path: string, ...handlers: express.RequestHandler[]): this;
374
+ /**
375
+ * Register an OPTIONS route handler.
376
+ */
377
+ options(path: string, ...handlers: express.RequestHandler[]): this;
378
+ /**
379
+ * Register a HEAD route handler.
380
+ */
381
+ head(path: string, ...handlers: express.RequestHandler[]): this;
324
382
  /**
325
383
  * Register custom middleware with optional path restriction.
326
384
  *