Compare commits

...

2 Commits

Author SHA1 Message Date
Juergen Kunz
26f7431111 fix(docs): update documentation to improve clarity
Some checks failed
Default (tags) / security (push) Successful in 51s
Default (tags) / test (push) Failing after 31m10s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-07-21 12:23:22 +00:00
Juergen Kunz
aa6ddbc4a6 BREAKING_CHANGE(routing): refactor route configuration to support multiple targets
Some checks failed
Default (tags) / security (push) Successful in 53s
Default (tags) / test (push) Failing after 31m2s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-07-21 08:52:07 +00:00
52 changed files with 3500 additions and 2608 deletions

View File

@@ -1,5 +1,5 @@
{ {
"expiryDate": "2025-10-01T02:31:27.435Z", "expiryDate": "2025-10-18T13:15:48.916Z",
"issueDate": "2025-07-03T02:31:27.435Z", "issueDate": "2025-07-20T13:15:48.916Z",
"savedAt": "2025-07-03T02:31:27.435Z" "savedAt": "2025-07-20T13:15:48.916Z"
} }

View File

@@ -1,5 +1,21 @@
# Changelog # Changelog
## 2025-07-21 - 20.0.2 - fix(docs)
Update documentation to improve clarity
- Enhanced readme with clearer breaking change warning for v20.0.0
- Fixed example email address from ssl@bleu.de to ssl@example.com
- Added load balancing and failover features to feature list
- Improved documentation structure and examples
## 2025-07-20 - 20.0.1 - BREAKING_CHANGE(routing)
Refactor route configuration to support multiple targets
- Changed route action configuration from single `target` to `targets` array
- Enables load balancing and failover capabilities with multiple upstream targets
- Updated all test files to use new `targets` array syntax
- Automatic certificate metadata refresh
## 2025-06-01 - 19.5.19 - fix(smartproxy) ## 2025-06-01 - 19.5.19 - fix(smartproxy)
Fix connection handling and improve route matching edge cases Fix connection handling and improve route matching edge cases

View File

