Compare commits

...

2 Commits

Author SHA1 Message Date
048f038e36 v4.1.1
Some checks failed
Docker (tags) / security (push) Failing after 1s
Docker (tags) / test (push) Has been skipped
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
2026-02-10 14:41:19 +00:00
e375adb80a fix(smartproxy): upgrade @push.rocks/smartproxy to ^23.1.0 and adapt code/tests for its async getStatistics() API 2026-02-10 14:41:19 +00:00
11 changed files with 197 additions and 95 deletions

View File

@@ -1,5 +1,14 @@
# Changelog # Changelog
## 2026-02-10 - 4.1.1 - fix(smartproxy)
upgrade @push.rocks/smartproxy to ^23.1.0 and adapt code/tests for its async getStatistics() API
- Bumped dependency @push.rocks/smartproxy 22.4.2 → 23.1.0 in package.json
- Changed ts/monitoring/classes.metricsmanager.ts to await smartProxy.getStatistics() (was synchronous)
- Updated multiple tests to set cacheConfig: { enabled: false } and added socketTimeouts where appropriate
- Improved SMTP test servers: handle multi-line input, drop data for packet-loss simulation, and ignore socket errors to make tests more robust
- Added migration notes to readme.hints.md documenting SmartProxy v23.1.0 changes (async getStatistics, Rust proxy behavior)
## 2026-02-10 - 4.1.0 - feat(cache) ## 2026-02-10 - 4.1.0 - feat(cache)
add persistent smartdata-backed cache with LocalTsmDb, cache cleaner, and DcRouter integration add persistent smartdata-backed cache with LocalTsmDb, cache cleaner, and DcRouter integration

View File

