Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e0af82c1ef | |||
| efe3d80713 | |||
| 6b04bc612b | |||
| e774ec87ca | |||
| cbde778f09 | |||
| bc2bc874a5 |
26
changelog.md
26
changelog.md
@@ -1,5 +1,31 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2026-02-13 - 23.1.6 - fix(smart-proxy)
|
||||||
|
disable built-in Rust ACME when a certProvisionFunction is provided and improve certificate provisioning flow
|
||||||
|
|
||||||
|
- Pass an optional ACME override into buildRustConfig so Rust ACME can be disabled per-run
|
||||||
|
- Disable Rust ACME when certProvisionFunction is configured to avoid provisioning race conditions
|
||||||
|
- Normalize routing glob patterns into concrete domain identifiers for certificate provisioning (expand leading-star globs and warn on unsupported patterns)
|
||||||
|
- Deduplicate domains during provisioning to avoid repeated attempts
|
||||||
|
- When the callback returns 'http01', explicitly trigger Rust ACME for the route via bridge.provisionCertificate and log success/failure
|
||||||
|
|
||||||
|
## 2026-02-13 - 23.1.5 - fix(smart-proxy)
|
||||||
|
provision certificates for wildcard domains instead of skipping them
|
||||||
|
|
||||||
|
- Removed early continue that skipped domains containing '*' in the domain loop
|
||||||
|
- Now calls provisionFn for wildcard domains so certificate provisioning can proceed for wildcard hosts
|
||||||
|
- Fixes cases where wildcard domains never had certificates requested
|
||||||
|
|
||||||
|
## 2026-02-12 - 23.1.4 - fix(tests)
|
||||||
|
make tests more robust and bump small dependencies
|
||||||
|
|
||||||
|
- Bump dependencies: @push.rocks/smartrust ^1.2.1 and minimatch ^10.2.0
|
||||||
|
- Replace hardcoded ports with named constants (ECHO_PORT, PROXY_PORT, PROXY_PORT_1/2) to avoid collisions between tests
|
||||||
|
- Add server 'error' handlers and reject listen promises on server errors to prevent silent hangs
|
||||||
|
- Reduce test timeouts and intervals (shorter test durations, more frequent pings) to speed up test runs
|
||||||
|
- Ensure proxy is stopped between tests and remove forced process.exit; export tap.start() consistently
|
||||||
|
- Adjust assertions to match the new shorter ping/response counts
|
||||||
|
|
||||||
## 2026-02-12 - 23.1.3 - fix(rustproxy)
|
## 2026-02-12 - 23.1.3 - fix(rustproxy)
|
||||||
install default rustls crypto provider early; detect and skip raw fast-path for HTTP connections and return proper HTTP 502 when no route matches
|
install default rustls crypto provider early; detect and skip raw fast-path for HTTP connections and return proper HTTP 502 when no route matches
|
||||||
|
|
||||||
|
|||||||
73
deno.lock
generated
73
deno.lock
generated
@@ -14,7 +14,7 @@
|
|||||||
"npm:@push.rocks/smartnetwork@^4.4.0": "4.4.0",
|
"npm:@push.rocks/smartnetwork@^4.4.0": "4.4.0",
|
||||||
"npm:@push.rocks/smartpromise@^4.2.3": "4.2.3",
|
"npm:@push.rocks/smartpromise@^4.2.3": "4.2.3",
|
||||||
"npm:@push.rocks/smartrequest@^5.0.1": "5.0.1",
|
"npm:@push.rocks/smartrequest@^5.0.1": "5.0.1",
|
||||||
"npm:@push.rocks/smartrust@^1.2.0": "1.2.0",
|
"npm:@push.rocks/smartrust@^1.2.1": "1.2.1",
|
||||||
"npm:@push.rocks/smartrx@^3.0.10": "3.0.10",
|
"npm:@push.rocks/smartrx@^3.0.10": "3.0.10",
|
||||||
"npm:@push.rocks/smartserve@^2.0.1": "2.0.1",
|
"npm:@push.rocks/smartserve@^2.0.1": "2.0.1",
|
||||||
"npm:@push.rocks/smartstring@^4.1.0": "4.1.0",
|
"npm:@push.rocks/smartstring@^4.1.0": "4.1.0",
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
"npm:@types/minimatch@6": "6.0.0",
|
"npm:@types/minimatch@6": "6.0.0",
|
||||||
"npm:@types/node@^25.2.3": "25.2.3",
|
"npm:@types/node@^25.2.3": "25.2.3",
|
||||||
"npm:@types/ws@^8.18.1": "8.18.1",
|
"npm:@types/ws@^8.18.1": "8.18.1",
|
||||||
"npm:minimatch@^10.1.2": "10.1.2",
|
"npm:minimatch@^10.2.0": "10.2.0",
|
||||||
"npm:pretty-ms@^9.3.0": "9.3.0",
|
"npm:pretty-ms@^9.3.0": "9.3.0",
|
||||||
"npm:typescript@^5.9.3": "5.9.3",
|
"npm:typescript@^5.9.3": "5.9.3",
|
||||||
"npm:why-is-node-running@^3.2.2": "3.2.2",
|
"npm:why-is-node-running@^3.2.2": "3.2.2",
|
||||||
@@ -57,17 +57,13 @@
|
|||||||
"integrity": "sha512-dcp0oXsjBL+XdFg1wUUP08uJQid5bQ0Yv3V3Y3lnI2QCbat0FU+Tsb0TZRnZ4+P150Vj/ITBqJUgDzFsF34grA==",
|
"integrity": "sha512-dcp0oXsjBL+XdFg1wUUP08uJQid5bQ0Yv3V3Y3lnI2QCbat0FU+Tsb0TZRnZ4+P150Vj/ITBqJUgDzFsF34grA==",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"@api.global/typedrequest",
|
"@api.global/typedrequest",
|
||||||
"@api.global/typedrequest-interfaces@3.0.19",
|
|
||||||
"@api.global/typedsocket@3.1.1",
|
"@api.global/typedsocket@3.1.1",
|
||||||
"@cloudflare/workers-types",
|
"@cloudflare/workers-types",
|
||||||
"@design.estate/dees-comms",
|
"@design.estate/dees-comms",
|
||||||
"@push.rocks/lik",
|
"@push.rocks/lik",
|
||||||
"@push.rocks/smartchok",
|
"@push.rocks/smartchok",
|
||||||
"@push.rocks/smartdelay",
|
"@push.rocks/smartdelay",
|
||||||
"@push.rocks/smartenv@5.0.13",
|
|
||||||
"@push.rocks/smartfeed",
|
"@push.rocks/smartfeed",
|
||||||
"@push.rocks/smartfile@11.2.7",
|
|
||||||
"@push.rocks/smartjson@5.2.0",
|
|
||||||
"@push.rocks/smartlog",
|
"@push.rocks/smartlog",
|
||||||
"@push.rocks/smartlog-destination-devtools",
|
"@push.rocks/smartlog-destination-devtools",
|
||||||
"@push.rocks/smartlog-interfaces",
|
"@push.rocks/smartlog-interfaces",
|
||||||
@@ -76,17 +72,12 @@
|
|||||||
"@push.rocks/smartmime",
|
"@push.rocks/smartmime",
|
||||||
"@push.rocks/smartntml",
|
"@push.rocks/smartntml",
|
||||||
"@push.rocks/smartopen",
|
"@push.rocks/smartopen",
|
||||||
"@push.rocks/smartpath@6.0.0",
|
|
||||||
"@push.rocks/smartpromise",
|
"@push.rocks/smartpromise",
|
||||||
"@push.rocks/smartrequest@4.4.2",
|
|
||||||
"@push.rocks/smartrx",
|
"@push.rocks/smartrx",
|
||||||
"@push.rocks/smartsitemap",
|
"@push.rocks/smartsitemap",
|
||||||
"@push.rocks/smartstream",
|
"@push.rocks/smartstream",
|
||||||
"@push.rocks/smarttime",
|
"@push.rocks/smarttime",
|
||||||
"@push.rocks/taskbuffer@3.5.0",
|
|
||||||
"@push.rocks/webrequest@3.0.37",
|
|
||||||
"@push.rocks/webstore",
|
"@push.rocks/webstore",
|
||||||
"@tsclass/tsclass@9.3.0",
|
|
||||||
"@types/express",
|
"@types/express",
|
||||||
"body-parser",
|
"body-parser",
|
||||||
"cors",
|
"cors",
|
||||||
@@ -143,9 +134,7 @@
|
|||||||
"integrity": "sha512-Wkz3NlhmfdZMKqXXI2c2dMtGGmSmhdOegZiziL+9b2mqPYdc7Gd8AZRdEOKvbSoIvc9G22/5BEadIWHrfq66TA==",
|
"integrity": "sha512-Wkz3NlhmfdZMKqXXI2c2dMtGGmSmhdOegZiziL+9b2mqPYdc7Gd8AZRdEOKvbSoIvc9G22/5BEadIWHrfq66TA==",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"@api.global/typedrequest",
|
"@api.global/typedrequest",
|
||||||
"@api.global/typedrequest-interfaces@3.0.19",
|
|
||||||
"@push.rocks/isohash",
|
"@push.rocks/isohash",
|
||||||
"@push.rocks/smartjson@5.2.0",
|
|
||||||
"@push.rocks/smartrx",
|
"@push.rocks/smartrx",
|
||||||
"@push.rocks/smartserve",
|
"@push.rocks/smartserve",
|
||||||
"@push.rocks/smartsocket@2.1.0",
|
"@push.rocks/smartsocket@2.1.0",
|
||||||
@@ -1305,17 +1294,6 @@
|
|||||||
],
|
],
|
||||||
"tarball": "https://verdaccio.lossless.digital/@inquirer/type/-/type-2.0.0.tgz"
|
"tarball": "https://verdaccio.lossless.digital/@inquirer/type/-/type-2.0.0.tgz"
|
||||||
},
|
},
|
||||||
"@isaacs/balanced-match@4.0.1": {
|
|
||||||
"integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==",
|
|
||||||
"tarball": "https://verdaccio.lossless.digital/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz"
|
|
||||||
},
|
|
||||||
"@isaacs/brace-expansion@5.0.1": {
|
|
||||||
"integrity": "sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==",
|
|
||||||
"dependencies": [
|
|
||||||
"@isaacs/balanced-match"
|
|
||||||
],
|
|
||||||
"tarball": "https://verdaccio.lossless.digital/@isaacs/brace-expansion/-/brace-expansion-5.0.1.tgz"
|
|
||||||
},
|
|
||||||
"@isaacs/cliui@9.0.0": {
|
"@isaacs/cliui@9.0.0": {
|
||||||
"integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==",
|
"integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==",
|
||||||
"tarball": "https://verdaccio.lossless.digital/@isaacs/cliui/-/cliui-9.0.0.tgz"
|
"tarball": "https://verdaccio.lossless.digital/@isaacs/cliui/-/cliui-9.0.0.tgz"
|
||||||
@@ -1748,7 +1726,7 @@
|
|||||||
"@push.rocks/smartstring",
|
"@push.rocks/smartstring",
|
||||||
"@push.rocks/smartunique",
|
"@push.rocks/smartunique",
|
||||||
"@tsclass/tsclass@9.3.0",
|
"@tsclass/tsclass@9.3.0",
|
||||||
"minimatch@10.1.2"
|
"minimatch@10.2.0"
|
||||||
],
|
],
|
||||||
"tarball": "https://verdaccio.lossless.digital/@push.rocks/smartbucket/-/smartbucket-4.4.1.tgz"
|
"tarball": "https://verdaccio.lossless.digital/@push.rocks/smartbucket/-/smartbucket-4.4.1.tgz"
|
||||||
},
|
},
|
||||||
@@ -1853,7 +1831,7 @@
|
|||||||
"acme-client",
|
"acme-client",
|
||||||
"dns-packet",
|
"dns-packet",
|
||||||
"elliptic",
|
"elliptic",
|
||||||
"minimatch@10.1.2"
|
"minimatch@10.2.0"
|
||||||
],
|
],
|
||||||
"tarball": "https://verdaccio.lossless.digital/@push.rocks/smartdns/-/smartdns-6.2.2.tgz"
|
"tarball": "https://verdaccio.lossless.digital/@push.rocks/smartdns/-/smartdns-6.2.2.tgz"
|
||||||
},
|
},
|
||||||
@@ -1869,7 +1847,7 @@
|
|||||||
"@types/dns-packet",
|
"@types/dns-packet",
|
||||||
"acme-client",
|
"acme-client",
|
||||||
"dns-packet",
|
"dns-packet",
|
||||||
"minimatch@10.1.2"
|
"minimatch@10.2.0"
|
||||||
],
|
],
|
||||||
"tarball": "https://verdaccio.lossless.digital/@push.rocks/smartdns/-/smartdns-7.8.0.tgz"
|
"tarball": "https://verdaccio.lossless.digital/@push.rocks/smartdns/-/smartdns-7.8.0.tgz"
|
||||||
},
|
},
|
||||||
@@ -2259,12 +2237,12 @@
|
|||||||
],
|
],
|
||||||
"tarball": "https://verdaccio.lossless.digital/@push.rocks/smartrouter/-/smartrouter-1.3.3.tgz"
|
"tarball": "https://verdaccio.lossless.digital/@push.rocks/smartrouter/-/smartrouter-1.3.3.tgz"
|
||||||
},
|
},
|
||||||
"@push.rocks/smartrust@1.2.0": {
|
"@push.rocks/smartrust@1.2.1": {
|
||||||
"integrity": "sha512-JlaALselIHoP6C3ceQbrvz424G21cND/QsH/KI3E/JrO4XphJiGZwM6f4yJWrijdPYR/YYMoaIiYN7ybZp0C4w==",
|
"integrity": "sha512-ANwXXibUwoHNWF1hhXhXVVrfzYlhgHYRa2205Jkd/s/wXzcWHftYZthilJj+52B7nkzSB76umfxKfK5eBYY2Ug==",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"@push.rocks/smartpath@6.0.0"
|
"@push.rocks/smartpath@6.0.0"
|
||||||
],
|
],
|
||||||
"tarball": "https://verdaccio.lossless.digital/@push.rocks/smartrust/-/smartrust-1.2.0.tgz"
|
"tarball": "https://verdaccio.lossless.digital/@push.rocks/smartrust/-/smartrust-1.2.1.tgz"
|
||||||
},
|
},
|
||||||
"@push.rocks/smartrx@3.0.10": {
|
"@push.rocks/smartrx@3.0.10": {
|
||||||
"integrity": "sha512-USjIYcsSfzn14cwOsxgq/bBmWDTTzy3ouWAnW5NdMyRRzEbmeNrvmy6TRqNeDlJ2PsYNTt1rr/zGUqvIy72ITg==",
|
"integrity": "sha512-USjIYcsSfzn14cwOsxgq/bBmWDTTzy3ouWAnW5NdMyRRzEbmeNrvmy6TRqNeDlJ2PsYNTt1rr/zGUqvIy72ITg==",
|
||||||
@@ -2325,7 +2303,6 @@
|
|||||||
"@push.rocks/smartsocket@2.1.0": {
|
"@push.rocks/smartsocket@2.1.0": {
|
||||||
"integrity": "sha512-etOGyfiDFQz/1WJnD3jFL2N7ykujTjiudAz6qZTz82xE5oabKuKX+Cn8SdM9dOwzyWmBUKbUdll8QhovAXjn+g==",
|
"integrity": "sha512-etOGyfiDFQz/1WJnD3jFL2N7ykujTjiudAz6qZTz82xE5oabKuKX+Cn8SdM9dOwzyWmBUKbUdll8QhovAXjn+g==",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"@api.global/typedrequest-interfaces@3.0.19",
|
|
||||||
"@api.global/typedserver@3.0.80",
|
"@api.global/typedserver@3.0.80",
|
||||||
"@push.rocks/isohash",
|
"@push.rocks/isohash",
|
||||||
"@push.rocks/isounique",
|
"@push.rocks/isounique",
|
||||||
@@ -3507,7 +3484,7 @@
|
|||||||
"@types/minimatch@6.0.0": {
|
"@types/minimatch@6.0.0": {
|
||||||
"integrity": "sha512-zmPitbQ8+6zNutpwgcQuLcsEpn/Cj54Kbn7L5pX0Os5kdWplB7xPgEh/g+SWOB/qmows2gpuCaPyduq8ZZRnxA==",
|
"integrity": "sha512-zmPitbQ8+6zNutpwgcQuLcsEpn/Cj54Kbn7L5pX0Os5kdWplB7xPgEh/g+SWOB/qmows2gpuCaPyduq8ZZRnxA==",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"minimatch@10.1.2"
|
"minimatch@10.2.0"
|
||||||
],
|
],
|
||||||
"deprecated": true,
|
"deprecated": true,
|
||||||
"tarball": "https://verdaccio.lossless.digital/@types/minimatch/-/minimatch-6.0.0.tgz"
|
"tarball": "https://verdaccio.lossless.digital/@types/minimatch/-/minimatch-6.0.0.tgz"
|
||||||
@@ -3809,6 +3786,13 @@
|
|||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||||
"tarball": "https://verdaccio.lossless.digital/balanced-match/-/balanced-match-1.0.2.tgz"
|
"tarball": "https://verdaccio.lossless.digital/balanced-match/-/balanced-match-1.0.2.tgz"
|
||||||
},
|
},
|
||||||
|
"balanced-match@4.0.2": {
|
||||||
|
"integrity": "sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg==",
|
||||||
|
"dependencies": [
|
||||||
|
"jackspeak"
|
||||||
|
],
|
||||||
|
"tarball": "https://verdaccio.lossless.digital/balanced-match/-/balanced-match-4.0.2.tgz"
|
||||||
|
},
|
||||||
"bare-events@2.8.2": {
|
"bare-events@2.8.2": {
|
||||||
"integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==",
|
"integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==",
|
||||||
"tarball": "https://verdaccio.lossless.digital/bare-events/-/bare-events-2.8.2.tgz"
|
"tarball": "https://verdaccio.lossless.digital/bare-events/-/bare-events-2.8.2.tgz"
|
||||||
@@ -3891,7 +3875,7 @@
|
|||||||
"brace-expansion@1.1.12": {
|
"brace-expansion@1.1.12": {
|
||||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"balanced-match",
|
"balanced-match@1.0.2",
|
||||||
"concat-map"
|
"concat-map"
|
||||||
],
|
],
|
||||||
"tarball": "https://verdaccio.lossless.digital/brace-expansion/-/brace-expansion-1.1.12.tgz"
|
"tarball": "https://verdaccio.lossless.digital/brace-expansion/-/brace-expansion-1.1.12.tgz"
|
||||||
@@ -3899,10 +3883,17 @@
|
|||||||
"brace-expansion@2.0.2": {
|
"brace-expansion@2.0.2": {
|
||||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"balanced-match"
|
"balanced-match@1.0.2"
|
||||||
],
|
],
|
||||||
"tarball": "https://verdaccio.lossless.digital/brace-expansion/-/brace-expansion-2.0.2.tgz"
|
"tarball": "https://verdaccio.lossless.digital/brace-expansion/-/brace-expansion-2.0.2.tgz"
|
||||||
},
|
},
|
||||||
|
"brace-expansion@5.0.2": {
|
||||||
|
"integrity": "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==",
|
||||||
|
"dependencies": [
|
||||||
|
"balanced-match@4.0.2"
|
||||||
|
],
|
||||||
|
"tarball": "https://verdaccio.lossless.digital/brace-expansion/-/brace-expansion-5.0.2.tgz"
|
||||||
|
},
|
||||||
"broadcast-channel@7.3.0": {
|
"broadcast-channel@7.3.0": {
|
||||||
"integrity": "sha512-UHPhLBQKfQ8OmMFMpmPfO5dRakyA1vsfiDGWTYNvChYol65tbuhivPEGgZZiuetorvExdvxaWiBy/ym1Ty08yA==",
|
"integrity": "sha512-UHPhLBQKfQ8OmMFMpmPfO5dRakyA1vsfiDGWTYNvChYol65tbuhivPEGgZZiuetorvExdvxaWiBy/ym1Ty08yA==",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
@@ -4823,7 +4814,7 @@
|
|||||||
"dependencies": [
|
"dependencies": [
|
||||||
"foreground-child@3.3.1",
|
"foreground-child@3.3.1",
|
||||||
"jackspeak",
|
"jackspeak",
|
||||||
"minimatch@10.1.2",
|
"minimatch@10.2.0",
|
||||||
"minipass",
|
"minipass",
|
||||||
"package-json-from-dist",
|
"package-json-from-dist",
|
||||||
"path-scurry"
|
"path-scurry"
|
||||||
@@ -5862,12 +5853,12 @@
|
|||||||
"integrity": "f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a",
|
"integrity": "f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a",
|
||||||
"tarball": "https://verdaccio.lossless.digital/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz"
|
"tarball": "https://verdaccio.lossless.digital/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz"
|
||||||
},
|
},
|
||||||
"minimatch@10.1.2": {
|
"minimatch@10.2.0": {
|
||||||
"integrity": "sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==",
|
"integrity": "sha512-ugkC31VaVg9cF0DFVoADH12k6061zNZkZON+aX8AWsR9GhPcErkcMBceb6znR8wLERM2AkkOxy2nWRLpT9Jq5w==",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"@isaacs/brace-expansion"
|
"brace-expansion@5.0.2"
|
||||||
],
|
],
|
||||||
"tarball": "https://verdaccio.lossless.digital/minimatch/-/minimatch-10.1.2.tgz"
|
"tarball": "https://verdaccio.lossless.digital/minimatch/-/minimatch-10.2.0.tgz"
|
||||||
},
|
},
|
||||||
"minimatch@3.1.2": {
|
"minimatch@3.1.2": {
|
||||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||||
@@ -7313,7 +7304,7 @@
|
|||||||
"npm:@push.rocks/smartnetwork@^4.4.0",
|
"npm:@push.rocks/smartnetwork@^4.4.0",
|
||||||
"npm:@push.rocks/smartpromise@^4.2.3",
|
"npm:@push.rocks/smartpromise@^4.2.3",
|
||||||
"npm:@push.rocks/smartrequest@^5.0.1",
|
"npm:@push.rocks/smartrequest@^5.0.1",
|
||||||
"npm:@push.rocks/smartrust@^1.2.0",
|
"npm:@push.rocks/smartrust@^1.2.1",
|
||||||
"npm:@push.rocks/smartrx@^3.0.10",
|
"npm:@push.rocks/smartrx@^3.0.10",
|
||||||
"npm:@push.rocks/smartserve@^2.0.1",
|
"npm:@push.rocks/smartserve@^2.0.1",
|
||||||
"npm:@push.rocks/smartstring@^4.1.0",
|
"npm:@push.rocks/smartstring@^4.1.0",
|
||||||
@@ -7322,7 +7313,7 @@
|
|||||||
"npm:@types/minimatch@6",
|
"npm:@types/minimatch@6",
|
||||||
"npm:@types/node@^25.2.3",
|
"npm:@types/node@^25.2.3",
|
||||||
"npm:@types/ws@^8.18.1",
|
"npm:@types/ws@^8.18.1",
|
||||||
"npm:minimatch@^10.1.2",
|
"npm:minimatch@^10.2.0",
|
||||||
"npm:pretty-ms@^9.3.0",
|
"npm:pretty-ms@^9.3.0",
|
||||||
"npm:typescript@^5.9.3",
|
"npm:typescript@^5.9.3",
|
||||||
"npm:why-is-node-running@^3.2.2",
|
"npm:why-is-node-running@^3.2.2",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@push.rocks/smartproxy",
|
"name": "@push.rocks/smartproxy",
|
||||||
"version": "23.1.3",
|
"version": "23.1.6",
|
||||||
"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",
|
||||||
@@ -34,14 +34,14 @@
|
|||||||
"@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.2.0",
|
"@push.rocks/smartrust": "^1.2.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": "^4.2.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.2",
|
"minimatch": "^10.2.0",
|
||||||
"pretty-ms": "^9.3.0",
|
"pretty-ms": "^9.3.0",
|
||||||
"ws": "^8.19.0"
|
"ws": "^8.19.0"
|
||||||
},
|
},
|
||||||
|
|||||||
62
pnpm-lock.yaml
generated
62
pnpm-lock.yaml
generated
@@ -36,8 +36,8 @@ importers:
|
|||||||
specifier: ^5.0.1
|
specifier: ^5.0.1
|
||||||
version: 5.0.1
|
version: 5.0.1
|
||||||
'@push.rocks/smartrust':
|
'@push.rocks/smartrust':
|
||||||
specifier: ^1.2.0
|
specifier: ^1.2.1
|
||||||
version: 1.2.0
|
version: 1.2.1
|
||||||
'@push.rocks/smartrx':
|
'@push.rocks/smartrx':
|
||||||
specifier: ^3.0.10
|
specifier: ^3.0.10
|
||||||
version: 3.0.10
|
version: 3.0.10
|
||||||
@@ -57,8 +57,8 @@ importers:
|
|||||||
specifier: ^8.18.1
|
specifier: ^8.18.1
|
||||||
version: 8.18.1
|
version: 8.18.1
|
||||||
minimatch:
|
minimatch:
|
||||||
specifier: ^10.1.2
|
specifier: ^10.2.0
|
||||||
version: 10.1.2
|
version: 10.2.0
|
||||||
pretty-ms:
|
pretty-ms:
|
||||||
specifier: ^9.3.0
|
specifier: ^9.3.0
|
||||||
version: 9.3.0
|
version: 9.3.0
|
||||||
@@ -570,14 +570,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag==}
|
resolution: {integrity: sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
'@isaacs/balanced-match@4.0.1':
|
|
||||||
resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==}
|
|
||||||
engines: {node: 20 || >=22}
|
|
||||||
|
|
||||||
'@isaacs/brace-expansion@5.0.1':
|
|
||||||
resolution: {integrity: sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==}
|
|
||||||
engines: {node: 20 || >=22}
|
|
||||||
|
|
||||||
'@isaacs/cliui@9.0.0':
|
'@isaacs/cliui@9.0.0':
|
||||||
resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==}
|
resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -883,8 +875,8 @@ packages:
|
|||||||
'@push.rocks/smartrouter@1.3.3':
|
'@push.rocks/smartrouter@1.3.3':
|
||||||
resolution: {integrity: sha512-1+xZEnWlhzqLWAaJ1zFNhQ0zgbfCWQl1DBT72LygLxTs+P0K8AwJKgqo/IX6CT55kGCFnPAZIYSbVJlGsgrB0w==}
|
resolution: {integrity: sha512-1+xZEnWlhzqLWAaJ1zFNhQ0zgbfCWQl1DBT72LygLxTs+P0K8AwJKgqo/IX6CT55kGCFnPAZIYSbVJlGsgrB0w==}
|
||||||
|
|
||||||
'@push.rocks/smartrust@1.2.0':
|
'@push.rocks/smartrust@1.2.1':
|
||||||
resolution: {integrity: sha512-JlaALselIHoP6C3ceQbrvz424G21cND/QsH/KI3E/JrO4XphJiGZwM6f4yJWrijdPYR/YYMoaIiYN7ybZp0C4w==}
|
resolution: {integrity: sha512-ANwXXibUwoHNWF1hhXhXVVrfzYlhgHYRa2205Jkd/s/wXzcWHftYZthilJj+52B7nkzSB76umfxKfK5eBYY2Ug==}
|
||||||
|
|
||||||
'@push.rocks/smartrx@3.0.10':
|
'@push.rocks/smartrx@3.0.10':
|
||||||
resolution: {integrity: sha512-USjIYcsSfzn14cwOsxgq/bBmWDTTzy3ouWAnW5NdMyRRzEbmeNrvmy6TRqNeDlJ2PsYNTt1rr/zGUqvIy72ITg==}
|
resolution: {integrity: sha512-USjIYcsSfzn14cwOsxgq/bBmWDTTzy3ouWAnW5NdMyRRzEbmeNrvmy6TRqNeDlJ2PsYNTt1rr/zGUqvIy72ITg==}
|
||||||
@@ -1649,6 +1641,10 @@ packages:
|
|||||||
balanced-match@1.0.2:
|
balanced-match@1.0.2:
|
||||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||||
|
|
||||||
|
balanced-match@4.0.2:
|
||||||
|
resolution: {integrity: sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg==}
|
||||||
|
engines: {node: 20 || >=22}
|
||||||
|
|
||||||
bare-events@2.8.2:
|
bare-events@2.8.2:
|
||||||
resolution: {integrity: sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==}
|
resolution: {integrity: sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -1714,6 +1710,10 @@ packages:
|
|||||||
brace-expansion@2.0.2:
|
brace-expansion@2.0.2:
|
||||||
resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
|
resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
|
||||||
|
|
||||||
|
brace-expansion@5.0.2:
|
||||||
|
resolution: {integrity: sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==}
|
||||||
|
engines: {node: 20 || >=22}
|
||||||
|
|
||||||
broadcast-channel@7.2.0:
|
broadcast-channel@7.2.0:
|
||||||
resolution: {integrity: sha512-JgraikEriG/TxBUi2W/w2O0jhHjXZUtXAvCZH0Yr3whjxYVgAg0hSe6r/teM+I5H5Q/q6RhyuKdC2pHNlFyepQ==}
|
resolution: {integrity: sha512-JgraikEriG/TxBUi2W/w2O0jhHjXZUtXAvCZH0Yr3whjxYVgAg0hSe6r/teM+I5H5Q/q6RhyuKdC2pHNlFyepQ==}
|
||||||
|
|
||||||
@@ -2750,8 +2750,8 @@ packages:
|
|||||||
minimalistic-crypto-utils@1.0.1:
|
minimalistic-crypto-utils@1.0.1:
|
||||||
resolution: {integrity: sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=}
|
resolution: {integrity: sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=}
|
||||||
|
|
||||||
minimatch@10.1.2:
|
minimatch@10.2.0:
|
||||||
resolution: {integrity: sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==}
|
resolution: {integrity: sha512-ugkC31VaVg9cF0DFVoADH12k6061zNZkZON+aX8AWsR9GhPcErkcMBceb6znR8wLERM2AkkOxy2nWRLpT9Jq5w==}
|
||||||
engines: {node: 20 || >=22}
|
engines: {node: 20 || >=22}
|
||||||
|
|
||||||
minimatch@3.1.2:
|
minimatch@3.1.2:
|
||||||
@@ -4654,12 +4654,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
mute-stream: 1.0.0
|
mute-stream: 1.0.0
|
||||||
|
|
||||||
'@isaacs/balanced-match@4.0.1': {}
|
|
||||||
|
|
||||||
'@isaacs/brace-expansion@5.0.1':
|
|
||||||
dependencies:
|
|
||||||
'@isaacs/balanced-match': 4.0.1
|
|
||||||
|
|
||||||
'@isaacs/cliui@9.0.0': {}
|
'@isaacs/cliui@9.0.0': {}
|
||||||
|
|
||||||
'@leichtgewicht/ip-codec@2.0.5': {}
|
'@leichtgewicht/ip-codec@2.0.5': {}
|
||||||
@@ -5034,7 +5028,7 @@ snapshots:
|
|||||||
'@push.rocks/smartstring': 4.1.0
|
'@push.rocks/smartstring': 4.1.0
|
||||||
'@push.rocks/smartunique': 3.0.9
|
'@push.rocks/smartunique': 3.0.9
|
||||||
'@tsclass/tsclass': 9.3.0
|
'@tsclass/tsclass': 9.3.0
|
||||||
minimatch: 10.1.2
|
minimatch: 10.2.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- aws-crt
|
- aws-crt
|
||||||
|
|
||||||
@@ -5127,7 +5121,7 @@ snapshots:
|
|||||||
acme-client: 5.4.0
|
acme-client: 5.4.0
|
||||||
dns-packet: 5.6.1
|
dns-packet: 5.6.1
|
||||||
elliptic: 6.6.1
|
elliptic: 6.6.1
|
||||||
minimatch: 10.1.2
|
minimatch: 10.2.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -5143,7 +5137,7 @@ snapshots:
|
|||||||
acme-client: 5.4.0
|
acme-client: 5.4.0
|
||||||
dns-packet: 5.6.1
|
dns-packet: 5.6.1
|
||||||
elliptic: 6.6.1
|
elliptic: 6.6.1
|
||||||
minimatch: 10.1.2
|
minimatch: 10.2.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -5497,7 +5491,7 @@ snapshots:
|
|||||||
'@push.rocks/smartrx': 3.0.10
|
'@push.rocks/smartrx': 3.0.10
|
||||||
path-to-regexp: 8.3.0
|
path-to-regexp: 8.3.0
|
||||||
|
|
||||||
'@push.rocks/smartrust@1.2.0':
|
'@push.rocks/smartrust@1.2.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@push.rocks/smartpath': 6.0.0
|
'@push.rocks/smartpath': 6.0.0
|
||||||
|
|
||||||
@@ -6323,7 +6317,7 @@ snapshots:
|
|||||||
|
|
||||||
'@types/minimatch@6.0.0':
|
'@types/minimatch@6.0.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
minimatch: 10.1.2
|
minimatch: 10.2.0
|
||||||
|
|
||||||
'@types/ms@2.1.0': {}
|
'@types/ms@2.1.0': {}
|
||||||
|
|
||||||
@@ -6494,6 +6488,10 @@ snapshots:
|
|||||||
|
|
||||||
balanced-match@1.0.2: {}
|
balanced-match@1.0.2: {}
|
||||||
|
|
||||||
|
balanced-match@4.0.2:
|
||||||
|
dependencies:
|
||||||
|
jackspeak: 4.2.3
|
||||||
|
|
||||||
bare-events@2.8.2: {}
|
bare-events@2.8.2: {}
|
||||||
|
|
||||||
bare-fs@4.5.3:
|
bare-fs@4.5.3:
|
||||||
@@ -6564,6 +6562,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
balanced-match: 1.0.2
|
balanced-match: 1.0.2
|
||||||
|
|
||||||
|
brace-expansion@5.0.2:
|
||||||
|
dependencies:
|
||||||
|
balanced-match: 4.0.2
|
||||||
|
|
||||||
broadcast-channel@7.2.0:
|
broadcast-channel@7.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.28.4
|
'@babel/runtime': 7.28.4
|
||||||
@@ -7157,7 +7159,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
foreground-child: 3.3.1
|
foreground-child: 3.3.1
|
||||||
jackspeak: 4.2.3
|
jackspeak: 4.2.3
|
||||||
minimatch: 10.1.2
|
minimatch: 10.2.0
|
||||||
minipass: 7.1.2
|
minipass: 7.1.2
|
||||||
package-json-from-dist: 1.0.1
|
package-json-from-dist: 1.0.1
|
||||||
path-scurry: 2.0.1
|
path-scurry: 2.0.1
|
||||||
@@ -7862,9 +7864,9 @@ snapshots:
|
|||||||
|
|
||||||
minimalistic-crypto-utils@1.0.1: {}
|
minimalistic-crypto-utils@1.0.1: {}
|
||||||
|
|
||||||
minimatch@10.1.2:
|
minimatch@10.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@isaacs/brace-expansion': 5.0.1
|
brace-expansion: 5.0.2
|
||||||
|
|
||||||
minimatch@3.1.2:
|
minimatch@3.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
@@ -6,42 +6,49 @@ import { SmartProxy } from '../ts/index.js';
|
|||||||
let testProxy: SmartProxy;
|
let testProxy: SmartProxy;
|
||||||
let targetServer: net.Server;
|
let targetServer: net.Server;
|
||||||
|
|
||||||
|
const ECHO_PORT = 47200;
|
||||||
|
const PROXY_PORT = 47201;
|
||||||
|
|
||||||
// Create a simple echo server as target
|
// Create a simple echo server as target
|
||||||
tap.test('setup test environment', async () => {
|
tap.test('setup test environment', async () => {
|
||||||
// Create target server that echoes data back
|
// Create target server that echoes data back
|
||||||
targetServer = net.createServer((socket) => {
|
targetServer = net.createServer((socket) => {
|
||||||
console.log('Target server: client connected');
|
console.log('Target server: client connected');
|
||||||
|
|
||||||
// Echo data back
|
// Echo data back
|
||||||
socket.on('data', (data) => {
|
socket.on('data', (data) => {
|
||||||
console.log(`Target server received: ${data.toString().trim()}`);
|
console.log(`Target server received: ${data.toString().trim()}`);
|
||||||
socket.write(data);
|
socket.write(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('close', () => {
|
socket.on('close', () => {
|
||||||
console.log('Target server: client disconnected');
|
console.log('Target server: client disconnected');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
await new Promise<void>((resolve) => {
|
await new Promise<void>((resolve, reject) => {
|
||||||
targetServer.listen(9876, () => {
|
targetServer.on('error', (err) => {
|
||||||
console.log('Target server listening on port 9876');
|
console.error(`Echo server error: ${err.message}`);
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
targetServer.listen(ECHO_PORT, () => {
|
||||||
|
console.log(`Target server listening on port ${ECHO_PORT}`);
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create proxy with simple TCP forwarding (no TLS)
|
// Create proxy with simple TCP forwarding (no TLS)
|
||||||
testProxy = new SmartProxy({
|
testProxy = new SmartProxy({
|
||||||
routes: [{
|
routes: [{
|
||||||
name: 'tcp-forward-test',
|
name: 'tcp-forward-test',
|
||||||
match: {
|
match: {
|
||||||
ports: 8888 // Plain TCP port
|
ports: PROXY_PORT // Plain TCP port
|
||||||
},
|
},
|
||||||
action: {
|
action: {
|
||||||
type: 'forward',
|
type: 'forward',
|
||||||
targets: [{
|
targets: [{
|
||||||
host: 'localhost',
|
host: 'localhost',
|
||||||
port: 9876
|
port: ECHO_PORT
|
||||||
}]
|
}]
|
||||||
// No TLS configuration - just plain TCP forwarding
|
// No TLS configuration - just plain TCP forwarding
|
||||||
}
|
}
|
||||||
@@ -49,7 +56,7 @@ tap.test('setup test environment', async () => {
|
|||||||
defaults: {
|
defaults: {
|
||||||
target: {
|
target: {
|
||||||
host: 'localhost',
|
host: 'localhost',
|
||||||
port: 9876
|
port: ECHO_PORT
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
enableDetailedLogging: true,
|
enableDetailedLogging: true,
|
||||||
@@ -59,72 +66,72 @@ tap.test('setup test environment', async () => {
|
|||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
keepAliveInitialDelay: 1000
|
keepAliveInitialDelay: 1000
|
||||||
});
|
});
|
||||||
|
|
||||||
await testProxy.start();
|
await testProxy.start();
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('should keep WebSocket-like connection open for extended period', async (tools) => {
|
tap.test('should keep WebSocket-like connection open for extended period', async (tools) => {
|
||||||
tools.timeout(60000); // 60 second test timeout
|
tools.timeout(15000); // 15 second test timeout
|
||||||
|
|
||||||
const client = new net.Socket();
|
const client = new net.Socket();
|
||||||
let messagesReceived = 0;
|
let messagesReceived = 0;
|
||||||
let connectionClosed = false;
|
let connectionClosed = false;
|
||||||
|
|
||||||
// Connect to proxy
|
// Connect to proxy
|
||||||
await new Promise<void>((resolve, reject) => {
|
await new Promise<void>((resolve, reject) => {
|
||||||
client.connect(8888, 'localhost', () => {
|
client.connect(PROXY_PORT, 'localhost', () => {
|
||||||
console.log('Client connected to proxy');
|
console.log('Client connected to proxy');
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('error', reject);
|
client.on('error', reject);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set up data handler
|
// Set up data handler
|
||||||
client.on('data', (data) => {
|
client.on('data', (data) => {
|
||||||
console.log(`Client received: ${data.toString().trim()}`);
|
console.log(`Client received: ${data.toString().trim()}`);
|
||||||
messagesReceived++;
|
messagesReceived++;
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('close', () => {
|
client.on('close', () => {
|
||||||
console.log('Client connection closed');
|
console.log('Client connection closed');
|
||||||
connectionClosed = true;
|
connectionClosed = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Send initial handshake-like data
|
// Send initial handshake-like data
|
||||||
client.write('HELLO\n');
|
client.write('HELLO\n');
|
||||||
|
|
||||||
// Wait for response
|
// Wait for response
|
||||||
await new Promise(resolve => setTimeout(resolve, 100));
|
await new Promise(resolve => setTimeout(resolve, 100));
|
||||||
expect(messagesReceived).toEqual(1);
|
expect(messagesReceived).toEqual(1);
|
||||||
|
|
||||||
// Simulate WebSocket-like keep-alive pattern
|
// Simulate WebSocket-like keep-alive pattern
|
||||||
// Send periodic messages over 60 seconds
|
// Send periodic messages over 5 seconds
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
const pingInterval = setInterval(() => {
|
const pingInterval = setInterval(() => {
|
||||||
if (!connectionClosed && Date.now() - startTime < 60000) {
|
if (!connectionClosed && Date.now() - startTime < 5000) {
|
||||||
console.log('Sending ping...');
|
console.log('Sending ping...');
|
||||||
client.write('PING\n');
|
client.write('PING\n');
|
||||||
} else {
|
} else {
|
||||||
clearInterval(pingInterval);
|
clearInterval(pingInterval);
|
||||||
}
|
}
|
||||||
}, 10000); // Every 10 seconds
|
}, 1000); // Every 1 second
|
||||||
|
|
||||||
// Wait for 55 seconds (must complete within 60s runner timeout)
|
// Wait for 5 seconds — sufficient to verify the connection stays open
|
||||||
await new Promise(resolve => setTimeout(resolve, 55000));
|
await new Promise(resolve => setTimeout(resolve, 5000));
|
||||||
|
|
||||||
// Clean up interval
|
// Clean up interval
|
||||||
clearInterval(pingInterval);
|
clearInterval(pingInterval);
|
||||||
|
|
||||||
// Connection should still be open
|
// Connection should still be open
|
||||||
expect(connectionClosed).toEqual(false);
|
expect(connectionClosed).toEqual(false);
|
||||||
|
|
||||||
// Should have received responses (1 hello + 6 pings)
|
// Should have received responses (1 hello + ~5 pings)
|
||||||
expect(messagesReceived).toBeGreaterThan(5);
|
expect(messagesReceived).toBeGreaterThan(3);
|
||||||
|
|
||||||
// Close connection gracefully
|
// Close connection gracefully
|
||||||
client.end();
|
client.end();
|
||||||
|
|
||||||
// Wait for close
|
// Wait for close
|
||||||
await new Promise(resolve => setTimeout(resolve, 100));
|
await new Promise(resolve => setTimeout(resolve, 100));
|
||||||
expect(connectionClosed).toEqual(true);
|
expect(connectionClosed).toEqual(true);
|
||||||
@@ -134,7 +141,7 @@ tap.test('should keep WebSocket-like connection open for extended period', async
|
|||||||
|
|
||||||
tap.test('cleanup', async () => {
|
tap.test('cleanup', async () => {
|
||||||
await testProxy.stop();
|
await testProxy.stop();
|
||||||
|
|
||||||
await new Promise<void>((resolve) => {
|
await new Promise<void>((resolve) => {
|
||||||
targetServer.close(() => {
|
targetServer.close(() => {
|
||||||
console.log('Target server closed');
|
console.log('Target server closed');
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import * as net from 'net';
|
|||||||
|
|
||||||
let smartProxyInstance: SmartProxy;
|
let smartProxyInstance: SmartProxy;
|
||||||
let echoServer: net.Server;
|
let echoServer: net.Server;
|
||||||
const echoServerPort = 9876;
|
const echoServerPort = 47300;
|
||||||
const proxyPort = 8080;
|
const proxyPort = 47301;
|
||||||
|
|
||||||
// Create an echo server for testing
|
// Create an echo server for testing
|
||||||
tap.test('should create echo server for testing', async () => {
|
tap.test('should create echo server for testing', async () => {
|
||||||
@@ -16,7 +16,11 @@ tap.test('should create echo server for testing', async () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
await new Promise<void>((resolve) => {
|
await new Promise<void>((resolve, reject) => {
|
||||||
|
echoServer.on('error', (err) => {
|
||||||
|
console.error(`Echo server error: ${err.message}`);
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
echoServer.listen(echoServerPort, () => {
|
echoServer.listen(echoServerPort, () => {
|
||||||
console.log(`Echo server listening on port ${echoServerPort}`);
|
console.log(`Echo server listening on port ${echoServerPort}`);
|
||||||
resolve();
|
resolve();
|
||||||
@@ -265,4 +269,4 @@ tap.test('should clean up resources', async () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
export default tap.start();
|
export default tap.start();
|
||||||
@@ -5,19 +5,27 @@ import { SmartProxy } from '../ts/proxies/smart-proxy/smart-proxy.js';
|
|||||||
let echoServer: net.Server;
|
let echoServer: net.Server;
|
||||||
let proxy: SmartProxy;
|
let proxy: SmartProxy;
|
||||||
|
|
||||||
|
const ECHO_PORT = 47400;
|
||||||
|
const PROXY_PORT_1 = 47401;
|
||||||
|
const PROXY_PORT_2 = 47402;
|
||||||
|
|
||||||
tap.test('port forwarding should not immediately close connections', async (tools) => {
|
tap.test('port forwarding should not immediately close connections', async (tools) => {
|
||||||
// Set a timeout for this test
|
// Set a timeout for this test
|
||||||
tools.timeout(10000); // 10 seconds
|
tools.timeout(10000); // 10 seconds
|
||||||
// Create an echo server
|
// Create an echo server
|
||||||
echoServer = await new Promise<net.Server>((resolve) => {
|
echoServer = await new Promise<net.Server>((resolve, reject) => {
|
||||||
const server = net.createServer((socket) => {
|
const server = net.createServer((socket) => {
|
||||||
socket.on('data', (data) => {
|
socket.on('data', (data) => {
|
||||||
socket.write(`ECHO: ${data}`);
|
socket.write(`ECHO: ${data}`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
server.listen(8888, () => {
|
server.on('error', (err) => {
|
||||||
console.log('Echo server listening on port 8888');
|
console.error(`Echo server error: ${err.message}`);
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
server.listen(ECHO_PORT, () => {
|
||||||
|
console.log(`Echo server listening on port ${ECHO_PORT}`);
|
||||||
resolve(server);
|
resolve(server);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -26,10 +34,10 @@ tap.test('port forwarding should not immediately close connections', async (tool
|
|||||||
proxy = new SmartProxy({
|
proxy = new SmartProxy({
|
||||||
routes: [{
|
routes: [{
|
||||||
name: 'test-forward',
|
name: 'test-forward',
|
||||||
match: { ports: 9999 },
|
match: { ports: PROXY_PORT_1 },
|
||||||
action: {
|
action: {
|
||||||
type: 'forward',
|
type: 'forward',
|
||||||
targets: [{ host: 'localhost', port: 8888 }]
|
targets: [{ host: 'localhost', port: ECHO_PORT }]
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
@@ -37,21 +45,24 @@ tap.test('port forwarding should not immediately close connections', async (tool
|
|||||||
await proxy.start();
|
await proxy.start();
|
||||||
|
|
||||||
// Test connection through proxy
|
// Test connection through proxy
|
||||||
const client = net.createConnection(9999, 'localhost');
|
const client = net.createConnection(PROXY_PORT_1, 'localhost');
|
||||||
|
|
||||||
const result = await new Promise<string>((resolve, reject) => {
|
const result = await new Promise<string>((resolve, reject) => {
|
||||||
client.on('data', (data) => {
|
client.on('data', (data) => {
|
||||||
const response = data.toString();
|
const response = data.toString();
|
||||||
client.end(); // Close the connection after receiving data
|
client.end(); // Close the connection after receiving data
|
||||||
resolve(response);
|
resolve(response);
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('error', reject);
|
client.on('error', reject);
|
||||||
|
|
||||||
client.write('Hello');
|
client.write('Hello');
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result).toEqual('ECHO: Hello');
|
expect(result).toEqual('ECHO: Hello');
|
||||||
|
|
||||||
|
// Stop proxy from test 1 before test 2 reassigns the variable
|
||||||
|
await proxy.stop();
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('TLS passthrough should work correctly', async () => {
|
tap.test('TLS passthrough should work correctly', async () => {
|
||||||
@@ -59,7 +70,7 @@ tap.test('TLS passthrough should work correctly', async () => {
|
|||||||
proxy = new SmartProxy({
|
proxy = new SmartProxy({
|
||||||
routes: [{
|
routes: [{
|
||||||
name: 'tls-test',
|
name: 'tls-test',
|
||||||
match: { ports: 8443, domains: 'test.example.com' },
|
match: { ports: PROXY_PORT_2, domains: 'test.example.com' },
|
||||||
action: {
|
action: {
|
||||||
type: 'forward',
|
type: 'forward',
|
||||||
tls: { mode: 'passthrough' },
|
tls: { mode: 'passthrough' },
|
||||||
@@ -85,16 +96,6 @@ tap.test('cleanup', async () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (proxy) {
|
|
||||||
await proxy.stop();
|
|
||||||
console.log('Proxy stopped');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default tap.start().then(() => {
|
export default tap.start();
|
||||||
// Force exit after tests complete
|
|
||||||
setTimeout(() => {
|
|
||||||
console.log('Forcing process exit');
|
|
||||||
process.exit(0);
|
|
||||||
}, 1000);
|
|
||||||
});
|
|
||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@push.rocks/smartproxy',
|
name: '@push.rocks/smartproxy',
|
||||||
version: '23.1.3',
|
version: '23.1.6',
|
||||||
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.'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { RouteValidator } from './utils/route-validator.js';
|
|||||||
import { Mutex } from './utils/mutex.js';
|
import { Mutex } from './utils/mutex.js';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { ISmartProxyOptions, TSmartProxyCertProvisionObject } from './models/interfaces.js';
|
import type { ISmartProxyOptions, TSmartProxyCertProvisionObject, IAcmeOptions } from './models/interfaces.js';
|
||||||
import type { IRouteConfig } from './models/route-types.js';
|
import type { IRouteConfig } from './models/route-types.js';
|
||||||
import type { IMetrics } from './models/metrics-types.js';
|
import type { IMetrics } from './models/metrics-types.js';
|
||||||
|
|
||||||
@@ -146,8 +146,16 @@ export class SmartProxy extends plugins.EventEmitter {
|
|||||||
// Preprocess routes (strip JS functions, convert socket-handler routes)
|
// Preprocess routes (strip JS functions, convert socket-handler routes)
|
||||||
const rustRoutes = this.preprocessor.preprocessForRust(this.settings.routes);
|
const rustRoutes = this.preprocessor.preprocessForRust(this.settings.routes);
|
||||||
|
|
||||||
|
// When certProvisionFunction handles cert provisioning,
|
||||||
|
// disable Rust's built-in ACME to prevent race condition.
|
||||||
|
let acmeForRust = this.settings.acme;
|
||||||
|
if (this.settings.certProvisionFunction && acmeForRust?.enabled) {
|
||||||
|
acmeForRust = { ...acmeForRust, enabled: false };
|
||||||
|
logger.log('info', 'Rust ACME disabled — certProvisionFunction will handle certificate provisioning', { component: 'smart-proxy' });
|
||||||
|
}
|
||||||
|
|
||||||
// Build Rust config
|
// Build Rust config
|
||||||
const config = this.buildRustConfig(rustRoutes);
|
const config = this.buildRustConfig(rustRoutes, acmeForRust);
|
||||||
|
|
||||||
// Start the Rust proxy
|
// Start the Rust proxy
|
||||||
await this.bridge.startProxy(config);
|
await this.bridge.startProxy(config);
|
||||||
@@ -334,20 +342,21 @@ export class SmartProxy extends plugins.EventEmitter {
|
|||||||
/**
|
/**
|
||||||
* Build the Rust configuration object from TS settings.
|
* Build the Rust configuration object from TS settings.
|
||||||
*/
|
*/
|
||||||
private buildRustConfig(routes: IRouteConfig[]): any {
|
private buildRustConfig(routes: IRouteConfig[], acmeOverride?: IAcmeOptions): any {
|
||||||
|
const acme = acmeOverride !== undefined ? acmeOverride : this.settings.acme;
|
||||||
return {
|
return {
|
||||||
routes,
|
routes,
|
||||||
defaults: this.settings.defaults,
|
defaults: this.settings.defaults,
|
||||||
acme: this.settings.acme
|
acme: acme
|
||||||
? {
|
? {
|
||||||
enabled: this.settings.acme.enabled,
|
enabled: acme.enabled,
|
||||||
email: this.settings.acme.email,
|
email: acme.email,
|
||||||
useProduction: this.settings.acme.useProduction,
|
useProduction: acme.useProduction,
|
||||||
port: this.settings.acme.port,
|
port: acme.port,
|
||||||
renewThresholdDays: this.settings.acme.renewThresholdDays,
|
renewThresholdDays: acme.renewThresholdDays,
|
||||||
autoRenew: this.settings.acme.autoRenew,
|
autoRenew: acme.autoRenew,
|
||||||
certificateStore: this.settings.acme.certificateStore,
|
certificateStore: acme.certificateStore,
|
||||||
renewCheckIntervalHours: this.settings.acme.renewCheckIntervalHours,
|
renewCheckIntervalHours: acme.renewCheckIntervalHours,
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
connectionTimeout: this.settings.connectionTimeout,
|
connectionTimeout: this.settings.connectionTimeout,
|
||||||
@@ -374,20 +383,31 @@ export class SmartProxy extends plugins.EventEmitter {
|
|||||||
const provisionFn = this.settings.certProvisionFunction;
|
const provisionFn = this.settings.certProvisionFunction;
|
||||||
if (!provisionFn) return;
|
if (!provisionFn) return;
|
||||||
|
|
||||||
|
const provisionedDomains = new Set<string>();
|
||||||
|
|
||||||
for (const route of this.settings.routes) {
|
for (const route of this.settings.routes) {
|
||||||
if (route.action.tls?.certificate !== 'auto') continue;
|
if (route.action.tls?.certificate !== 'auto') continue;
|
||||||
if (!route.match.domains) continue;
|
if (!route.match.domains) continue;
|
||||||
|
|
||||||
const domains = Array.isArray(route.match.domains) ? route.match.domains : [route.match.domains];
|
const rawDomains = Array.isArray(route.match.domains) ? route.match.domains : [route.match.domains];
|
||||||
|
const certDomains = this.normalizeDomainsForCertProvisioning(rawDomains);
|
||||||
for (const domain of domains) {
|
|
||||||
if (domain.includes('*')) continue;
|
|
||||||
|
|
||||||
|
for (const domain of certDomains) {
|
||||||
|
if (provisionedDomains.has(domain)) continue;
|
||||||
|
provisionedDomains.add(domain);
|
||||||
try {
|
try {
|
||||||
const result: TSmartProxyCertProvisionObject = await provisionFn(domain);
|
const result: TSmartProxyCertProvisionObject = await provisionFn(domain);
|
||||||
|
|
||||||
if (result === 'http01') {
|
if (result === 'http01') {
|
||||||
// Rust handles ACME for this domain
|
// Callback wants HTTP-01 for this domain — trigger Rust ACME explicitly
|
||||||
|
if (route.name) {
|
||||||
|
try {
|
||||||
|
await this.bridge.provisionCertificate(route.name);
|
||||||
|
logger.log('info', `Triggered Rust ACME for ${domain} (route: ${route.name})`, { component: 'smart-proxy' });
|
||||||
|
} catch (provisionErr: any) {
|
||||||
|
logger.log('warn', `Cannot provision cert for ${domain} — callback returned 'http01' but Rust ACME failed: ${provisionErr.message}`, { component: 'smart-proxy' });
|
||||||
|
}
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,6 +433,43 @@ export class SmartProxy extends plugins.EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize routing glob patterns into valid domain identifiers for cert provisioning.
|
||||||
|
* - `*nevermind.cloud` → `['nevermind.cloud', '*.nevermind.cloud']`
|
||||||
|
* - `*.lossless.digital` → `['*.lossless.digital']` (already valid wildcard)
|
||||||
|
* - `code.foss.global` → `['code.foss.global']` (plain domain)
|
||||||
|
* - `*mid*.example.com` → skipped with warning (unsupported glob)
|
||||||
|
*/
|
||||||
|
private normalizeDomainsForCertProvisioning(rawDomains: string[]): string[] {
|
||||||
|
const result: string[] = [];
|
||||||
|
for (const raw of rawDomains) {
|
||||||
|
// Plain domain — no glob characters
|
||||||
|
if (!raw.includes('*')) {
|
||||||
|
result.push(raw);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid wildcard: *.example.com
|
||||||
|
if (raw.startsWith('*.') && !raw.slice(2).includes('*')) {
|
||||||
|
result.push(raw);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Routing glob like *example.com (leading star, no dot after it)
|
||||||
|
// Convert to bare domain + wildcard pair
|
||||||
|
if (raw.startsWith('*') && !raw.startsWith('*.') && !raw.slice(1).includes('*')) {
|
||||||
|
const baseDomain = raw.slice(1); // Remove leading *
|
||||||
|
result.push(baseDomain);
|
||||||
|
result.push(`*.${baseDomain}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unsupported glob pattern (e.g. *mid*.example.com)
|
||||||
|
logger.log('warn', `Skipping unsupported glob pattern for cert provisioning: ${raw}`, { component: 'smart-proxy' });
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private isValidDomain(domain: string): boolean {
|
private isValidDomain(domain: string): boolean {
|
||||||
if (!domain || domain.length === 0) return false;
|
if (!domain || domain.length === 0) return false;
|
||||||
if (domain.includes('*')) return false;
|
if (domain.includes('*')) return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user