@@ -1,6 +1,6 @@
{ {
"name": "@push.rocks/smartproxy", "name": "@push.rocks/smartproxy",
"version": "19.6.17", "version": "20.0.2",
"private": false, "private": false,
"description": "A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.", "description": "A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.",
"main": "dist_ts/index.js", "main": "dist_ts/index.js",
@@ -51,7 +51,8 @@
"assets/**/*", "assets/**/*",
"cli.js", "cli.js",
"npmextra.json", "npmextra.json",
"readme.md" "readme.md",
"changelog.md"
], ],
"browserslist": [ "browserslist": [
"last 1 chrome versions" "last 1 chrome versions"

3026
readme.md

File diff suppressed because it is too large Load Diff

2749
test-output.log Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -32,14 +32,14 @@ tap.test('PathMatcher - wildcard matching', async () => {
const result = PathMatcher.match('/api/*', '/api/users/123/profile'); const result = PathMatcher.match('/api/*', '/api/users/123/profile');
expect(result.matches).toEqual(true); expect(result.matches).toEqual(true);
expect(result.pathMatch).toEqual('/api'); // Normalized without trailing slash expect(result.pathMatch).toEqual('/api'); // Normalized without trailing slash
expect(result.pathRemainder).toEqual('users/123/profile'); expect(result.pathRemainder).toEqual('/users/123/profile');
}); });
tap.test('PathMatcher - mixed parameters and wildcards', async () => { tap.test('PathMatcher - mixed parameters and wildcards', async () => {
const result = PathMatcher.match('/api/:version/*', '/api/v1/users/123'); const result = PathMatcher.match('/api/:version/*', '/api/v1/users/123');
expect(result.matches).toEqual(true); expect(result.matches).toEqual(true);
expect(result.params).toEqual({ version: 'v1' }); expect(result.params).toEqual({ version: 'v1' });
expect(result.pathRemainder).toEqual('users/123'); expect(result.pathRemainder).toEqual('/users/123');
}); });
tap.test('PathMatcher - trailing slash normalization', async () => { tap.test('PathMatcher - trailing slash normalization', async () => {

View File

@@ -58,7 +58,7 @@ tap.test('Shared Security Manager', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'target.com', port: 443 } targets: [{ host: 'target.com', port: 443 }]
}, },
security: { security: {
ipAllowList: ['10.0.0.*', '192.168.1.*'], ipAllowList: ['10.0.0.*', '192.168.1.*'],
@@ -113,7 +113,7 @@ tap.test('Shared Security Manager', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'target.com', port: 443 } targets: [{ host: 'target.com', port: 443 }]
}, },
security: { security: {
rateLimit: { rateLimit: {

View File

@@ -59,7 +59,7 @@ tap.test('should create ACME challenge route', async (tools) => {
}, },
action: { action: {
type: 'forward' as const, type: 'forward' as const,
target: { host: 'localhost', port: 8080 } targets: [{ host: 'localhost', port: 8080 }]
} }
}, },
challengeRoute challengeRoute

View File

@@ -18,7 +18,7 @@ tap.test('should defer certificate provisioning until ports are ready', async (t
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 8181 }, targets: [{ host: 'localhost', port: 8181 }],
tls: { tls: {
mode: 'terminate', mode: 'terminate',
certificate: 'auto', certificate: 'auto',

View File

@@ -30,7 +30,7 @@ tap.test('should defer certificate provisioning until after ports are listening'
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 8181 }, targets: [{ host: 'localhost', port: 8181 }],
tls: { tls: {
mode: 'terminate', mode: 'terminate',
certificate: 'auto', certificate: 'auto',
@@ -126,7 +126,7 @@ tap.test('should have ACME challenge route ready before certificate provisioning
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 8181 }, targets: [{ host: 'localhost', port: 8181 }],
tls: { tls: {
mode: 'terminate', mode: 'terminate',
certificate: 'auto' certificate: 'auto'

View File

@@ -16,10 +16,10 @@ tap.test('SmartCertManager should call getCertificateForDomain with wildcard opt
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 8080 port: 8080
}, }],
tls: { tls: {
mode: 'terminate', mode: 'terminate',
certificate: 'auto', certificate: 'auto',

View File

@@ -59,10 +59,10 @@ tap.test('SmartProxy should support custom certificate provision function', asyn
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 8080 port: 8080
}, }],
tls: { tls: {
mode: 'terminate', mode: 'terminate',
certificate: 'auto' certificate: 'auto'
@@ -109,10 +109,10 @@ tap.test('Custom certificate provision function should be called', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 8080 port: 8080
}, }],
tls: { tls: {
mode: 'terminate', mode: 'terminate',
certificate: 'auto' certificate: 'auto'
@@ -172,10 +172,10 @@ tap.test('Should fallback to ACME when custom provision fails', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 8080 port: 8080
}, }],
tls: { tls: {
mode: 'terminate', mode: 'terminate',
certificate: 'auto' certificate: 'auto'
@@ -231,10 +231,10 @@ tap.test('Should not fallback when certProvisionFallbackToAcme is false', async
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 8080 port: 8080
}, }],
tls: { tls: {
mode: 'terminate', mode: 'terminate',
certificate: 'auto' certificate: 'auto'
@@ -310,10 +310,10 @@ tap.test('Should return http01 for unknown domains', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 8080 port: 8080
}, }],
tls: { tls: {
mode: 'terminate', mode: 'terminate',
certificate: 'auto' certificate: 'auto'

View File

@@ -7,7 +7,7 @@ const testProxy = new SmartProxy({
match: { ports: 9443, domains: 'test.local' }, match: { ports: 9443, domains: 'test.local' },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 8080 }, targets: [{ host: 'localhost', port: 8080 }],
tls: { tls: {
mode: 'terminate', mode: 'terminate',
certificate: 'auto', certificate: 'auto',
@@ -67,7 +67,7 @@ tap.test('should handle static certificates', async () => {
match: { ports: 9444, domains: 'static.example.com' }, match: { ports: 9444, domains: 'static.example.com' },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 8080 }, targets: [{ host: 'localhost', port: 8080 }],
tls: { tls: {
mode: 'terminate', mode: 'terminate',
certificate: { certificate: {
@@ -96,7 +96,7 @@ tap.test('should handle ACME challenge routes', async () => {
match: { ports: 9445, domains: 'acme.local' }, match: { ports: 9445, domains: 'acme.local' },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 8080 }, targets: [{ host: 'localhost', port: 8080 }],
tls: { tls: {
mode: 'terminate', mode: 'terminate',
certificate: 'auto', certificate: 'auto',
@@ -112,7 +112,7 @@ tap.test('should handle ACME challenge routes', async () => {
match: { ports: 9081, domains: 'acme.local' }, match: { ports: 9081, domains: 'acme.local' },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 8080 } targets: [{ host: 'localhost', port: 8080 }]
} }
}], }],
acme: { acme: {
@@ -167,7 +167,7 @@ tap.test('should renew certificates', async () => {
match: { ports: 9446, domains: 'renew.local' }, match: { ports: 9446, domains: 'renew.local' },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 8080 }, targets: [{ host: 'localhost', port: 8080 }],
tls: { tls: {
mode: 'terminate', mode: 'terminate',
certificate: 'auto', certificate: 'auto',

View File

@@ -8,7 +8,7 @@ tap.test('should create SmartProxy with certificate routes', async () => {
match: { ports: 8443, domains: 'test.example.com' }, match: { ports: 8443, domains: 'test.example.com' },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 8080 }, targets: [{ host: 'localhost', port: 8080 }],
tls: { tls: {
mode: 'terminate', mode: 'terminate',
certificate: 'auto', certificate: 'auto',

View File

@@ -13,7 +13,7 @@ tap.test('cleanup queue bug - verify queue processing handles more than batch si
match: { ports: 8588 }, match: { ports: 8588 },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 9996 } targets: [{ host: 'localhost', port: 9996 }]
} }
}], }],
enableDetailedLogging: false, enableDetailedLogging: false,

View File

@@ -18,10 +18,10 @@ tap.test('should handle clients that connect and immediately disconnect without
match: { ports: 8560 }, match: { ports: 8560 },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 9999 // Non-existent port port: 9999 // Non-existent port
} }]
} }
}] }]
}); });
@@ -173,10 +173,10 @@ tap.test('should handle clients that error during connection', async () => {
match: { ports: 8561 }, match: { ports: 8561 },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 9999 port: 9999
} }]
} }
}] }]
}); });

