@catbee/utils 2.0.1 → 2.0.2
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/crypto/index.d.ts +1 -1
- package/date/index.cjs +343 -102
- package/date/index.d.ts +178 -6
- package/date/index.mjs +338 -103
- package/logger/index.cjs +1 -1
- package/logger/index.mjs +1 -1
- package/package.json +6 -6
- package/server/index.cjs +175 -11
- package/server/index.d.ts +89 -2
- package/server/index.mjs +177 -13
- package/types/index.d.ts +3 -2
- package/validation/index.cjs +30 -4
- package/validation/index.d.ts +29 -3
- package/validation/index.mjs +30 -5
package/server/index.cjs
CHANGED
|
@@ -57,17 +57,29 @@ var ServerConfigBuilder = class {
|
|
|
57
57
|
*
|
|
58
58
|
* @private
|
|
59
59
|
* @param port - The port number to validate
|
|
60
|
-
* @throws {Error} If port is not an integer or is outside the valid range (
|
|
60
|
+
* @throws {Error} If port is not an integer or is outside the valid range (0-65535)
|
|
61
61
|
*/
|
|
62
62
|
validatePort(port) {
|
|
63
|
-
if (!validation.isPort(port)) {
|
|
64
|
-
throw new Error(`Port must be a valid number between
|
|
63
|
+
if (!validation.isPort(port, true)) {
|
|
64
|
+
throw new Error(`Port must be a valid number between 0 and 65535, got: ${port}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Validates that a hostname is valid.
|
|
69
|
+
*
|
|
70
|
+
* @private
|
|
71
|
+
* @param host - The hostname to validate
|
|
72
|
+
* @throws {Error} If hostname is invalid
|
|
73
|
+
*/
|
|
74
|
+
validateHost(host) {
|
|
75
|
+
if (!validation.isHostname(host)) {
|
|
76
|
+
throw new Error(`Host must be a valid hostname or IP address, got: ${host}`);
|
|
65
77
|
}
|
|
66
78
|
}
|
|
67
79
|
/**
|
|
68
80
|
* Sets the port the server will listen on.
|
|
69
81
|
*
|
|
70
|
-
* @param port - The port number (
|
|
82
|
+
* @param port - The port number (0-65535). Use 0 for dynamic port assignment.
|
|
71
83
|
* @returns The builder instance for chaining
|
|
72
84
|
* @throws {Error} If port is invalid
|
|
73
85
|
* @default 3000 (can be overridden via PORT env variable)
|
|
@@ -87,14 +99,17 @@ var ServerConfigBuilder = class {
|
|
|
87
99
|
*
|
|
88
100
|
* @param host - The hostname (e.g., 'localhost', '0.0.0.0', '127.0.0.1')
|
|
89
101
|
* @returns The builder instance for chaining
|
|
102
|
+
* @throws {Error} If hostname is invalid
|
|
90
103
|
* @default '0.0.0.0' (can be overridden via HOST env variable)
|
|
91
104
|
*
|
|
92
105
|
* @example
|
|
93
106
|
* ```typescript
|
|
94
107
|
* builder.withHost('0.0.0.0') // Listen on all interfaces
|
|
108
|
+
* builder.withHost('localhost') // Listen on localhost only
|
|
95
109
|
* ```
|
|
96
110
|
*/
|
|
97
111
|
withHost(host) {
|
|
112
|
+
this.validateHost(host);
|
|
98
113
|
this.config.host = host;
|
|
99
114
|
return this;
|
|
100
115
|
}
|
|
@@ -505,12 +520,23 @@ var ServerConfigBuilder = class {
|
|
|
505
520
|
* ```
|
|
506
521
|
*/
|
|
507
522
|
withBodyParser(opts) {
|
|
523
|
+
if (opts === true) {
|
|
524
|
+
this.config.bodyParser = config.getCatbeeServerGlobalConfig().bodyParser;
|
|
525
|
+
return this;
|
|
526
|
+
} else if (opts === false) {
|
|
527
|
+
this.config.bodyParser = false;
|
|
528
|
+
return this;
|
|
529
|
+
}
|
|
508
530
|
this.config.bodyParser = {
|
|
509
531
|
...this.config.bodyParser,
|
|
510
532
|
...opts
|
|
511
533
|
};
|
|
512
534
|
return this;
|
|
513
535
|
}
|
|
536
|
+
disableBodyParser() {
|
|
537
|
+
this.config.bodyParser = false;
|
|
538
|
+
return this;
|
|
539
|
+
}
|
|
514
540
|
/**
|
|
515
541
|
* Configures cookie parsing middleware.
|
|
516
542
|
*
|
|
@@ -661,7 +687,7 @@ var ServerConfigBuilder = class {
|
|
|
661
687
|
});
|
|
662
688
|
}
|
|
663
689
|
mergeConfig(key, value) {
|
|
664
|
-
const current =
|
|
690
|
+
const current = object.isPlainObject(this.config[key]) ? object.deepClone(this.config[key]) : {};
|
|
665
691
|
this.config[key] = object.deepObjMerge({}, current, value);
|
|
666
692
|
}
|
|
667
693
|
setEnabled(key, enable, overrides = {}) {
|
|
@@ -742,12 +768,15 @@ var ExpressServer = class {
|
|
|
742
768
|
*/
|
|
743
769
|
constructor(config$1, hooks = {}) {
|
|
744
770
|
if (this.hasBuildMarker(config$1)) {
|
|
745
|
-
this.config = config$1;
|
|
771
|
+
this.config = object.deepObjMerge({}, config$1);
|
|
746
772
|
} else {
|
|
747
773
|
this.config = object.deepObjMerge({}, config.getCatbeeServerGlobalConfig(), config$1);
|
|
748
774
|
}
|
|
749
|
-
if (
|
|
750
|
-
|
|
775
|
+
if (this.config.host) {
|
|
776
|
+
this.config.host = this.normalizeHost(this.config.host);
|
|
777
|
+
}
|
|
778
|
+
if (!validation.isPort(this.config.port, true)) {
|
|
779
|
+
const msg = `Port must be a valid number between 0 and 65535, got: ${this.config.port}`;
|
|
751
780
|
logger.getLogger().error(msg);
|
|
752
781
|
throw new Error(msg);
|
|
753
782
|
}
|
|
@@ -1026,7 +1055,6 @@ var ExpressServer = class {
|
|
|
1026
1055
|
}
|
|
1027
1056
|
const logger$1 = logger.getLogger();
|
|
1028
1057
|
const incomingRequestMetaData = {
|
|
1029
|
-
requestId: req.id,
|
|
1030
1058
|
method: req.method,
|
|
1031
1059
|
url: req.originalUrl || req.url,
|
|
1032
1060
|
ip: req.ip
|
|
@@ -1076,13 +1104,23 @@ var ExpressServer = class {
|
|
|
1076
1104
|
* Set up body parsing middleware.
|
|
1077
1105
|
*/
|
|
1078
1106
|
setupBodyParsingMiddleware() {
|
|
1079
|
-
if (this.config.bodyParser) {
|
|
1107
|
+
if (object.isPlainObject(this.config.bodyParser)) {
|
|
1080
1108
|
if (this.config.bodyParser.json) {
|
|
1081
1109
|
this.app.use(express__default.default.json(this.config.bodyParser.json));
|
|
1082
1110
|
}
|
|
1083
1111
|
if (this.config.bodyParser.urlencoded) {
|
|
1084
1112
|
this.app.use(express__default.default.urlencoded(this.config.bodyParser.urlencoded));
|
|
1085
1113
|
}
|
|
1114
|
+
} else if (this.config.bodyParser === true) {
|
|
1115
|
+
const globalBodyParserConfig = config.getCatbeeServerGlobalConfig().bodyParser;
|
|
1116
|
+
if (object.isPlainObject(globalBodyParserConfig)) {
|
|
1117
|
+
if (globalBodyParserConfig.json) {
|
|
1118
|
+
this.app.use(express__default.default.json(globalBodyParserConfig.json));
|
|
1119
|
+
}
|
|
1120
|
+
if (globalBodyParserConfig.urlencoded) {
|
|
1121
|
+
this.app.use(express__default.default.urlencoded(globalBodyParserConfig.urlencoded));
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1086
1124
|
}
|
|
1087
1125
|
}
|
|
1088
1126
|
/**
|
|
@@ -1421,7 +1459,9 @@ var ExpressServer = class {
|
|
|
1421
1459
|
*/
|
|
1422
1460
|
logServerStartInfo() {
|
|
1423
1461
|
const protocol = this.config.https ? "https" : "http";
|
|
1424
|
-
const
|
|
1462
|
+
const port = this.getPort();
|
|
1463
|
+
const host = this.formatHostForUrl(this.config.host || "localhost");
|
|
1464
|
+
const url = `${protocol}://${host}:${port}`;
|
|
1425
1465
|
logger.getLogger().info(`Server running on ${url}`);
|
|
1426
1466
|
if (this.config.healthCheck?.path) {
|
|
1427
1467
|
logger.getLogger().info(`Health check available at ${url}${this.normalizePath(this.config.healthCheck.path, this.config.healthCheck.withGlobalPrefix)}`);
|
|
@@ -1646,12 +1686,136 @@ var ExpressServer = class {
|
|
|
1646
1686
|
return this.config;
|
|
1647
1687
|
}
|
|
1648
1688
|
/**
|
|
1689
|
+
* Get the port the server is listening on.
|
|
1690
|
+
* Returns the actual port if server is running (useful when config.port was 0),
|
|
1691
|
+
* otherwise returns the configured port.
|
|
1692
|
+
*
|
|
1693
|
+
* @returns The port number
|
|
1694
|
+
*/
|
|
1695
|
+
getPort() {
|
|
1696
|
+
const address = this.server?.address();
|
|
1697
|
+
if (address && typeof address === "object" && "port" in address) {
|
|
1698
|
+
return address.port;
|
|
1699
|
+
}
|
|
1700
|
+
return this.config.port;
|
|
1701
|
+
}
|
|
1702
|
+
/**
|
|
1703
|
+
* Get the full URL the server is running on.
|
|
1704
|
+
* Returns the actual URL if server is running (useful when config.port was 0),
|
|
1705
|
+
* otherwise returns the configured URL.
|
|
1706
|
+
*
|
|
1707
|
+
* @returns The full server URL (e.g., "http://localhost:3000")
|
|
1708
|
+
*/
|
|
1709
|
+
getUrl() {
|
|
1710
|
+
const protocol = this.config.https ? "https" : "http";
|
|
1711
|
+
const port = this.getPort();
|
|
1712
|
+
const host = this.formatHostForUrl(this.config.host || "localhost");
|
|
1713
|
+
return `${protocol}://${host}:${port}`;
|
|
1714
|
+
}
|
|
1715
|
+
/**
|
|
1716
|
+
* Check if the server is configured for dynamic port assignment.
|
|
1717
|
+
* Returns true if the original port configuration was 0.
|
|
1718
|
+
*
|
|
1719
|
+
* @returns True if using dynamic port assignment, false otherwise
|
|
1720
|
+
*/
|
|
1721
|
+
isPortDynamic() {
|
|
1722
|
+
return this.config.port === 0;
|
|
1723
|
+
}
|
|
1724
|
+
/**
|
|
1725
|
+
* Check if the server is currently running and listening for requests.
|
|
1726
|
+
*
|
|
1727
|
+
* @returns True if server is running, false otherwise
|
|
1728
|
+
*/
|
|
1729
|
+
isRunning() {
|
|
1730
|
+
return this.server !== null && this.server.listening;
|
|
1731
|
+
}
|
|
1732
|
+
/**
|
|
1733
|
+
* Get the host address the server is bound to.
|
|
1734
|
+
*
|
|
1735
|
+
* @returns The host address
|
|
1736
|
+
*/
|
|
1737
|
+
getHost() {
|
|
1738
|
+
return this.config.host || "localhost";
|
|
1739
|
+
}
|
|
1740
|
+
/**
|
|
1741
|
+
* Get the protocol the server is using ('http' or 'https').
|
|
1742
|
+
*
|
|
1743
|
+
* @returns The protocol string
|
|
1744
|
+
*/
|
|
1745
|
+
getProtocol() {
|
|
1746
|
+
return this.config.https ? "https" : "http";
|
|
1747
|
+
}
|
|
1748
|
+
/**
|
|
1749
|
+
* Check if the server is configured to use HTTPS.
|
|
1750
|
+
*
|
|
1751
|
+
* @returns True if using HTTPS, false otherwise
|
|
1752
|
+
*/
|
|
1753
|
+
isHttps() {
|
|
1754
|
+
return this.config.https !== void 0;
|
|
1755
|
+
}
|
|
1756
|
+
/**
|
|
1757
|
+
* Set a new port for the server.
|
|
1758
|
+
* Can only be called before the server starts listening.
|
|
1759
|
+
* Useful for testing scenarios where you need to change the port dynamically.
|
|
1760
|
+
*
|
|
1761
|
+
* @param port - The new port number (0-65535)
|
|
1762
|
+
* @throws Error if server is already running or port is invalid
|
|
1763
|
+
*/
|
|
1764
|
+
setPort(port) {
|
|
1765
|
+
if (this.server) {
|
|
1766
|
+
throw new Error("Cannot change port after server has started");
|
|
1767
|
+
}
|
|
1768
|
+
if (!validation.isPort(port, true)) {
|
|
1769
|
+
throw new Error(`Port must be a valid number between 0 and 65535, got: ${port}`);
|
|
1770
|
+
}
|
|
1771
|
+
this.config.port = port;
|
|
1772
|
+
}
|
|
1773
|
+
/**
|
|
1774
|
+
* Set a new host for the server.
|
|
1775
|
+
* Can only be called before the server starts listening.
|
|
1776
|
+
* Useful for testing scenarios where you need to change the host dynamically.
|
|
1777
|
+
*
|
|
1778
|
+
* @param host - The new host (e.g., "localhost", "0.0.0.0", "127.0.0.1", "::1", or "[::1]")
|
|
1779
|
+
* @throws {Error} If server is already running or host is invalid
|
|
1780
|
+
*/
|
|
1781
|
+
setHost(host) {
|
|
1782
|
+
if (this.server) {
|
|
1783
|
+
throw new Error("Cannot change host after server has started");
|
|
1784
|
+
}
|
|
1785
|
+
const normalizedHost = this.normalizeHost(host);
|
|
1786
|
+
if (!validation.isHostname(normalizedHost)) {
|
|
1787
|
+
throw new Error(`Host must be a valid hostname or IP address, got: ${host}`);
|
|
1788
|
+
}
|
|
1789
|
+
this.config.host = normalizedHost;
|
|
1790
|
+
}
|
|
1791
|
+
/**
|
|
1649
1792
|
* Wait until server initialization (middleware + routes) has completed.
|
|
1650
1793
|
* Useful for integration tests that inspect app before starting.
|
|
1651
1794
|
*/
|
|
1652
1795
|
async waitUntilReady() {
|
|
1653
1796
|
await this.initPromise;
|
|
1654
1797
|
}
|
|
1798
|
+
/**
|
|
1799
|
+
* Normalize host by stripping surrounding brackets from IPv6 addresses.
|
|
1800
|
+
* This ensures the host value is compatible with server.listen().
|
|
1801
|
+
* Brackets are URL syntax only and must be removed for Node.js binding.
|
|
1802
|
+
*/
|
|
1803
|
+
normalizeHost(host) {
|
|
1804
|
+
if (host.startsWith("[") && host.endsWith("]")) {
|
|
1805
|
+
return host.slice(1, -1);
|
|
1806
|
+
}
|
|
1807
|
+
return host;
|
|
1808
|
+
}
|
|
1809
|
+
/**
|
|
1810
|
+
* Format host for use in URLs.
|
|
1811
|
+
* Wraps IPv6 addresses in brackets per RFC 3986.
|
|
1812
|
+
*/
|
|
1813
|
+
formatHostForUrl(host) {
|
|
1814
|
+
if (host.includes(":")) {
|
|
1815
|
+
return `[${host}]`;
|
|
1816
|
+
}
|
|
1817
|
+
return host;
|
|
1818
|
+
}
|
|
1655
1819
|
normalizePath(path, withGlobalPrefix = false) {
|
|
1656
1820
|
const sanitize = /* @__PURE__ */ __name((p) => {
|
|
1657
1821
|
return "/" + p.trim().replace(/^\/+/, "").replace(/\/{2,}/g, "/").replace(/\/+$/, "");
|
package/server/index.d.ts
CHANGED
|
@@ -363,11 +363,87 @@ declare class ExpressServer {
|
|
|
363
363
|
* @return {*} {CatbeeServerConfig}
|
|
364
364
|
*/
|
|
365
365
|
getConfig(): CatbeeServerConfig;
|
|
366
|
+
/**
|
|
367
|
+
* Get the port the server is listening on.
|
|
368
|
+
* Returns the actual port if server is running (useful when config.port was 0),
|
|
369
|
+
* otherwise returns the configured port.
|
|
370
|
+
*
|
|
371
|
+
* @returns The port number
|
|
372
|
+
*/
|
|
373
|
+
getPort(): number;
|
|
374
|
+
/**
|
|
375
|
+
* Get the full URL the server is running on.
|
|
376
|
+
* Returns the actual URL if server is running (useful when config.port was 0),
|
|
377
|
+
* otherwise returns the configured URL.
|
|
378
|
+
*
|
|
379
|
+
* @returns The full server URL (e.g., "http://localhost:3000")
|
|
380
|
+
*/
|
|
381
|
+
getUrl(): string;
|
|
382
|
+
/**
|
|
383
|
+
* Check if the server is configured for dynamic port assignment.
|
|
384
|
+
* Returns true if the original port configuration was 0.
|
|
385
|
+
*
|
|
386
|
+
* @returns True if using dynamic port assignment, false otherwise
|
|
387
|
+
*/
|
|
388
|
+
isPortDynamic(): boolean;
|
|
389
|
+
/**
|
|
390
|
+
* Check if the server is currently running and listening for requests.
|
|
391
|
+
*
|
|
392
|
+
* @returns True if server is running, false otherwise
|
|
393
|
+
*/
|
|
394
|
+
isRunning(): boolean;
|
|
395
|
+
/**
|
|
396
|
+
* Get the host address the server is bound to.
|
|
397
|
+
*
|
|
398
|
+
* @returns The host address
|
|
399
|
+
*/
|
|
400
|
+
getHost(): string;
|
|
401
|
+
/**
|
|
402
|
+
* Get the protocol the server is using ('http' or 'https').
|
|
403
|
+
*
|
|
404
|
+
* @returns The protocol string
|
|
405
|
+
*/
|
|
406
|
+
getProtocol(): string;
|
|
407
|
+
/**
|
|
408
|
+
* Check if the server is configured to use HTTPS.
|
|
409
|
+
*
|
|
410
|
+
* @returns True if using HTTPS, false otherwise
|
|
411
|
+
*/
|
|
412
|
+
isHttps(): boolean;
|
|
413
|
+
/**
|
|
414
|
+
* Set a new port for the server.
|
|
415
|
+
* Can only be called before the server starts listening.
|
|
416
|
+
* Useful for testing scenarios where you need to change the port dynamically.
|
|
417
|
+
*
|
|
418
|
+
* @param port - The new port number (0-65535)
|
|
419
|
+
* @throws Error if server is already running or port is invalid
|
|
420
|
+
*/
|
|
421
|
+
setPort(port: number): void;
|
|
422
|
+
/**
|
|
423
|
+
* Set a new host for the server.
|
|
424
|
+
* Can only be called before the server starts listening.
|
|
425
|
+
* Useful for testing scenarios where you need to change the host dynamically.
|
|
426
|
+
*
|
|
427
|
+
* @param host - The new host (e.g., "localhost", "0.0.0.0", "127.0.0.1", "::1", or "[::1]")
|
|
428
|
+
* @throws {Error} If server is already running or host is invalid
|
|
429
|
+
*/
|
|
430
|
+
setHost(host: string): void;
|
|
366
431
|
/**
|
|
367
432
|
* Wait until server initialization (middleware + routes) has completed.
|
|
368
433
|
* Useful for integration tests that inspect app before starting.
|
|
369
434
|
*/
|
|
370
435
|
waitUntilReady(): Promise<void>;
|
|
436
|
+
/**
|
|
437
|
+
* Normalize host by stripping surrounding brackets from IPv6 addresses.
|
|
438
|
+
* This ensures the host value is compatible with server.listen().
|
|
439
|
+
* Brackets are URL syntax only and must be removed for Node.js binding.
|
|
440
|
+
*/
|
|
441
|
+
private normalizeHost;
|
|
442
|
+
/**
|
|
443
|
+
* Format host for use in URLs.
|
|
444
|
+
* Wraps IPv6 addresses in brackets per RFC 3986.
|
|
445
|
+
*/
|
|
446
|
+
private formatHostForUrl;
|
|
371
447
|
private normalizePath;
|
|
372
448
|
private normalizeRouteForMetrics;
|
|
373
449
|
/**
|
|
@@ -403,13 +479,21 @@ declare class ServerConfigBuilder {
|
|
|
403
479
|
*
|
|
404
480
|
* @private
|
|
405
481
|
* @param port - The port number to validate
|
|
406
|
-
* @throws {Error} If port is not an integer or is outside the valid range (
|
|
482
|
+
* @throws {Error} If port is not an integer or is outside the valid range (0-65535)
|
|
407
483
|
*/
|
|
408
484
|
private validatePort;
|
|
485
|
+
/**
|
|
486
|
+
* Validates that a hostname is valid.
|
|
487
|
+
*
|
|
488
|
+
* @private
|
|
489
|
+
* @param host - The hostname to validate
|
|
490
|
+
* @throws {Error} If hostname is invalid
|
|
491
|
+
*/
|
|
492
|
+
private validateHost;
|
|
409
493
|
/**
|
|
410
494
|
* Sets the port the server will listen on.
|
|
411
495
|
*
|
|
412
|
-
* @param port - The port number (
|
|
496
|
+
* @param port - The port number (0-65535). Use 0 for dynamic port assignment.
|
|
413
497
|
* @returns The builder instance for chaining
|
|
414
498
|
* @throws {Error} If port is invalid
|
|
415
499
|
* @default 3000 (can be overridden via PORT env variable)
|
|
@@ -425,11 +509,13 @@ declare class ServerConfigBuilder {
|
|
|
425
509
|
*
|
|
426
510
|
* @param host - The hostname (e.g., 'localhost', '0.0.0.0', '127.0.0.1')
|
|
427
511
|
* @returns The builder instance for chaining
|
|
512
|
+
* @throws {Error} If hostname is invalid
|
|
428
513
|
* @default '0.0.0.0' (can be overridden via HOST env variable)
|
|
429
514
|
*
|
|
430
515
|
* @example
|
|
431
516
|
* ```typescript
|
|
432
517
|
* builder.withHost('0.0.0.0') // Listen on all interfaces
|
|
518
|
+
* builder.withHost('localhost') // Listen on localhost only
|
|
433
519
|
* ```
|
|
434
520
|
*/
|
|
435
521
|
withHost(host: string): this;
|
|
@@ -768,6 +854,7 @@ declare class ServerConfigBuilder {
|
|
|
768
854
|
* ```
|
|
769
855
|
*/
|
|
770
856
|
withBodyParser(opts: NonNullable<CatbeeServerConfig['bodyParser']>): this;
|
|
857
|
+
disableBodyParser(): this;
|
|
771
858
|
/**
|
|
772
859
|
* Configures cookie parsing middleware.
|
|
773
860
|
*
|