@@ -1,7 +1,7 @@
{ {
"name": "@serve.zone/dcrouter", "name": "@serve.zone/dcrouter",
"private": false, "private": false,
"version": "4.1.0", "version": "4.1.1",
"description": "A multifaceted routing service handling mail and SMS delivery functions.", "description": "A multifaceted routing service handling mail and SMS delivery functions.",
"type": "module", "type": "module",
"exports": { "exports": {
@@ -50,7 +50,7 @@
"@push.rocks/smartnetwork": "^4.4.0", "@push.rocks/smartnetwork": "^4.4.0",
"@push.rocks/smartpath": "^6.0.0", "@push.rocks/smartpath": "^6.0.0",
"@push.rocks/smartpromise": "^4.2.3", "@push.rocks/smartpromise": "^4.2.3",
"@push.rocks/smartproxy": "^22.4.2", "@push.rocks/smartproxy": "^23.1.0",
"@push.rocks/smartradius": "^1.1.0", "@push.rocks/smartradius": "^1.1.0",
"@push.rocks/smartrequest": "^5.0.1", "@push.rocks/smartrequest": "^5.0.1",
"@push.rocks/smartrule": "^2.0.1", "@push.rocks/smartrule": "^2.0.1",

59
pnpm-lock.yaml generated
View File

@@ -75,8 +75,8 @@ importers:
specifier: ^4.2.3 specifier: ^4.2.3
version: 4.2.3 version: 4.2.3
'@push.rocks/smartproxy': '@push.rocks/smartproxy':
specifier: ^22.4.2 specifier: ^23.1.0
version: 22.4.2(socks@2.8.7) version: 23.1.0(socks@2.8.7)
'@push.rocks/smartradius': '@push.rocks/smartradius':
specifier: ^1.1.0 specifier: ^1.1.0
version: 1.1.0 version: 1.1.0
@@ -677,6 +677,10 @@ packages:
resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==}
engines: {node: 20 || >=22} engines: {node: 20 || >=22}
'@isaacs/brace-expansion@5.0.1':
resolution: {integrity: sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==}
engines: {node: 20 || >=22}
'@isaacs/cliui@8.0.2': '@isaacs/cliui@8.0.2':
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'} engines: {node: '>=12'}
@@ -1075,8 +1079,8 @@ packages:
'@push.rocks/smartpromise@4.2.3': '@push.rocks/smartpromise@4.2.3':
resolution: {integrity: sha512-Ycg/TJR+tMt+S3wSFurOpEoW6nXv12QBtKXgBcjMZ4RsdO28geN46U09osPn9N9WuwQy1PkmTV5J/V4F9U8qEw==} resolution: {integrity: sha512-Ycg/TJR+tMt+S3wSFurOpEoW6nXv12QBtKXgBcjMZ4RsdO28geN46U09osPn9N9WuwQy1PkmTV5J/V4F9U8qEw==}
'@push.rocks/smartproxy@22.4.2': '@push.rocks/smartproxy@23.1.0':
resolution: {integrity: sha512-JdDa1VxGOnWfF5HuJRvkX3/zHuIKz+IV9n/XOsNZQA9zMZdLVlWPqjGio9GLWsPOWA2l1YZKymjMH4ybPbGQtA==} resolution: {integrity: sha512-2EhMFeQytDwnqooK9BNkLw9oz8M1LUFuMEg6271xRnwf8gUkDq5WT0brrmLdOmpqkU/3h/wDeZUrn65zq3VAcA==}
'@push.rocks/smartpuppeteer@2.0.5': '@push.rocks/smartpuppeteer@2.0.5':
resolution: {integrity: sha512-yK/qSeWVHIGWRp3c8S5tfdGP6WCKllZC4DR8d8CQlEjszOSBmHtlTdyyqOMBZ/BA4kd+eU5f3A1r4K2tGYty1g==} resolution: {integrity: sha512-yK/qSeWVHIGWRp3c8S5tfdGP6WCKllZC4DR8d8CQlEjszOSBmHtlTdyyqOMBZ/BA4kd+eU5f3A1r4K2tGYty1g==}
@@ -1099,6 +1103,9 @@ packages:
'@push.rocks/smartrule@2.0.1': '@push.rocks/smartrule@2.0.1':
resolution: {integrity: sha512-8oYEnS9z+NgCAcUtXPMguYyZpHqA/ROp0bxVQwUaHDwa3YzzA8jHIXvA94hk3sxvkk0xmIpp4UhBEelzIwwJow==} resolution: {integrity: sha512-8oYEnS9z+NgCAcUtXPMguYyZpHqA/ROp0bxVQwUaHDwa3YzzA8jHIXvA94hk3sxvkk0xmIpp4UhBEelzIwwJow==}
'@push.rocks/smartrust@1.1.1':
resolution: {integrity: sha512-NtfTOrVpw0K+z/jW24OmunvZBqkJHfe1tJhTMPFYUb4a5Yt5mtTc3oUvlX+bHarn94Jq0oh0HCLh8xcPQ2Sd7w==}
'@push.rocks/smartrx@3.0.10': '@push.rocks/smartrx@3.0.10':
resolution: {integrity: sha512-USjIYcsSfzn14cwOsxgq/bBmWDTTzy3ouWAnW5NdMyRRzEbmeNrvmy6TRqNeDlJ2PsYNTt1rr/zGUqvIy72ITg==} resolution: {integrity: sha512-USjIYcsSfzn14cwOsxgq/bBmWDTTzy3ouWAnW5NdMyRRzEbmeNrvmy6TRqNeDlJ2PsYNTt1rr/zGUqvIy72ITg==}
@@ -1160,6 +1167,9 @@ packages:
'@push.rocks/taskbuffer@3.5.0': '@push.rocks/taskbuffer@3.5.0':
resolution: {integrity: sha512-Y9WwIEIyp6oVFdj06j84tfrZIvjhbMb3DF52rYxlTeYLk3W7RPhSg1bGPCbtkXWeKdBrSe37V90BkOG7Qq8Pqg==} resolution: {integrity: sha512-Y9WwIEIyp6oVFdj06j84tfrZIvjhbMb3DF52rYxlTeYLk3W7RPhSg1bGPCbtkXWeKdBrSe37V90BkOG7Qq8Pqg==}
'@push.rocks/taskbuffer@4.2.0':
resolution: {integrity: sha512-ttoBe5y/WXkAo5/wSMcC/Y4Zbyw4XG8kwAsEaqnAPCxa3M9MI1oV/yM1e9gU1IH97HVPidzbTxRU5/PcHDdUsg==}
'@push.rocks/webrequest@3.0.37': '@push.rocks/webrequest@3.0.37':
resolution: {integrity: sha512-fLN7kP6GeHFxE4UH4r9C9pjcQb0QkJxHeAMwXvbOqB9hh0MFNKhtGU7GoaTn8SVRGRMPc9UqZVNwo6u5l8Wn0A==} resolution: {integrity: sha512-fLN7kP6GeHFxE4UH4r9C9pjcQb0QkJxHeAMwXvbOqB9hh0MFNKhtGU7GoaTn8SVRGRMPc9UqZVNwo6u5l8Wn0A==}
@@ -3336,6 +3346,10 @@ packages:
resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==}
engines: {node: 20 || >=22} engines: {node: 20 || >=22}
minimatch@10.1.2:
resolution: {integrity: sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==}
engines: {node: 20 || >=22}
minimatch@3.1.2: minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
@@ -5551,6 +5565,10 @@ snapshots:
dependencies: dependencies:
'@isaacs/balanced-match': 4.0.1 '@isaacs/balanced-match': 4.0.1
'@isaacs/brace-expansion@5.0.1':
dependencies:
'@isaacs/balanced-match': 4.0.1
'@isaacs/cliui@8.0.2': '@isaacs/cliui@8.0.2':
dependencies: dependencies:
string-width: 5.1.2 string-width: 5.1.2
@@ -6513,7 +6531,7 @@ snapshots:
'@push.rocks/smartpromise@4.2.3': {} '@push.rocks/smartpromise@4.2.3': {}
'@push.rocks/smartproxy@22.4.2(socks@2.8.7)': '@push.rocks/smartproxy@23.1.0(socks@2.8.7)':
dependencies: dependencies:
'@push.rocks/lik': 6.2.2 '@push.rocks/lik': 6.2.2
'@push.rocks/smartacme': 8.0.0(socks@2.8.7) '@push.rocks/smartacme': 8.0.0(socks@2.8.7)
@@ -6524,13 +6542,14 @@ snapshots:
'@push.rocks/smartnetwork': 4.4.0 '@push.rocks/smartnetwork': 4.4.0
'@push.rocks/smartpromise': 4.2.3 '@push.rocks/smartpromise': 4.2.3
'@push.rocks/smartrequest': 5.0.1 '@push.rocks/smartrequest': 5.0.1
'@push.rocks/smartrust': 1.1.1
'@push.rocks/smartrx': 3.0.10 '@push.rocks/smartrx': 3.0.10
'@push.rocks/smartstring': 4.1.0 '@push.rocks/smartstring': 4.1.0
'@push.rocks/taskbuffer': 3.5.0 '@push.rocks/taskbuffer': 4.2.0
'@tsclass/tsclass': 9.3.0 '@tsclass/tsclass': 9.3.0
'@types/minimatch': 6.0.0 '@types/minimatch': 6.0.0
'@types/ws': 8.18.1 '@types/ws': 8.18.1
minimatch: 10.1.1 minimatch: 10.1.2
pretty-ms: 9.3.0 pretty-ms: 9.3.0
ws: 8.19.0 ws: 8.19.0
transitivePeerDependencies: transitivePeerDependencies:
@@ -6604,6 +6623,10 @@ snapshots:
'@push.rocks/smartrule@2.0.1': {} '@push.rocks/smartrule@2.0.1': {}
'@push.rocks/smartrust@1.1.1':
dependencies:
'@push.rocks/smartpath': 6.0.0
'@push.rocks/smartrx@3.0.10': '@push.rocks/smartrx@3.0.10':
dependencies: dependencies:
'@push.rocks/smartpromise': 4.2.3 '@push.rocks/smartpromise': 4.2.3
@@ -6775,6 +6798,22 @@ snapshots:
- supports-color - supports-color
- vue - vue
'@push.rocks/taskbuffer@4.2.0':
dependencies:
'@design.estate/dees-element': 2.1.6
'@push.rocks/lik': 6.2.2
'@push.rocks/smartdelay': 3.0.5
'@push.rocks/smartlog': 3.1.10
'@push.rocks/smartpromise': 4.2.3
'@push.rocks/smartrx': 3.0.10
'@push.rocks/smarttime': 4.1.1
'@push.rocks/smartunique': 3.0.9
transitivePeerDependencies:
- '@nuxt/kit'
- react
- supports-color
- vue
'@push.rocks/webrequest@3.0.37': '@push.rocks/webrequest@3.0.37':
dependencies: dependencies:
'@push.rocks/smartdelay': 3.0.5 '@push.rocks/smartdelay': 3.0.5
@@ -7631,7 +7670,7 @@ snapshots:
'@types/minimatch@6.0.0': '@types/minimatch@6.0.0':
dependencies: dependencies:
minimatch: 10.1.1 minimatch: 10.1.2
'@types/ms@2.1.0': {} '@types/ms@2.1.0': {}
@@ -9397,6 +9436,10 @@ snapshots:
dependencies: dependencies:
'@isaacs/brace-expansion': 5.0.0 '@isaacs/brace-expansion': 5.0.0
minimatch@10.1.2:
dependencies:
'@isaacs/brace-expansion': 5.0.1
minimatch@3.1.2: minimatch@3.1.2:
dependencies: dependencies:
brace-expansion: 1.1.12 brace-expansion: 1.1.12

View File

@@ -1,5 +1,28 @@
# Implementation Hints and Learnings # Implementation Hints and Learnings
## Dependency Upgrade (2026-02-10)
### SmartProxy v23.1.0 Upgrade
- `@push.rocks/smartproxy`: 22.4.2 → 23.1.0
**Key Changes:**
- Rust-based proxy components for improved performance
- Rust binary runs as separate process via IPC
- `getStatistics()` now returns `Promise<any>` (was synchronous)
- nftables-proxy removed (not used by dcrouter)
**Code Changes Required:**
```typescript
// Old (synchronous)
const proxyStats = this.dcRouter.smartProxy.getStatistics();
// New (async)
const proxyStats = await this.dcRouter.smartProxy.getStatistics();
```
**Files Modified:**
- `ts/monitoring/classes.metricsmanager.ts` - Added `await` to `getStatistics()` call
## Dependency Upgrade (2026-02-01) ## Dependency Upgrade (2026-02-01)
### Major Upgrades Completed ### Major Upgrades Completed

View File

@@ -197,25 +197,15 @@ tap.test('CERR-03: Network Failures - should handle EHOSTUNREACH', async () => {
}); });
tap.test('CERR-03: Network Failures - should handle packet loss simulation', async () => { tap.test('CERR-03: Network Failures - should handle packet loss simulation', async () => {
// Create a server that randomly drops data // Create a server that sends a greeting but never responds to commands,
let packetCount = 0; // simulating complete packet loss after the initial connection.
const lossyServer = net.createServer((socket) => { const lossyServer = net.createServer((socket) => {
socket.on('error', () => {});
socket.write('220 Lossy server ready\r\n'); socket.write('220 Lossy server ready\r\n');
socket.on('data', (data) => { // Never respond to any commands - simulates total packet loss
packetCount++; socket.on('data', () => {
// Intentionally drop all data to simulate packet loss
// Simulate 30% packet loss
if (Math.random() > 0.3) {
const command = data.toString().trim();
if (command.startsWith('EHLO')) {
socket.write('250 OK\r\n');
} else if (command === 'QUIT') {
socket.write('221 Bye\r\n');
socket.end();
}
}
// Otherwise, don't respond (simulate packet loss)
}); });
}); });
@@ -227,8 +217,8 @@ tap.test('CERR-03: Network Failures - should handle packet loss simulation', asy
host: 'localhost', host: 'localhost',
port: 2558, port: 2558,
secure: false, secure: false,
connectionTimeout: 1000, connectionTimeout: 2000,
socketTimeout: 1000 // Short timeout to detect loss socketTimeout: 2000 // Short timeout to detect loss
}); });
let verifyResult = false; let verifyResult = false;
@@ -237,16 +227,16 @@ tap.test('CERR-03: Network Failures - should handle packet loss simulation', asy
try { try {
verifyResult = await client.verify(); verifyResult = await client.verify();
if (verifyResult) { if (verifyResult) {
console.log('Connected despite simulated packet loss'); console.log('Connection succeeded unexpectedly');
} else { } else {
console.log('✅ Connection failed due to packet loss'); console.log('✅ Connection failed due to packet loss');
} }
} catch (error) { } catch (error) {
errorOccurred = true; errorOccurred = true;
console.log(`✅ Packet loss detected after ${packetCount} packets: ${error.message}`); console.log(`✅ Packet loss detected: ${error.message}`);
} }
// Either verification failed or an error occurred - both are expected with packet loss // verify() must have returned false or thrown - both indicate packet loss was detected
expect(!verifyResult || errorOccurred).toBeTrue(); expect(!verifyResult || errorOccurred).toBeTrue();
// Clean up client first // Clean up client first

View File

@@ -19,10 +19,13 @@ tap.test('setup - start SMTP server for greylisting tests', async () => {
tap.test('CERR-04: Basic greylisting response handling', async () => { tap.test('CERR-04: Basic greylisting response handling', async () => {
// Create server that simulates greylisting // Create server that simulates greylisting
const greylistServer = net.createServer((socket) => { const greylistServer = net.createServer((socket) => {
socket.on('error', () => {});
socket.write('220 Greylist Test Server\r\n'); socket.write('220 Greylist Test Server\r\n');
socket.on('data', (data) => { socket.on('data', (data) => {
const command = data.toString().trim(); const lines = data.toString().split('\r\n').filter((l: string) => l.trim());
for (const line of lines) {
const command = line.trim();
if (command.startsWith('EHLO') || command.startsWith('HELO')) { if (command.startsWith('EHLO') || command.startsWith('HELO')) {
socket.write('250 OK\r\n'); socket.write('250 OK\r\n');
@@ -31,12 +34,17 @@ tap.test('CERR-04: Basic greylisting response handling', async () => {
} else if (command.startsWith('RCPT TO')) { } else if (command.startsWith('RCPT TO')) {
// Simulate greylisting response // Simulate greylisting response
socket.write('451 4.7.1 Greylisting in effect, please retry later\r\n'); socket.write('451 4.7.1 Greylisting in effect, please retry later\r\n');
} else if (command.startsWith('RSET')) {
socket.write('250 OK\r\n');
} else if (command.startsWith('DATA')) {
socket.write('503 Bad sequence of commands\r\n');
} else if (command === 'QUIT') { } else if (command === 'QUIT') {
socket.write('221 Bye\r\n'); socket.write('221 Bye\r\n');
socket.end(); socket.end();
} else { } else if (command.length > 0) {
socket.write('250 OK\r\n'); socket.write('250 OK\r\n');
} }
}
}); });
}); });
@@ -48,7 +56,8 @@ tap.test('CERR-04: Basic greylisting response handling', async () => {
host: '127.0.0.1', host: '127.0.0.1',
port: 2560, port: 2560,
secure: false, secure: false,
connectionTimeout: 5000 connectionTimeout: 5000,
socketTimeout: 5000
}); });
const email = new Email({ const email = new Email({
@@ -107,20 +116,30 @@ tap.test('CERR-04: Different greylisting response codes', async () => {
tap.test('CERR-04: Greylisting with temporary failure', async () => { tap.test('CERR-04: Greylisting with temporary failure', async () => {
// Create server that sends 450 response (temporary failure) // Create server that sends 450 response (temporary failure)
const tempFailServer = net.createServer((socket) => { const tempFailServer = net.createServer((socket) => {
socket.on('error', () => {});
socket.write('220 Temp Fail Server\r\n'); socket.write('220 Temp Fail Server\r\n');
socket.on('data', (data) => { socket.on('data', (data) => {
const command = data.toString().trim(); const lines = data.toString().split('\r\n').filter((l: string) => l.trim());
for (const line of lines) {
const command = line.trim();
if (command.startsWith('EHLO')) { if (command.startsWith('EHLO') || command.startsWith('HELO')) {
socket.write('250 OK\r\n'); socket.write('250 OK\r\n');
} else if (command.startsWith('MAIL FROM')) { } else if (command.startsWith('MAIL FROM')) {
socket.write('250 OK\r\n'); socket.write('250 OK\r\n');
} else if (command.startsWith('RCPT TO')) { } else if (command.startsWith('RCPT TO')) {
socket.write('450 4.7.1 Mailbox temporarily unavailable\r\n'); socket.write('450 4.7.1 Mailbox temporarily unavailable\r\n');
} else if (command.startsWith('RSET')) {
socket.write('250 OK\r\n');
} else if (command.startsWith('DATA')) {
socket.write('503 Bad sequence of commands\r\n');
} else if (command === 'QUIT') { } else if (command === 'QUIT') {
socket.write('221 Bye\r\n'); socket.write('221 Bye\r\n');
socket.end(); socket.end();
} else if (command.length > 0) {
socket.write('250 OK\r\n');
}
} }
}); });
}); });
@@ -133,7 +152,8 @@ tap.test('CERR-04: Greylisting with temporary failure', async () => {
host: '127.0.0.1', host: '127.0.0.1',
port: 2561, port: 2561,
secure: false, secure: false,
connectionTimeout: 5000 connectionTimeout: 5000,
socketTimeout: 5000
}); });
const email = new Email({ const email = new Email({
@@ -199,20 +219,30 @@ tap.test('CERR-04: Basic connection verification', async () => {
tap.test('CERR-04: Server with RCPT rejection', async () => { tap.test('CERR-04: Server with RCPT rejection', async () => {
// Test server rejecting at RCPT TO stage // Test server rejecting at RCPT TO stage
const rejectServer = net.createServer((socket) => { const rejectServer = net.createServer((socket) => {
socket.on('error', () => {});
socket.write('220 Reject Server\r\n'); socket.write('220 Reject Server\r\n');
socket.on('data', (data) => { socket.on('data', (data) => {
const command = data.toString().trim(); const lines = data.toString().split('\r\n').filter((l: string) => l.trim());
for (const line of lines) {
const command = line.trim();
if (command.startsWith('EHLO')) { if (command.startsWith('EHLO') || command.startsWith('HELO')) {
socket.write('250 OK\r\n'); socket.write('250 OK\r\n');
} else if (command.startsWith('MAIL FROM')) { } else if (command.startsWith('MAIL FROM')) {
socket.write('250 OK\r\n'); socket.write('250 OK\r\n');
} else if (command.startsWith('RCPT TO')) { } else if (command.startsWith('RCPT TO')) {
socket.write('451 4.2.1 Recipient rejected temporarily\r\n'); socket.write('451 4.2.1 Recipient rejected temporarily\r\n');
} else if (command.startsWith('RSET')) {
socket.write('250 OK\r\n');
} else if (command.startsWith('DATA')) {
socket.write('503 Bad sequence of commands\r\n');
} else if (command === 'QUIT') { } else if (command === 'QUIT') {
socket.write('221 Bye\r\n'); socket.write('221 Bye\r\n');
socket.end(); socket.end();
} else if (command.length > 0) {
socket.write('250 OK\r\n');
}
} }
}); });
}); });
@@ -225,7 +255,8 @@ tap.test('CERR-04: Server with RCPT rejection', async () => {
host: '127.0.0.1', host: '127.0.0.1',
port: 2562, port: 2562,
secure: false, secure: false,
connectionTimeout: 5000 connectionTimeout: 5000,
socketTimeout: 5000
}); });
const email = new Email({ const email = new Email({

View File

@@ -8,7 +8,8 @@ tap.test('should NOT instantiate DNS server when dnsNsDomains is not set', async
dcRouter = new DcRouter({ dcRouter = new DcRouter({
smartProxyConfig: { smartProxyConfig: {
routes: [] routes: []
} },
cacheConfig: { enabled: false }
}); });
await dcRouter.start(); await dcRouter.start();

View File

@@ -15,7 +15,8 @@ tap.test('should use traditional port forwarding when useSocketHandler is false'
}, },
smartProxyConfig: { smartProxyConfig: {
routes: [] routes: []
} },
cacheConfig: { enabled: false }
}); });
await dcRouter.start(); await dcRouter.start();
@@ -51,7 +52,8 @@ tap.test('should use socket-handler mode when useSocketHandler is true', async (
}, },
smartProxyConfig: { smartProxyConfig: {
routes: [] routes: []
} },
cacheConfig: { enabled: false }
}); });
await dcRouter.start(); await dcRouter.start();
@@ -85,7 +87,7 @@ tap.test('should generate correct email routes for each port', async () => {
useSocketHandler: true useSocketHandler: true
}; };
dcRouter = new DcRouter({ emailConfig }); dcRouter = new DcRouter({ emailConfig, cacheConfig: { enabled: false } });
// Access the private method to generate routes // Access the private method to generate routes
const emailRoutes = (dcRouter as any).generateEmailRoutes(emailConfig); const emailRoutes = (dcRouter as any).generateEmailRoutes(emailConfig);
@@ -119,7 +121,8 @@ tap.test('email socket handler should handle different ports correctly', async (
domains: ['test.local'], domains: ['test.local'],
routes: [], routes: [],
useSocketHandler: true useSocketHandler: true
} },
cacheConfig: { enabled: false }
}); });
await dcRouter.start(); await dcRouter.start();
@@ -145,7 +148,8 @@ tap.test('email server handleSocket method should work', async () => {
domains: ['test.local'], domains: ['test.local'],
routes: [], routes: [],
useSocketHandler: true useSocketHandler: true
} },
cacheConfig: { enabled: false }
}); });
await dcRouter.start(); await dcRouter.start();
@@ -182,7 +186,8 @@ tap.test('should not create SMTP servers when useSocketHandler is true', async (
domains: ['test.local'], domains: ['test.local'],
routes: [], routes: [],
useSocketHandler: true useSocketHandler: true
} },
cacheConfig: { enabled: false }
}); });
await dcRouter.start(); await dcRouter.start();
@@ -209,7 +214,7 @@ tap.test('TLS handling should differ between ports', async () => {
useSocketHandler: false // Use traditional mode to check TLS config useSocketHandler: false // Use traditional mode to check TLS config
}; };
dcRouter = new DcRouter({ emailConfig }); dcRouter = new DcRouter({ emailConfig, cacheConfig: { enabled: false } });
const emailRoutes = (dcRouter as any).generateEmailRoutes(emailConfig); const emailRoutes = (dcRouter as any).generateEmailRoutes(emailConfig);

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@serve.zone/dcrouter', name: '@serve.zone/dcrouter',
version: '4.1.0', version: '4.1.1',
description: 'A multifaceted routing service handling mail and SMS delivery functions.' description: 'A multifaceted routing service handling mail and SMS delivery functions.'
} }

View File

@@ -123,7 +123,7 @@ export class MetricsManager {
return this.metricsCache.get('serverStats', async () => { return this.metricsCache.get('serverStats', async () => {
const smartMetricsData = await this.smartMetrics.getMetrics(); const smartMetricsData = await this.smartMetrics.getMetrics();
const proxyMetrics = this.dcRouter.smartProxy ? this.dcRouter.smartProxy.getMetrics() : null; const proxyMetrics = this.dcRouter.smartProxy ? this.dcRouter.smartProxy.getMetrics() : null;
const proxyStats = this.dcRouter.smartProxy ? this.dcRouter.smartProxy.getStatistics() : null; const proxyStats = this.dcRouter.smartProxy ? await this.dcRouter.smartProxy.getStatistics() : null;
return { return {
uptime: process.uptime(), uptime: process.uptime(),

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@serve.zone/dcrouter', name: '@serve.zone/dcrouter',
version: '4.1.0', version: '4.1.1',
description: 'A multifaceted routing service handling mail and SMS delivery functions.' description: 'A multifaceted routing service handling mail and SMS delivery functions.'
} }