View File

@@ -20,10 +20,10 @@ tap.test('comprehensive connection cleanup test - all scenarios', async () => {
match: { ports: 8570 }, match: { ports: 8570 },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 9999 // Non-existent port port: 9999 // Non-existent port
} }]
} }
}, },
{ {
@@ -31,10 +31,10 @@ tap.test('comprehensive connection cleanup test - all scenarios', async () => {
match: { ports: 8571 }, match: { ports: 8571 },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 9999 // Non-existent port port: 9999 // Non-existent port
}, }],
tls: { tls: {
mode: 'passthrough' mode: 'passthrough'
} }
@@ -215,10 +215,10 @@ tap.test('comprehensive connection cleanup test - all scenarios', async () => {
action: { action: {
type: 'forward', type: 'forward',
forwardingEngine: 'nftables', forwardingEngine: 'nftables',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 9999 port: 9999
} }]
} }
}] }]
}); });

View File

@@ -65,10 +65,10 @@ tap.test('should forward TCP connections correctly', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: '127.0.0.1', host: '127.0.0.1',
port: 7001, port: 7001,
}, }],
}, },
}, },
], ],
@@ -118,10 +118,10 @@ tap.test('should handle TLS passthrough correctly', async () => {
tls: { tls: {
mode: 'passthrough', mode: 'passthrough',
}, },
target: { targets: [{
host: '127.0.0.1', host: '127.0.0.1',
port: 7002, port: 7002,
}, }],
}, },
}, },
], ],
@@ -179,10 +179,10 @@ tap.test('should handle SNI-based forwarding', async () => {
tls: { tls: {
mode: 'passthrough', mode: 'passthrough',
}, },
target: { targets: [{
host: '127.0.0.1', host: '127.0.0.1',
port: 7002, port: 7002,
}, }],
}, },
}, },
{ {
@@ -197,10 +197,10 @@ tap.test('should handle SNI-based forwarding', async () => {
tls: { tls: {
mode: 'passthrough', mode: 'passthrough',
}, },
target: { targets: [{
host: '127.0.0.1', host: '127.0.0.1',
port: 7002, port: 7002,
}, }],
}, },
}, },
], ],

View File

@@ -90,10 +90,10 @@ tap.test('Setup test environment', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: TEST_SERVER_PORT port: TEST_SERVER_PORT
} }]
}, },
security: { security: {
maxConnections: 5 // Low limit for testing maxConnections: 5 // Low limit for testing
@@ -198,10 +198,10 @@ tap.test('HttpProxy per-IP validation', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: TEST_SERVER_PORT port: TEST_SERVER_PORT
}, }],
tls: { tls: {
mode: 'terminate' mode: 'terminate'
} }

