Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8fdcd479d6 | |||
| d24dde8eff | |||
| 40a34073e9 | |||
| 9ac297c197 | |||
| ddd0662fb8 | |||
| 11bc0dde6c |
25
changelog.md
25
changelog.md
@@ -1,5 +1,30 @@
|
||||
# Changelog
|
||||
|
||||
## 2026-02-19 - 7.0.0 - BREAKING CHANGE(deps)
|
||||
bump dependencies: @serve.zone/remoteingress to ^4.0.0 (breaking), @push.rocks/smartproxy to ^25.7.6, @types/node to ^25.3.0
|
||||
|
||||
- Updated @serve.zone/remoteingress from ^3.3.0 to ^4.0.0 — major breaking change; may require code changes to adapt to new API.
|
||||
- Updated @push.rocks/smartproxy from ^25.7.3 to ^25.7.6 — patch update (non-breaking).
|
||||
- Updated @types/node from ^25.2.3 to ^25.3.0 — patch update (non-breaking).
|
||||
- Current package version is 6.13.2; recommend bumping to 7.0.0 due to the breaking dependency upgrade.
|
||||
|
||||
## 2026-02-19 - 6.13.2 - fix(runtime)
|
||||
prevent memory leaks and improve shutdown/stream handling across services
|
||||
|
||||
- Add CertProvisionScheduler.clear() to reset in-memory backoff cache and call it during DcRouter shutdown
|
||||
- Stop any existing SmartAcme instance before creating a new one (await stop and log errors) to avoid duplicate running instances
|
||||
- Null out many DcRouter service references and clear certificateStatusMap on shutdown to allow GC of stopped services
|
||||
- Cap emailMetrics.recipients map size and trim to ~80% of MAX_TOP_DOMAINS to prevent unbounded growth
|
||||
- Await virtualStream.sendData in logs follow handler and clear the interval if the stream errors/closes to avoid interval leaks
|
||||
- Limit normalizedMacCache size and evict oldest entries when it exceeds 10000 to prevent unbounded cache growth
|
||||
|
||||
## 2026-02-18 - 6.13.1 - fix(dcrouter)
|
||||
enable PROXY protocol v1 handling for SmartProxy when remoteIngress is enabled to preserve client IPs
|
||||
|
||||
- Set smartProxyConfig.acceptProxyProtocol = true when options.remoteIngressConfig.enabled
|
||||
- Whitelist loopback address by setting smartProxyConfig.proxyIPs = ['127.0.0.1']
|
||||
- Only applies when remoteIngress is enabled; used to accept tunneled connections forwarded by the hub to preserve original client IPs
|
||||
|
||||
## 2026-02-18 - 6.13.0 - feat(remoteingress)
|
||||
include listenPorts for allowed edges sent to the Rust hub and always resync allowed edges when edge properties change
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@serve.zone/dcrouter",
|
||||
"private": false,
|
||||
"version": "6.13.0",
|
||||
"version": "7.0.0",
|
||||
"description": "A multifaceted routing service handling mail and SMS delivery functions.",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
@@ -24,7 +24,7 @@
|
||||
"@git.zone/tsrun": "^2.0.1",
|
||||
"@git.zone/tstest": "^3.1.8",
|
||||
"@git.zone/tswatch": "^3.1.0",
|
||||
"@types/node": "^25.2.3"
|
||||
"@types/node": "^25.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@api.global/typedrequest": "^3.2.6",
|
||||
@@ -49,14 +49,14 @@
|
||||
"@push.rocks/smartnetwork": "^4.4.0",
|
||||
"@push.rocks/smartpath": "^6.0.0",
|
||||
"@push.rocks/smartpromise": "^4.2.3",
|
||||
"@push.rocks/smartproxy": "^25.7.3",
|
||||
"@push.rocks/smartproxy": "^25.7.6",
|
||||
"@push.rocks/smartradius": "^1.1.1",
|
||||
"@push.rocks/smartrequest": "^5.0.1",
|
||||
"@push.rocks/smartrx": "^3.0.10",
|
||||
"@push.rocks/smartstate": "^2.0.30",
|
||||
"@push.rocks/smartunique": "^3.0.9",
|
||||
"@serve.zone/interfaces": "^5.3.0",
|
||||
"@serve.zone/remoteingress": "^3.3.0",
|
||||
"@serve.zone/remoteingress": "^4.0.0",
|
||||
"@tsclass/tsclass": "^9.3.0",
|
||||
"lru-cache": "^11.2.6",
|
||||
"uuid": "^13.0.0"
|
||||
|
||||
88
pnpm-lock.yaml
generated
88
pnpm-lock.yaml
generated
@@ -75,8 +75,8 @@ importers:
|
||||
specifier: ^4.2.3
|
||||
version: 4.2.3
|
||||
'@push.rocks/smartproxy':
|
||||
specifier: ^25.7.3
|
||||
version: 25.7.3
|
||||
specifier: ^25.7.6
|
||||
version: 25.7.6
|
||||
'@push.rocks/smartradius':
|
||||
specifier: ^1.1.1
|
||||
version: 1.1.1
|
||||
@@ -96,8 +96,8 @@ importers:
|
||||
specifier: ^5.3.0
|
||||
version: 5.3.0
|
||||
'@serve.zone/remoteingress':
|
||||
specifier: ^3.3.0
|
||||
version: 3.3.0
|
||||
specifier: ^4.0.0
|
||||
version: 4.0.0
|
||||
'@tsclass/tsclass':
|
||||
specifier: ^9.3.0
|
||||
version: 9.3.0
|
||||
@@ -124,8 +124,8 @@ importers:
|
||||
specifier: ^3.1.0
|
||||
version: 3.1.0(@tiptap/pm@2.27.2)
|
||||
'@types/node':
|
||||
specifier: ^25.2.3
|
||||
version: 25.2.3
|
||||
specifier: ^25.3.0
|
||||
version: 25.3.0
|
||||
|
||||
packages:
|
||||
|
||||
@@ -1034,8 +1034,8 @@ packages:
|
||||
'@push.rocks/smartpromise@4.2.3':
|
||||
resolution: {integrity: sha512-Ycg/TJR+tMt+S3wSFurOpEoW6nXv12QBtKXgBcjMZ4RsdO28geN46U09osPn9N9WuwQy1PkmTV5J/V4F9U8qEw==}
|
||||
|
||||
'@push.rocks/smartproxy@25.7.3':
|
||||
resolution: {integrity: sha512-9b5dwsLAhuDqnJptGBum4qBHlZwZPqPG3CJKxAwE3uFKjCmcE8qGDwodI0CjrQ7KW2PJ1BMq/Lk4ghs3Da6PWw==}
|
||||
'@push.rocks/smartproxy@25.7.6':
|
||||
resolution: {integrity: sha512-S7RilqdsHV8c31ex/Fcwpsv465kbwYQ5tMesoS/kRsOBxjan+UPOhJQxPH4H7TmKbvEsi5NMPK48ffgJmk9x1g==}
|
||||
|
||||
'@push.rocks/smartpuppeteer@2.0.5':
|
||||
resolution: {integrity: sha512-yK/qSeWVHIGWRp3c8S5tfdGP6WCKllZC4DR8d8CQlEjszOSBmHtlTdyyqOMBZ/BA4kd+eU5f3A1r4K2tGYty1g==}
|
||||
@@ -1340,8 +1340,8 @@ packages:
|
||||
'@serve.zone/interfaces@5.3.0':
|
||||
resolution: {integrity: sha512-venO7wtDR9ixzD9NhdERBGjNKbFA5LL0yHw4eqGh0UpmvtXVc3SFG0uuHDilOKMZqZ8bttV88qVsFy1aSTJrtA==}
|
||||
|
||||
'@serve.zone/remoteingress@3.3.0':
|
||||
resolution: {integrity: sha512-nmw0F+Otrg78Xai9G3qLcP3NP4VkGPGm/6IGJmrXEgx3Z+ewh5Rhs1/rtN0mJFNXP77LZz1HuEBgR8aWbSHFQw==}
|
||||
'@serve.zone/remoteingress@4.0.0':
|
||||
resolution: {integrity: sha512-kcC9pnQdS5Mw0ypmwT3GIYwrjVQJOjWw5TJ+j46t6Y98S4Mb7wEAAPsU+YRXozpkqUxWUDBeDK1fQHLvoF9PmQ==}
|
||||
|
||||
'@sindresorhus/is@5.6.0':
|
||||
resolution: {integrity: sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==}
|
||||
@@ -1834,8 +1834,8 @@ packages:
|
||||
'@types/node@22.19.11':
|
||||
resolution: {integrity: sha512-BH7YwL6rA93ReqeQS1c4bsPpcfOmJasG+Fkr6Y59q83f9M1WcBRHR2vM+P9eOisYRcN3ujQoiZY8uk5W+1WL8w==}
|
||||
|
||||
'@types/node@25.2.3':
|
||||
resolution: {integrity: sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==}
|
||||
'@types/node@25.3.0':
|
||||
resolution: {integrity: sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==}
|
||||
|
||||
'@types/pidusage@2.0.5':
|
||||
resolution: {integrity: sha512-MIiyZI4/MK9UGUXWt0jJcCZhVw7YdhBuTOuqP/BjuLDLZ2PmmViMIQgZiWxtaMicQfAz/kMrZ5T7PKxFSkTeUA==}
|
||||
@@ -3238,6 +3238,10 @@ packages:
|
||||
resolution: {integrity: sha512-ugkC31VaVg9cF0DFVoADH12k6061zNZkZON+aX8AWsR9GhPcErkcMBceb6znR8wLERM2AkkOxy2nWRLpT9Jq5w==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
minimatch@10.2.1:
|
||||
resolution: {integrity: sha512-MClCe8IL5nRRmawL6ib/eT4oLyeKMGCghibcDWK+J0hh0Q8kqSdia6BvbRMVk6mPa6WqUa5uR2oxt6C5jd533A==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
minimatch@3.1.2:
|
||||
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
|
||||
|
||||
@@ -4089,8 +4093,8 @@ packages:
|
||||
undici-types@6.21.0:
|
||||
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
||||
|
||||
undici-types@7.16.0:
|
||||
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
|
||||
undici-types@7.18.2:
|
||||
resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}
|
||||
|
||||
unified@11.0.5:
|
||||
resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
|
||||
@@ -6352,13 +6356,13 @@ snapshots:
|
||||
|
||||
'@push.rocks/smartpromise@4.2.3': {}
|
||||
|
||||
'@push.rocks/smartproxy@25.7.3':
|
||||
'@push.rocks/smartproxy@25.7.6':
|
||||
dependencies:
|
||||
'@push.rocks/smartcrypto': 2.0.4
|
||||
'@push.rocks/smartlog': 3.1.11
|
||||
'@push.rocks/smartrust': 1.2.1
|
||||
'@tsclass/tsclass': 9.3.0
|
||||
minimatch: 10.2.0
|
||||
minimatch: 10.2.1
|
||||
|
||||
'@push.rocks/smartpuppeteer@2.0.5(typescript@5.9.3)':
|
||||
dependencies:
|
||||
@@ -6830,7 +6834,7 @@ snapshots:
|
||||
'@push.rocks/smartlog-interfaces': 3.0.2
|
||||
'@tsclass/tsclass': 9.3.0
|
||||
|
||||
'@serve.zone/remoteingress@3.3.0':
|
||||
'@serve.zone/remoteingress@4.0.0':
|
||||
dependencies:
|
||||
'@push.rocks/qenv': 6.1.3
|
||||
'@push.rocks/smartrust': 1.2.1
|
||||
@@ -7362,22 +7366,22 @@ snapshots:
|
||||
'@types/body-parser@1.19.6':
|
||||
dependencies:
|
||||
'@types/connect': 3.4.38
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 25.3.0
|
||||
|
||||
'@types/buffer-json@2.0.3': {}
|
||||
|
||||
'@types/clean-css@4.2.11':
|
||||
dependencies:
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 25.3.0
|
||||
source-map: 0.6.1
|
||||
|
||||
'@types/connect@3.4.38':
|
||||
dependencies:
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 25.3.0
|
||||
|
||||
'@types/cors@2.8.19':
|
||||
dependencies:
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 25.3.0
|
||||
|
||||
'@types/debug@4.1.12':
|
||||
dependencies:
|
||||
@@ -7385,7 +7389,7 @@ snapshots:
|
||||
|
||||
'@types/express-serve-static-core@5.1.1':
|
||||
dependencies:
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 25.3.0
|
||||
'@types/qs': 6.14.0
|
||||
'@types/range-parser': 1.2.7
|
||||
'@types/send': 1.2.1
|
||||
@@ -7398,17 +7402,17 @@ snapshots:
|
||||
|
||||
'@types/from2@2.3.6':
|
||||
dependencies:
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 25.3.0
|
||||
|
||||
'@types/fs-extra@11.0.4':
|
||||
dependencies:
|
||||
'@types/jsonfile': 6.1.4
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 25.3.0
|
||||
|
||||
'@types/glob@8.1.0':
|
||||
dependencies:
|
||||
'@types/minimatch': 5.1.2
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 25.3.0
|
||||
|
||||
'@types/hast@3.0.4':
|
||||
dependencies:
|
||||
@@ -7430,12 +7434,12 @@ snapshots:
|
||||
|
||||
'@types/jsonfile@6.1.4':
|
||||
dependencies:
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 25.3.0
|
||||
|
||||
'@types/jsonwebtoken@9.0.10':
|
||||
dependencies:
|
||||
'@types/ms': 2.1.0
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 25.3.0
|
||||
|
||||
'@types/linkify-it@5.0.0': {}
|
||||
|
||||
@@ -7458,16 +7462,16 @@ snapshots:
|
||||
|
||||
'@types/mute-stream@0.0.4':
|
||||
dependencies:
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 25.3.0
|
||||
|
||||
'@types/node-fetch@2.6.13':
|
||||
dependencies:
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 25.3.0
|
||||
form-data: 4.0.5
|
||||
|
||||
'@types/node-forge@1.3.14':
|
||||
dependencies:
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 25.3.0
|
||||
|
||||
'@types/node@18.19.130':
|
||||
dependencies:
|
||||
@@ -7477,9 +7481,9 @@ snapshots:
|
||||
dependencies:
|
||||
undici-types: 6.21.0
|
||||
|
||||
'@types/node@25.2.3':
|
||||
'@types/node@25.3.0':
|
||||
dependencies:
|
||||
undici-types: 7.16.0
|
||||
undici-types: 7.18.2
|
||||
|
||||
'@types/pidusage@2.0.5': {}
|
||||
|
||||
@@ -7497,22 +7501,22 @@ snapshots:
|
||||
|
||||
'@types/send@1.2.1':
|
||||
dependencies:
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 25.3.0
|
||||
|
||||
'@types/serve-static@2.2.0':
|
||||
dependencies:
|
||||
'@types/http-errors': 2.0.5
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 25.3.0
|
||||
|
||||
'@types/symbol-tree@3.2.5': {}
|
||||
|
||||
'@types/tar-stream@3.1.4':
|
||||
dependencies:
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 25.3.0
|
||||
|
||||
'@types/through2@2.0.41':
|
||||
dependencies:
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 25.3.0
|
||||
|
||||
'@types/trusted-types@2.0.7': {}
|
||||
|
||||
@@ -7542,11 +7546,11 @@ snapshots:
|
||||
|
||||
'@types/ws@8.18.1':
|
||||
dependencies:
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 25.3.0
|
||||
|
||||
'@types/yauzl@2.10.3':
|
||||
dependencies:
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 25.3.0
|
||||
optional: true
|
||||
|
||||
'@ungap/structured-clone@1.3.0': {}
|
||||
@@ -8019,7 +8023,7 @@ snapshots:
|
||||
engine.io@6.6.4:
|
||||
dependencies:
|
||||
'@types/cors': 2.8.19
|
||||
'@types/node': 25.2.3
|
||||
'@types/node': 25.3.0
|
||||
accepts: 1.3.8
|
||||
base64id: 2.0.0
|
||||
cookie: 0.7.2
|
||||
@@ -9167,6 +9171,10 @@ snapshots:
|
||||
dependencies:
|
||||
brace-expansion: 5.0.2
|
||||
|
||||
minimatch@10.2.1:
|
||||
dependencies:
|
||||
brace-expansion: 5.0.2
|
||||
|
||||
minimatch@3.1.2:
|
||||
dependencies:
|
||||
brace-expansion: 1.1.12
|
||||
@@ -10152,7 +10160,7 @@ snapshots:
|
||||
|
||||
undici-types@6.21.0: {}
|
||||
|
||||
undici-types@7.16.0: {}
|
||||
undici-types@7.18.2: {}
|
||||
|
||||
unified@11.0.5:
|
||||
dependencies:
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@serve.zone/dcrouter',
|
||||
version: '6.13.0',
|
||||
version: '7.0.0',
|
||||
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
||||
}
|
||||
|
||||
@@ -106,6 +106,13 @@ export class CertProvisionScheduler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all in-memory backoff cache entries
|
||||
*/
|
||||
public clear(): void {
|
||||
this.backoffCache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get backoff info for UI display
|
||||
*/
|
||||
|
||||
@@ -534,6 +534,12 @@ export class DcRouter {
|
||||
|
||||
// If we have DNS challenge handlers, create SmartAcme and wire to certProvisionFunction
|
||||
if (challengeHandlers.length > 0) {
|
||||
// Stop old SmartAcme if it exists (e.g., during updateSmartProxyConfig)
|
||||
if (this.smartAcme) {
|
||||
await this.smartAcme.stop().catch(err =>
|
||||
console.error('[DcRouter] Error stopping old SmartAcme:', err)
|
||||
);
|
||||
}
|
||||
this.smartAcme = new plugins.smartacme.SmartAcme({
|
||||
accountEmail: acmeConfig?.accountEmail || this.options.tls?.contactEmail || 'admin@example.com',
|
||||
certManager: new StorageBackedCertManager(this.storageManager),
|
||||
@@ -586,6 +592,13 @@ export class DcRouter {
|
||||
};
|
||||
}
|
||||
|
||||
// When remoteIngress is enabled, the hub binary forwards tunneled connections
|
||||
// to SmartProxy with PROXY protocol v1 headers to preserve client IPs.
|
||||
if (this.options.remoteIngressConfig?.enabled) {
|
||||
smartProxyConfig.acceptProxyProtocol = true;
|
||||
smartProxyConfig.proxyIPs = ['127.0.0.1'];
|
||||
}
|
||||
|
||||
// Create SmartProxy instance
|
||||
console.log('[DcRouter] Creating SmartProxy instance with config:', JSON.stringify({
|
||||
routeCount: smartProxyConfig.routes?.length,
|
||||
@@ -937,6 +950,25 @@ export class DcRouter {
|
||||
await this.cacheDb.stop().catch(err => console.error('Error stopping CacheDb:', err));
|
||||
}
|
||||
|
||||
// Clear backoff cache in cert scheduler
|
||||
if (this.certProvisionScheduler) {
|
||||
this.certProvisionScheduler.clear();
|
||||
}
|
||||
|
||||
// Allow GC of stopped services by nulling references
|
||||
this.smartProxy = undefined;
|
||||
this.emailServer = undefined;
|
||||
this.dnsServer = undefined;
|
||||
this.metricsManager = undefined;
|
||||
this.cacheCleaner = undefined;
|
||||
this.cacheDb = undefined;
|
||||
this.tunnelManager = undefined;
|
||||
this.radiusServer = undefined;
|
||||
this.smartAcme = undefined;
|
||||
this.certProvisionScheduler = undefined;
|
||||
this.remoteIngressManager = undefined;
|
||||
this.certificateStatusMap.clear();
|
||||
|
||||
console.log('All DcRouter services stopped');
|
||||
} catch (error) {
|
||||
console.error('Error during DcRouter shutdown:', error);
|
||||
|
||||
@@ -279,6 +279,14 @@ export class MetricsManager {
|
||||
if (recipient) {
|
||||
const count = this.emailMetrics.recipients.get(recipient) || 0;
|
||||
this.emailMetrics.recipients.set(recipient, count + 1);
|
||||
|
||||
// Cap recipients map to prevent unbounded growth within a day
|
||||
if (this.emailMetrics.recipients.size > this.MAX_TOP_DOMAINS) {
|
||||
const sorted = Array.from(this.emailMetrics.recipients.entries())
|
||||
.sort((a, b) => b[1] - a[1])
|
||||
.slice(0, Math.floor(this.MAX_TOP_DOMAINS * 0.8));
|
||||
this.emailMetrics.recipients = new Map(sorted);
|
||||
}
|
||||
}
|
||||
|
||||
if (deliveryTimeMs) {
|
||||
|
||||
@@ -148,7 +148,7 @@ export class LogsHandler {
|
||||
}
|
||||
|
||||
// For follow mode, simulate real-time log streaming
|
||||
intervalId = setInterval(() => {
|
||||
intervalId = setInterval(async () => {
|
||||
const categories: Array<'smtp' | 'dns' | 'security' | 'system' | 'email'> = ['smtp', 'dns', 'security', 'system', 'email'];
|
||||
const levels: Array<'debug' | 'info' | 'warn' | 'error'> = ['info', 'warn', 'error', 'debug'];
|
||||
|
||||
@@ -171,7 +171,13 @@ export class LogsHandler {
|
||||
|
||||
const logData = JSON.stringify(logEntry);
|
||||
const encoder = new TextEncoder();
|
||||
virtualStream.sendData(encoder.encode(logData));
|
||||
try {
|
||||
await virtualStream.sendData(encoder.encode(logData));
|
||||
} catch {
|
||||
// Stream closed or errored — clean up to prevent interval leak
|
||||
clearInterval(intervalId!);
|
||||
intervalId = null;
|
||||
}
|
||||
}, 2000); // Send a log every 2 seconds
|
||||
|
||||
// TODO: Hook into actual logger events
|
||||
|
||||
@@ -100,6 +100,14 @@ export class VlanManager {
|
||||
// Cache the result
|
||||
this.normalizedMacCache.set(mac, normalized);
|
||||
|
||||
// Prevent unbounded cache growth
|
||||
if (this.normalizedMacCache.size > 10000) {
|
||||
const iterator = this.normalizedMacCache.keys();
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
this.normalizedMacCache.delete(iterator.next().value);
|
||||
}
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@serve.zone/dcrouter',
|
||||
version: '6.13.0',
|
||||
version: '7.0.0',
|
||||
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user