View File

@@ -9,7 +9,7 @@ tap.test('should verify certificate manager callback is preserved on updateRoute
match: { ports: [18443], domains: ['test.local'] }, match: { ports: [18443], domains: ['test.local'] },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 3000 }, targets: [{ host: 'localhost', port: 3000 }],
tls: { tls: {
mode: 'terminate', mode: 'terminate',
certificate: 'auto', certificate: 'auto',
@@ -63,7 +63,7 @@ tap.test('should verify certificate manager callback is preserved on updateRoute
match: { ports: [18444], domains: ['test2.local'] }, match: { ports: [18444], domains: ['test2.local'] },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 3001 }, targets: [{ host: 'localhost', port: 3001 }],
tls: { tls: {
mode: 'terminate', mode: 'terminate',
certificate: 'auto', certificate: 'auto',

View File

@@ -37,7 +37,7 @@ tap.test('regular forward route should work correctly', async () => {
match: { ports: 7890 }, match: { ports: 7890 },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 6789 } targets: [{ host: 'localhost', port: 6789 }]
} }
}] }]
}); });
@@ -106,7 +106,7 @@ tap.skip.test('NFTables forward route should not terminate connections (requires
action: { action: {
type: 'forward', type: 'forward',
forwardingEngine: 'nftables', forwardingEngine: 'nftables',
target: { host: 'localhost', port: 6789 } targets: [{ host: 'localhost', port: 6789 }]
} }
}] }]
}); });

View File

@@ -39,10 +39,10 @@ tap.test('forward connections should not be immediately closed', async (t) => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: '127.0.0.1', host: '127.0.0.1',
port: 9090, port: 9090,
}, }],
}, },
}, },
], ],

View File

@@ -39,7 +39,7 @@ tap.test('Route Helpers - Create HTTP routes', async () => {
const route = helpers.httpOnly('example.com', { host: 'localhost', port: 3000 }); const route = helpers.httpOnly('example.com', { host: 'localhost', port: 3000 });
expect(route.action.type).toEqual('forward'); expect(route.action.type).toEqual('forward');
expect(route.match.domains).toEqual('example.com'); expect(route.match.domains).toEqual('example.com');
expect(route.action.target).toEqual({ host: 'localhost', port: 3000 }); expect(route.action.targets?.[0]).toEqual({ host: 'localhost', port: 3000 });
}); });
tap.test('Route Helpers - Create HTTPS terminate to HTTP routes', async () => { tap.test('Route Helpers - Create HTTPS terminate to HTTP routes', async () => {

View File

@@ -20,7 +20,7 @@ tap.test('should forward non-TLS connections on HttpProxy ports', async (tapTest
match: { ports: testPort }, match: { ports: testPort },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 8181 } targets: [{ host: 'localhost', port: 8181 }]
} }
}] }]
}; };
@@ -81,7 +81,7 @@ tap.test('should use direct connection for non-HttpProxy ports', async (tapTest)
match: { ports: 8080 }, // Not in useHttpProxy match: { ports: 8080 }, // Not in useHttpProxy
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 8181 } targets: [{ host: 'localhost', port: 8181 }]
} }
}] }]
}; };
@@ -142,7 +142,7 @@ tap.test('should handle ACME HTTP-01 challenges on port 80 with HttpProxy', asyn
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 8080 } targets: [{ host: 'localhost', port: 8080 }]
} }
}] }]
}; };

View File

@@ -14,7 +14,7 @@ tap.test('should detect and forward non-TLS connections on useHttpProxy ports',
match: { ports: 8080 }, match: { ports: 8080 },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 8181 } targets: [{ host: 'localhost', port: 8181 }]
} }
}] }]
}; };
@@ -140,7 +140,7 @@ tap.test('should handle TLS connections normally', async (tapTest) => {
match: { ports: 443 }, match: { ports: 443 },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 8443 }, targets: [{ host: 'localhost', port: 8443 }],
tls: { mode: 'terminate' } tls: { mode: 'terminate' }
} }
}] }]

View File

@@ -17,7 +17,7 @@ tap.test('should detect and forward non-TLS connections on HttpProxy ports', asy
match: { ports: 8081 }, match: { ports: 8081 },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 8181 } targets: [{ host: 'localhost', port: 8181 }]
} }
}] }]
}); });
@@ -120,7 +120,7 @@ tap.test('should properly detect non-TLS connections on HttpProxy ports', async
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: targetPort } targets: [{ host: 'localhost', port: targetPort }]
} }
}] }]
}); });

View File

@@ -42,7 +42,7 @@ tap.test('should forward HTTP connections on port 8080', async (tapTest) => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: targetPort } targets: [{ host: 'localhost', port: targetPort }]
} }
}] }]
}); });
@@ -131,7 +131,7 @@ tap.test('should handle basic HTTP request forwarding', async (tapTest) => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: targetPort } targets: [{ host: 'localhost', port: targetPort }]
} }
}] }]
}); });

View File

@@ -67,7 +67,7 @@ tap.test('should handle ACME challenges on port 8080 with improved port binding
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: targetPort }, targets: [{ host: 'localhost', port: targetPort }],
tls: { tls: {
mode: 'terminate', mode: 'terminate',
certificate: 'auto' // Use ACME for certificate certificate: 'auto' // Use ACME for certificate
@@ -83,7 +83,7 @@ tap.test('should handle ACME challenges on port 8080 with improved port binding
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: targetPort } targets: [{ host: 'localhost', port: targetPort }]
} }
} }
], ],
@@ -191,7 +191,7 @@ tap.test('should handle ACME challenges on port 8080 with improved port binding
}, },
action: { action: {
type: 'forward' as const, type: 'forward' as const,
target: { host: 'localhost', port: targetPort } targets: [{ host: 'localhost', port: targetPort }]
} }
} }
]; ];

View File

@@ -95,10 +95,10 @@ tap.test('should support static host/port routes', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: serverPort port: serverPort
} }]
} }
} }
]; ];
@@ -135,13 +135,13 @@ tap.test('should support function-based host', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: (context: IRouteContext) => { host: (context: IRouteContext) => {
// Return localhost always in this test // Return localhost always in this test
return 'localhost'; return 'localhost';
}, },
port: serverPort port: serverPort
} }]
} }
} }
]; ];
@@ -178,13 +178,13 @@ tap.test('should support function-based port', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: (context: IRouteContext) => { port: (context: IRouteContext) => {
// Return test server port // Return test server port
return serverPort; return serverPort;
} }
} }]
} }
} }
]; ];
@@ -221,14 +221,14 @@ tap.test('should support function-based host AND port', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: (context: IRouteContext) => { host: (context: IRouteContext) => {
return 'localhost'; return 'localhost';
}, },
port: (context: IRouteContext) => { port: (context: IRouteContext) => {
return serverPort; return serverPort;
} }
} }]
} }
} }
]; ];
@@ -265,7 +265,7 @@ tap.test('should support context-based routing with path', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: (context: IRouteContext) => { host: (context: IRouteContext) => {
// Use path to determine host // Use path to determine host
if (context.path?.startsWith('/api')) { if (context.path?.startsWith('/api')) {
@@ -275,7 +275,7 @@ tap.test('should support context-based routing with path', async () => {
} }
}, },
port: serverPort port: serverPort
} }]
} }
} }
]; ];

View File

@@ -40,7 +40,7 @@ tap.test('keepalive support - verify keepalive connections are properly handled'
match: { ports: 8590 }, match: { ports: 8590 },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 9998 } targets: [{ host: 'localhost', port: 9998 }]
} }
}], }],
keepAlive: true, keepAlive: true,
@@ -117,7 +117,7 @@ tap.test('keepalive support - verify keepalive connections are properly handled'
match: { ports: 8591 }, match: { ports: 8591 },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 9998 } targets: [{ host: 'localhost', port: 9998 }]
} }
}], }],
keepAlive: true, keepAlive: true,
@@ -178,7 +178,7 @@ tap.test('keepalive support - verify keepalive connections are properly handled'
match: { ports: 8592 }, match: { ports: 8592 },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 9998 } targets: [{ host: 'localhost', port: 9998 }]
} }
}], }],
keepAlive: true, keepAlive: true,

View File

@@ -39,10 +39,10 @@ tap.test('setup test environment', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 9876 port: 9876
} }]
// No TLS configuration - just plain TCP forwarding // No TLS configuration - just plain TCP forwarding
} }
}], }],

View File

@@ -36,10 +36,10 @@ tap.test('should create SmartProxy instance with new metrics', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: echoServerPort port: echoServerPort
}, }],
tls: { tls: {
mode: 'passthrough' mode: 'passthrough'
} }

View File

@@ -34,10 +34,10 @@ tap.skip.test('NFTables forwarding should not terminate connections (requires ro
action: { action: {
type: 'forward', type: 'forward',
forwardingEngine: 'nftables', forwardingEngine: 'nftables',
target: { targets: [{
host: '127.0.0.1', host: '127.0.0.1',
port: 8001, port: 8001,
}, }],
}, },
}, },
// Also add regular forwarding route for comparison // Also add regular forwarding route for comparison
@@ -49,10 +49,10 @@ tap.skip.test('NFTables forwarding should not terminate connections (requires ro
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: '127.0.0.1', host: '127.0.0.1',
port: 8001, port: 8001,
}, }],
}, },
}, },
], ],

View File

@@ -42,10 +42,10 @@ const sampleRoute: IRouteConfig = {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 8000 port: 8000
}, }],
forwardingEngine: 'nftables', forwardingEngine: 'nftables',
nftables: { nftables: {
protocol: 'tcp', protocol: 'tcp',
@@ -115,10 +115,10 @@ tap.skip.test('NFTablesManager route updating test', async () => {
...sampleRoute, ...sampleRoute,
action: { action: {
...sampleRoute.action, ...sampleRoute.action,
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 9000 // Different port port: 9000 // Different port
}, }],
nftables: { nftables: {
...sampleRoute.action.nftables, ...sampleRoute.action.nftables,
protocol: 'all' // Different protocol protocol: 'all' // Different protocol
@@ -147,10 +147,10 @@ tap.skip.test('NFTablesManager route deprovisioning test', async () => {
...sampleRoute, ...sampleRoute,
action: { action: {
...sampleRoute.action, ...sampleRoute.action,
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 9000 // Different port from original test port: 9000 // Different port from original test
}, }],
nftables: { nftables: {
...sampleRoute.action.nftables, ...sampleRoute.action.nftables,
protocol: 'all' // Different protocol from original test protocol: 'all' // Different protocol from original test

View File

@@ -91,7 +91,7 @@ testFn('SmartProxy getNfTablesStatus functionality', async () => {
match: { ports: 3004 }, match: { ports: 3004 },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 3005 } targets: [{ host: 'localhost', port: 3005 }]
} }
} }
] ]

View File

@@ -29,7 +29,7 @@ tap.test('port forwarding should not immediately close connections', async (tool
match: { ports: 9999 }, match: { ports: 9999 },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 8888 } targets: [{ host: 'localhost', port: 8888 }]
} }
}] }]
}); });
@@ -63,7 +63,7 @@ tap.test('TLS passthrough should work correctly', async () => {
action: { action: {
type: 'forward', type: 'forward',
tls: { mode: 'passthrough' }, tls: { mode: 'passthrough' },
target: { host: 'localhost', port: 443 } targets: [{ host: 'localhost', port: 443 }]
} }
}] }]
}); });

View File

@@ -214,12 +214,12 @@ tap.test('should handle errors in port mapping functions', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: () => { port: () => {
throw new Error('Test error in port mapping function'); throw new Error('Test error in port mapping function');
} }
} }]
}, },
name: 'Error Route' name: 'Error Route'
}; };

View File

@@ -21,7 +21,7 @@ tap.test('should not double-register port 80 when user route and ACME use same p
}, },
action: { action: {
type: 'forward' as const, type: 'forward' as const,
target: { host: 'localhost', port: 3000 } targets: [{ host: 'localhost', port: 3000 }]
} }
}, },
{ {
@@ -31,7 +31,7 @@ tap.test('should not double-register port 80 when user route and ACME use same p
}, },
action: { action: {
type: 'forward' as const, type: 'forward' as const,
target: { host: 'localhost', port: 3001 }, targets: [{ host: 'localhost', port: 3001 }],
tls: { tls: {
mode: 'terminate' as const, mode: 'terminate' as const,
certificate: 'auto' as const certificate: 'auto' as const
@@ -153,7 +153,7 @@ tap.test('should handle ACME on different port than user routes', async (tools)
}, },
action: { action: {
type: 'forward' as const, type: 'forward' as const,
target: { host: 'localhost', port: 3000 } targets: [{ host: 'localhost', port: 3000 }]
} }
}, },
{ {
@@ -163,7 +163,7 @@ tap.test('should handle ACME on different port than user routes', async (tools)
}, },
action: { action: {
type: 'forward' as const, type: 'forward' as const,
target: { host: 'localhost', port: 3001 }, targets: [{ host: 'localhost', port: 3001 }],
tls: { tls: {
mode: 'terminate' as const, mode: 'terminate' as const,
certificate: 'auto' as const certificate: 'auto' as const

View File

@@ -15,10 +15,10 @@ tap.test('setup two smartproxies in a chain configuration', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'httpbin.org', host: 'httpbin.org',
port: 443 port: 443
} }]
} }
} }
], ],
@@ -45,10 +45,10 @@ tap.test('setup two smartproxies in a chain configuration', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 8002 port: 8002
}, }],
sendProxyProtocol: true sendProxyProtocol: true
} }
} }

View File

@@ -32,10 +32,10 @@ tap.test('simple proxy chain test - identify connection accumulation', async ()
match: { ports: 8591 }, match: { ports: 8591 },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 9998 // Backend that closes immediately port: 9998 // Backend that closes immediately
} }]
} }
}] }]
}); });
@@ -50,10 +50,10 @@ tap.test('simple proxy chain test - identify connection accumulation', async ()
match: { ports: 8590 }, match: { ports: 8590 },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 8591 // Forward to proxy2 port: 8591 // Forward to proxy2
} }]
} }
}] }]
}); });

View File

@@ -19,10 +19,10 @@ tap.test('should handle proxy chaining without connection accumulation', async (
match: { ports: 8581 }, match: { ports: 8581 },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 9999 // Non-existent backend port: 9999 // Non-existent backend
} }]
} }
}] }]
}); });
@@ -37,10 +37,10 @@ tap.test('should handle proxy chaining without connection accumulation', async (
match: { ports: 8580 }, match: { ports: 8580 },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 8581 // Forward to proxy2 port: 8581 // Forward to proxy2
} }]
} }
}] }]
}); });
@@ -270,10 +270,10 @@ tap.test('should handle proxy chain with HTTP traffic', async () => {
match: { ports: 8583 }, match: { ports: 8583 },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 9999 // Non-existent backend port: 9999 // Non-existent backend
} }]
} }
}] }]
}); });
@@ -289,10 +289,10 @@ tap.test('should handle proxy chain with HTTP traffic', async () => {
match: { ports: 8582 }, match: { ports: 8582 },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 8583 // Forward to proxy2 port: 8583 // Forward to proxy2
} }]
} }
}] }]
}); });

View File

@@ -19,10 +19,10 @@ tap.test('should handle rapid connection retries without leaking connections', a
match: { ports: 8550 }, match: { ports: 8550 },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 9999 // Non-existent port to force connection failures port: 9999 // Non-existent port to force connection failures
} }]
} }
}] }]
}); });

View File

@@ -17,7 +17,7 @@ tap.test('should set update routes callback on certificate manager', async () =>
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 3000 }, targets: [{ host: 'localhost', port: 3000 }],
tls: { tls: {
mode: 'terminate', mode: 'terminate',
certificate: 'auto', certificate: 'auto',
@@ -95,7 +95,7 @@ tap.test('should set update routes callback on certificate manager', async () =>
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 3001 }, targets: [{ host: 'localhost', port: 3001 }],
tls: { tls: {
mode: 'terminate', mode: 'terminate',
certificate: 'auto', certificate: 'auto',

View File

@@ -28,10 +28,10 @@ tap.test('route security should block connections from unauthorized IPs', async
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: '127.0.0.1', host: '127.0.0.1',
port: 9990 port: 9990
} }]
}, },
security: { security: {
// Only allow a non-existent IP // Only allow a non-existent IP
@@ -142,10 +142,10 @@ tap.test('route security with block list should work', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: '127.0.0.1', host: '127.0.0.1',
port: 9992 port: 9992
} }]
}, },
security: { // Security at route level, not action level security: { // Security at route level, not action level
ipBlockList: ['127.0.0.1', '::1', '::ffff:127.0.0.1'] ipBlockList: ['127.0.0.1', '::1', '::ffff:127.0.0.1']
@@ -234,10 +234,10 @@ tap.test('route without security should allow all connections', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: '127.0.0.1', host: '127.0.0.1',
port: 9994 port: 9994
} }]
} }
// No security defined // No security defined
}]; }];

View File

@@ -10,10 +10,10 @@ tap.test('route security should be correctly configured', async () => {
}, },
action: { action: {
type: 'forward' as const, type: 'forward' as const,
target: { targets: [{
host: '127.0.0.1', host: '127.0.0.1',
port: 8991 port: 8991
}, }],
security: { security: {
ipAllowList: ['192.168.1.1'], ipAllowList: ['192.168.1.1'],
ipBlockList: ['10.0.0.1'] ipBlockList: ['10.0.0.1']

View File

@@ -26,10 +26,10 @@ tap.test('route-specific security should be enforced', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: '127.0.0.1', host: '127.0.0.1',
port: 8877 port: 8877
} }]
}, },
security: { security: {
ipAllowList: ['127.0.0.1', '::1', '::ffff:127.0.0.1'] ipAllowList: ['127.0.0.1', '::1', '::ffff:127.0.0.1']
@@ -108,10 +108,10 @@ tap.test('route-specific IP block list should be enforced', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: '127.0.0.1', host: '127.0.0.1',
port: 8879 port: 8879
} }]
}, },
security: { security: {
ipAllowList: ['0.0.0.0/0', '::/0'], // Allow all IPs ipAllowList: ['0.0.0.0/0', '::/0'], // Allow all IPs
@@ -215,10 +215,10 @@ tap.test('routes without security should allow all connections', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: '127.0.0.1', host: '127.0.0.1',
port: 8881 port: 8881
} }]
// No security section - should allow all // No security section - should allow all
} }
}]; }];

View File

@@ -13,10 +13,10 @@ const createRoute = (id: number, domain: string, port: number = 8443) => ({
}, },
action: { action: {
type: 'forward' as const, type: 'forward' as const,
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 3000 + id port: 3000 + id
}, }],
tls: { tls: {
mode: 'terminate' as const, mode: 'terminate' as const,
certificate: 'auto' as const, certificate: 'auto' as const,
@@ -209,10 +209,10 @@ tap.test('should handle route updates when cert manager is not initialized', asy
}, },
action: { action: {
type: 'forward' as const, type: 'forward' as const,
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 3000 port: 3000
} }]
} }
}] }]
}); });

View File

@@ -37,10 +37,10 @@ function createRouteConfig(
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: destinationIp, host: destinationIp,
port: destinationPort port: destinationPort
} }]
} }
}; };
} }

View File

@@ -15,10 +15,10 @@ tap.test('should create a SmartCertManager instance', async () => {
}, },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 3000 port: 3000
}, }],
tls: { tls: {
mode: 'terminate', mode: 'terminate',
certificate: 'auto', certificate: 'auto',

View File

@@ -30,7 +30,7 @@ tap.test('stuck connection cleanup - verify connections to hanging backends are
match: { ports: 8589 }, match: { ports: 8589 },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 9997 } targets: [{ host: 'localhost', port: 9997 }]
} }
}], }],
keepAlive: true, keepAlive: true,

View File

@@ -17,7 +17,7 @@ tap.test('websocket keep-alive settings for SNI passthrough', async (tools) => {
match: { ports: 8443, domains: 'test.local' }, match: { ports: 8443, domains: 'test.local' },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 9443 }, targets: [{ host: 'localhost', port: 9443 }],
tls: { mode: 'passthrough' } tls: { mode: 'passthrough' }
} }
} }
@@ -108,7 +108,7 @@ tap.test('long-lived connection survival test', async (tools) => {
match: { ports: 8444 }, match: { ports: 8444 },
action: { action: {
type: 'forward', type: 'forward',
target: { host: 'localhost', port: 9444 } targets: [{ host: 'localhost', port: 9444 }]
} }
} }
] ]

View File

@@ -52,10 +52,10 @@ tap.test('zombie connection cleanup - verify inactivity check detects and cleans
match: { ports: 8591 }, match: { ports: 8591 },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 9998 port: 9998
} }]
} }
}] }]
}); });
@@ -71,10 +71,10 @@ tap.test('zombie connection cleanup - verify inactivity check detects and cleans
match: { ports: 8590 }, match: { ports: 8590 },
action: { action: {
type: 'forward', type: 'forward',
target: { targets: [{
host: 'localhost', host: 'localhost',
port: 8591 port: 8591
} }]
} }
}] }]
}); });