From b219ec2208015d98ac40e818ca7b6844d909f7c5 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Fri, 12 Sep 2025 17:59:06 +0000 Subject: [PATCH] feat(smartnetwork): Add randomizable port search and switch DNS resolution to @push.rocks/smartdns; export smartdns and update docs --- changelog.md | 9 + package.json | 3 +- pnpm-lock.yaml | 394 +++++++++++++++++------- readme.md | 22 +- ts/00_commitinfo_data.ts | 2 +- ts/smartnetwork.classes.smartnetwork.ts | 81 ++++- ts/smartnetwork.plugins.ts | 3 +- 7 files changed, 382 insertions(+), 132 deletions(-) diff --git a/changelog.md b/changelog.md index 27324cf..d02bd0e 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,14 @@ # Changelog +## 2025-09-12 - 4.3.0 - feat(smartnetwork) +Add randomizable port search and switch DNS resolution to @push.rocks/smartdns; export smartdns and update docs + +- findFreePort: added options.randomize (IFindFreePortOptions) to return a random available port within a range; retains default sequential search behavior +- resolveDns: switched to @push.rocks/smartdns client with 'prefer-system' strategy and DoH fallback; now returns parsed A, AAAA and MX records +- Exported smartdns from the internal plugins module and added @push.rocks/smartdns dependency +- Documentation updates: readme clarifies random port selection, DNS resolution strategy and adds examples for random findFreePort usage +- Bumped @git.zone/tstest dev dependency to ^2.3.7 + ## 2025-09-12 - 4.2.0 - feat(PublicIp) Add PublicIp service and refactor SmartNetwork to use it; remove public-ip dependency; update exports, docs and dependencies diff --git a/package.json b/package.json index 1ced7bb..6f64eb7 100644 --- a/package.json +++ b/package.json @@ -17,11 +17,12 @@ "devDependencies": { "@git.zone/tsbuild": "^2.6.8", "@git.zone/tsrun": "^1.2.39", - "@git.zone/tstest": "^2.3.6", + "@git.zone/tstest": "^2.3.7", "@push.rocks/smartenv": "^5.0.13", "@types/node": "^22.15.19" }, "dependencies": { + "@push.rocks/smartdns": "^7.6.1", "@push.rocks/smartping": "^1.0.7", "@push.rocks/smartpromise": "^4.2.3", "@push.rocks/smartstring": "^4.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 404c184..30774c0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + '@push.rocks/smartdns': + specifier: ^7.6.1 + version: 7.6.1 '@push.rocks/smartping': specifier: ^1.0.7 version: 1.0.8 @@ -31,8 +34,8 @@ importers: specifier: ^1.2.39 version: 1.3.3 '@git.zone/tstest': - specifier: ^2.3.6 - version: 2.3.6(@aws-sdk/credential-providers@3.812.0)(socks@2.8.7)(typescript@5.9.2) + specifier: ^2.3.7 + version: 2.3.7(@aws-sdk/credential-providers@3.812.0)(socks@2.8.7)(typescript@5.9.2) '@push.rocks/smartenv': specifier: ^5.0.13 version: 5.0.13 @@ -676,8 +679,8 @@ packages: resolution: {integrity: sha512-DDzWunkxXLtXJTxBf4EioXLwhuqdA2VzdTmOzWrw4Z4Qnms/YM67q36yajwNohAajPYyRz5DayU0ikrceFXyVw==} hasBin: true - '@git.zone/tstest@2.3.6': - resolution: {integrity: sha512-2dcVM1WvQj9FoLPRWbLgBCWnDK0auI2c2vJxUzrLe0bi/ci50yrXxyKb2FIToQ+kOVe234Yb6jhNyp/d/zyHMQ==} + '@git.zone/tstest@2.3.7': + resolution: {integrity: sha512-BO+OIeE/7vS2mrqloWGIE30bpAqmZoHj0FN4FLjas7qy6k6MSJO/nM53yqdkk0SDysGGauw+1vkw+vVYceUD3Q==} hasBin: true '@happy-dom/global-registrator@15.11.7': @@ -765,6 +768,39 @@ packages: '@pdf-lib/upng@1.0.1': resolution: {integrity: sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ==} + '@peculiar/asn1-cms@2.5.0': + resolution: {integrity: sha512-p0SjJ3TuuleIvjPM4aYfvYw8Fk1Hn/zAVyPJZTtZ2eE9/MIer6/18ROxX6N/e6edVSfvuZBqhxAj3YgsmSjQ/A==} + + '@peculiar/asn1-csr@2.5.0': + resolution: {integrity: sha512-ioigvA6WSYN9h/YssMmmoIwgl3RvZlAYx4A/9jD2qaqXZwGcNlAxaw54eSx2QG1Yu7YyBC5Rku3nNoHrQ16YsQ==} + + '@peculiar/asn1-ecc@2.5.0': + resolution: {integrity: sha512-t4eYGNhXtLRxaP50h3sfO6aJebUCDGQACoeexcelL4roMFRRVgB20yBIu2LxsPh/tdW9I282gNgMOyg3ywg/mg==} + + '@peculiar/asn1-pfx@2.5.0': + resolution: {integrity: sha512-Vj0d0wxJZA+Ztqfb7W+/iu8Uasw6hhKtCdLKXLG/P3kEPIQpqGI4P4YXlROfl7gOCqFIbgsj1HzFIFwQ5s20ug==} + + '@peculiar/asn1-pkcs8@2.5.0': + resolution: {integrity: sha512-L7599HTI2SLlitlpEP8oAPaJgYssByI4eCwQq2C9eC90otFpm8MRn66PpbKviweAlhinWQ3ZjDD2KIVtx7PaVw==} + + '@peculiar/asn1-pkcs9@2.5.0': + resolution: {integrity: sha512-UgqSMBLNLR5TzEZ5ZzxR45Nk6VJrammxd60WMSkofyNzd3DQLSNycGWSK5Xg3UTYbXcDFyG8pA/7/y/ztVCa6A==} + + '@peculiar/asn1-rsa@2.5.0': + resolution: {integrity: sha512-qMZ/vweiTHy9syrkkqWFvbT3eLoedvamcUdnnvwyyUNv5FgFXA3KP8td+ATibnlZ0EANW5PYRm8E6MJzEB/72Q==} + + '@peculiar/asn1-schema@2.5.0': + resolution: {integrity: sha512-YM/nFfskFJSlHqv59ed6dZlLZqtZQwjRVJ4bBAiWV08Oc+1rSd5lDZcBEx0lGDHfSoH3UziI2pXt2UM33KerPQ==} + + '@peculiar/asn1-x509-attr@2.5.0': + resolution: {integrity: sha512-9f0hPOxiJDoG/bfNLAFven+Bd4gwz/VzrCIIWc1025LEI4BXO0U5fOCTNDPbbp2ll+UzqKsZ3g61mpBp74gk9A==} + + '@peculiar/asn1-x509@2.5.0': + resolution: {integrity: sha512-CpwtMCTJvfvYTFMuiME5IH+8qmDe3yEWzKHe7OOADbGfq7ohxeLaXwQo0q4du3qs0AII3UbLCvb9NF/6q0oTKQ==} + + '@peculiar/x509@1.14.0': + resolution: {integrity: sha512-Yc4PDxN3OrxUPiXgU63c+ZRXKGE8YKF2McTciYhUHFtHVB0KMnjeFSU0qpztGhsp4P0uKix4+J2xEpIEDu8oXg==} + '@pnpm/config.env-replace@1.1.0': resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} engines: {node: '>=12.22.0'} @@ -839,6 +875,9 @@ packages: '@push.rocks/smartdelay@3.0.5': resolution: {integrity: sha512-mUuI7kj2f7ztjpic96FvRIlf2RsKBa5arw81AHNsndbxO6asRcxuWL8dTVxouEIK8YsBUlj0AsrCkHhMbLQdHw==} + '@push.rocks/smartdns@7.6.1': + resolution: {integrity: sha512-nnP5+A2GOt0WsHrYhtKERmjdEHUchc+QbCCBEqlyeQTn+mNfx2WZvKVI1DFRJt8lamvzxP6Hr/BSe3WHdh4Snw==} + '@push.rocks/smartenv@5.0.13': resolution: {integrity: sha512-ACXmUcHZHl2CF2jnVuRw9saRRrZvJblCRs2d+K5aLR1DfkYFX3eA21kcMlKeLisI3aGNbIj9vz/rowN5qkRkfA==} @@ -902,8 +941,8 @@ packages: '@push.rocks/smartmongo@2.0.12': resolution: {integrity: sha512-NglYiO14BikxnlvW6JF18FtopBtaWQEGAtPxHmmSCbyhU8Mi0aEFO7VgCasE9Kguba/wcR597qhcDEdcpBg1eQ==} - '@push.rocks/smartnetwork@4.1.2': - resolution: {integrity: sha512-TjucG72ooHgzAUpNu2LAv4iFoettmZq2aEWhhzIa7AKcOvt4yxsk3Vl73guhKRohTfhdRauPcH5OHISLUHJbYA==} + '@push.rocks/smartnetwork@4.2.0': + resolution: {integrity: sha512-XkRE2hQFCxUKzeD54MhbWlZAEVGyOhjU68A0zP9r3wsVjsVRqz38PwoM2GrhMrW4gtPa1j1t6cEUv1WNTwfo/Q==} '@push.rocks/smartnpm@2.0.6': resolution: {integrity: sha512-7anKDOjX6gXWs1IAc+YWz9ZZ8gDsTwaLh+CxRnGHjAawOmK788NrrgVCg2Fb3qojrPnoxecc46F8Ivp1BT7Izw==} @@ -1444,6 +1483,9 @@ packages: '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@types/bn.js@5.2.0': + resolution: {integrity: sha512-DLbJ1BPqxvQhIGbeu8VbUC1DiAiahHtAYvA0ZEAa4P31F7IaArc8z3C3BRQdWX4mtLQuABG4yzp76ZrS02Ui1Q==} + '@types/body-parser@1.19.6': resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} @@ -1462,8 +1504,11 @@ packages: '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} - '@types/default-gateway@7.2.2': - resolution: {integrity: sha512-35C93fYQlnLKLASkMPoxRvok4fENwB3By9clRLd2I/08n/XRl0pCdf7EB17K5oMMwZu8NBYA8i66jH5r/LYBKA==} + '@types/dns-packet@5.6.5': + resolution: {integrity: sha512-qXOC7XLOEe43ehtWJCMnQXvgcIpv6rPmQ1jXT98Ad8A3TB1Ue50jsCbSSSyuazScEuZ/Q026vHbrOTVkmwA+7Q==} + + '@types/elliptic@6.4.18': + resolution: {integrity: sha512-UseG6H5vjRiNpQvrhy4VF/JXdA3V/Fp5amvveaL+fs28BZ6xIKJBPnUPRlEaZpysD9MbpfaLi8lbl7PGUAkpWw==} '@types/express-serve-static-core@5.0.7': resolution: {integrity: sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==} @@ -1599,6 +1644,10 @@ packages: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} + acme-client@5.4.0: + resolution: {integrity: sha512-mORqg60S8iML6XSmVjqjGHJkINrCGLMj2QvDmFzI9vIlv1RGlyjmw3nrzaINJjkNsYXC41XhhD5pfy7CtuGcbA==} + engines: {node: '>= 16'} + agent-base@7.1.4: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} @@ -1641,6 +1690,10 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + asn1js@3.0.6: + resolution: {integrity: sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA==} + engines: {node: '>=12.0.0'} + ast-types@0.13.4: resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} engines: {node: '>=4'} @@ -1654,6 +1707,9 @@ packages: asynckit@0.4.0: resolution: {integrity: sha1-x57Zf380y48robyXkLzDZkdLS3k=} + axios@1.12.1: + resolution: {integrity: sha512-Kn4kbSXpkFHCGE6rBFNwIv0GQs4AvDT80jlveJDKFxjbTYMUeB4QtsdPCv6H8Cm19Je7IU6VFtRl2zWZI0rudQ==} + b4a@1.7.1: resolution: {integrity: sha512-ZovbrBV0g6JxK5cGUF1Suby1vLfKjv4RWi8IxoaO/Mon8BDD9I21RxjHFtgQ+kskJqLAVyQZly3uMBui+vhc8Q==} peerDependencies: @@ -1712,6 +1768,9 @@ packages: resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} engines: {node: '>=10.0.0'} + bn.js@4.12.2: + resolution: {integrity: sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==} + body-parser@2.2.0: resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} engines: {node: '>=18'} @@ -1731,6 +1790,9 @@ packages: broadcast-channel@7.1.0: resolution: {integrity: sha512-InJljddsYWbEL8LBnopnCg+qMQp9KcowvYWOt4YWrjD5HmxzDYKdVbDS1w/ji5rFZdRD58V5UxJPtBdpEbEJYw==} + brorand@1.1.0: + resolution: {integrity: sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=} + bson@6.10.4: resolution: {integrity: sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==} engines: {node: '>=16.20.1'} @@ -1824,10 +1886,6 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} - clone-regexp@3.0.0: - resolution: {integrity: sha512-ujdnoq2Kxb8s3ItNBtnYeXdm07FcU0u8ARAT1lQ2YdMwQC+cdiXX8KoqMVuglztILivceTtp4ivqGSmEmhBUJw==} - engines: {node: '>=12'} - co@4.6.0: resolution: {integrity: sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} @@ -1889,10 +1947,6 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} - convert-hrtime@5.0.0: - resolution: {integrity: sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==} - engines: {node: '>=12'} - cookie-signature@1.2.2: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} engines: {node: '>=6.6.0'} @@ -2029,10 +2083,6 @@ packages: resolution: {integrity: sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==} engines: {node: '>=6'} - dns-socket@4.2.2: - resolution: {integrity: sha512-BDeBd8najI4/lS00HSKpdFia+OvUMytaVjfzR9n5Lq8MlZRSvtbI+uLtx1+XmQFls5wFU9dssccTmQQ6nfpjdg==} - engines: {node: '>=6'} - dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -2043,6 +2093,9 @@ packages: ee-first@1.1.1: resolution: {integrity: sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=} + elliptic@6.6.1: + resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -2318,10 +2371,6 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - function-timeout@0.1.1: - resolution: {integrity: sha512-0NVVC0TaP7dSTvn1yMiy6d6Q8gifzbvQafO46RtLG/kHJUBNd+pVRGOBoK44wNBvtSPUJRfdVvkFdD3p0xvyZg==} - engines: {node: '>=14.16'} - get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -2374,10 +2423,6 @@ packages: resolution: {integrity: sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==} engines: {node: '>=14.16'} - got@13.0.0: - resolution: {integrity: sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA==} - engines: {node: '>=16'} - graceful-fs@4.2.10: resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} @@ -2403,6 +2448,9 @@ packages: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} + hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -2420,6 +2468,9 @@ packages: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true + hmac-drbg@1.0.1: + resolution: {integrity: sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=} + html-minifier@4.0.0: resolution: {integrity: sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==} engines: {node: '>=6'} @@ -2489,10 +2540,6 @@ packages: resolution: {integrity: sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==} engines: {node: '>= 12'} - ip-regex@5.0.0: - resolution: {integrity: sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -2516,10 +2563,6 @@ packages: resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} engines: {node: '>= 0.4'} - is-ip@5.0.1: - resolution: {integrity: sha512-FCsGHdlrOnZQcp0+XT5a+pYowf33itBalCl+7ovNXC/7o5BhIpG14M3OrpPPdBSIQJCm+0M5+9mO7S9VVTTCFw==} - engines: {node: '>=14.16'} - is-nan@1.3.2: resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} engines: {node: '>= 0.4'} @@ -2543,10 +2586,6 @@ packages: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} - is-regexp@3.1.0: - resolution: {integrity: sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==} - engines: {node: '>=12'} - is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} @@ -2939,6 +2978,12 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} + minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + + minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=} + minimatch@10.0.1: resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} engines: {node: 20 || >=22} @@ -3223,10 +3268,6 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - public-ip@7.0.1: - resolution: {integrity: sha512-DdNcqcIbI0wEeCBcqX+bmZpUCvrDMJHXE553zgyG1MZ8S1a/iCCxmK9iTjjql+SpHSv4cZkmRv5/zGYW93AlCw==} - engines: {node: '>=18'} - pump@3.0.3: resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} @@ -3246,6 +3287,13 @@ packages: engines: {node: '>=18'} hasBin: true + pvtsutils@1.3.6: + resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==} + + pvutils@1.1.3: + resolution: {integrity: sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==} + engines: {node: '>=6.0.0'} + qs@6.14.0: resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} engines: {node: '>=0.6'} @@ -3278,6 +3326,9 @@ packages: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} + reflect-metadata@0.2.2: + resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} @@ -3543,10 +3594,6 @@ packages: resolution: {integrity: sha512-FhwotcEqjr241ZbjFzjlIYg6c5/L/s4yBGWSMvJ9UoExiSqL+FnFA/CaeZx17WGaZMS/4SOZp8wH18jSS4R4lw==} engines: {node: '>=16'} - super-regex@0.2.0: - resolution: {integrity: sha512-WZzIx3rC1CvbMDloLsVw0lkZVKJWbrkJ0k1ghKFmcnPrW1+jWbgTkTEWVtD9lMdmI4jZEz40+naBxl1dCUhXXw==} - engines: {node: '>=14.16'} - supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -3584,10 +3631,6 @@ packages: through@2.3.8: resolution: {integrity: sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=} - time-span@5.1.0: - resolution: {integrity: sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==} - engines: {node: '>=12'} - tiny-worker@2.3.0: resolution: {integrity: sha512-pJ70wq5EAqTAEl9IkGzA+fN0836rycEuz2Cn6yeZ6FRzlVS5IDOkFHpIoEsksPRQV34GDqXm65+OlnZqUSyK2g==} @@ -3636,6 +3679,10 @@ packages: engines: {node: '>=18.0.0'} hasBin: true + tsyringe@4.10.0: + resolution: {integrity: sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==} + engines: {node: '>= 6.0.0'} + turndown-plugin-gfm@1.0.2: resolution: {integrity: sha512-vwz9tfvF7XN/jE0dGoBei3FXWuvll78ohzCZQuOb+ZjWrs3a0XhQVomJEb2Qh4VHTPNRO4GPZh0V7VRbiWwkRg==} @@ -5087,7 +5134,7 @@ snapshots: '@push.rocks/smartshell': 3.2.3 tsx: 4.19.3 - '@git.zone/tstest@2.3.6(@aws-sdk/credential-providers@3.812.0)(socks@2.8.7)(typescript@5.9.2)': + '@git.zone/tstest@2.3.7(@aws-sdk/credential-providers@3.812.0)(socks@2.8.7)(typescript@5.9.2)': dependencies: '@api.global/typedserver': 3.0.79 '@git.zone/tsbundle': 2.5.1 @@ -5104,6 +5151,7 @@ snapshots: '@push.rocks/smartjson': 5.0.20 '@push.rocks/smartlog': 3.1.9 '@push.rocks/smartmongo': 2.0.12(@aws-sdk/credential-providers@3.812.0)(socks@2.8.7) + '@push.rocks/smartnetwork': 4.2.0 '@push.rocks/smartpath': 6.0.0 '@push.rocks/smartpromise': 4.2.3 '@push.rocks/smartrequest': 4.3.1 @@ -5237,6 +5285,96 @@ snapshots: dependencies: pako: 1.0.11 + '@peculiar/asn1-cms@2.5.0': + dependencies: + '@peculiar/asn1-schema': 2.5.0 + '@peculiar/asn1-x509': 2.5.0 + '@peculiar/asn1-x509-attr': 2.5.0 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-csr@2.5.0': + dependencies: + '@peculiar/asn1-schema': 2.5.0 + '@peculiar/asn1-x509': 2.5.0 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-ecc@2.5.0': + dependencies: + '@peculiar/asn1-schema': 2.5.0 + '@peculiar/asn1-x509': 2.5.0 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-pfx@2.5.0': + dependencies: + '@peculiar/asn1-cms': 2.5.0 + '@peculiar/asn1-pkcs8': 2.5.0 + '@peculiar/asn1-rsa': 2.5.0 + '@peculiar/asn1-schema': 2.5.0 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-pkcs8@2.5.0': + dependencies: + '@peculiar/asn1-schema': 2.5.0 + '@peculiar/asn1-x509': 2.5.0 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-pkcs9@2.5.0': + dependencies: + '@peculiar/asn1-cms': 2.5.0 + '@peculiar/asn1-pfx': 2.5.0 + '@peculiar/asn1-pkcs8': 2.5.0 + '@peculiar/asn1-schema': 2.5.0 + '@peculiar/asn1-x509': 2.5.0 + '@peculiar/asn1-x509-attr': 2.5.0 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-rsa@2.5.0': + dependencies: + '@peculiar/asn1-schema': 2.5.0 + '@peculiar/asn1-x509': 2.5.0 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-schema@2.5.0': + dependencies: + asn1js: 3.0.6 + pvtsutils: 1.3.6 + tslib: 2.8.1 + + '@peculiar/asn1-x509-attr@2.5.0': + dependencies: + '@peculiar/asn1-schema': 2.5.0 + '@peculiar/asn1-x509': 2.5.0 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-x509@2.5.0': + dependencies: + '@peculiar/asn1-schema': 2.5.0 + asn1js: 3.0.6 + pvtsutils: 1.3.6 + tslib: 2.8.1 + + '@peculiar/x509@1.14.0': + dependencies: + '@peculiar/asn1-cms': 2.5.0 + '@peculiar/asn1-csr': 2.5.0 + '@peculiar/asn1-ecc': 2.5.0 + '@peculiar/asn1-pkcs9': 2.5.0 + '@peculiar/asn1-rsa': 2.5.0 + '@peculiar/asn1-schema': 2.5.0 + '@peculiar/asn1-x509': 2.5.0 + pvtsutils: 1.3.6 + reflect-metadata: 0.2.2 + tslib: 2.8.1 + tsyringe: 4.10.0 + '@pnpm/config.env-replace@1.1.0': {} '@pnpm/network.ca-file@1.0.2': @@ -5462,6 +5600,22 @@ snapshots: dependencies: '@push.rocks/smartpromise': 4.2.3 + '@push.rocks/smartdns@7.6.1': + dependencies: + '@push.rocks/smartdelay': 3.0.5 + '@push.rocks/smartenv': 5.0.13 + '@push.rocks/smartpromise': 4.2.3 + '@push.rocks/smartrequest': 2.1.0 + '@tsclass/tsclass': 9.2.0 + '@types/dns-packet': 5.6.5 + '@types/elliptic': 6.4.18 + acme-client: 5.4.0 + dns-packet: 5.6.1 + elliptic: 6.6.1 + minimatch: 10.0.3 + transitivePeerDependencies: + - supports-color + '@push.rocks/smartenv@5.0.13': dependencies: '@push.rocks/smartpromise': 4.2.3 @@ -5632,14 +5786,12 @@ snapshots: - supports-color - vue - '@push.rocks/smartnetwork@4.1.2': + '@push.rocks/smartnetwork@4.2.0': dependencies: '@push.rocks/smartping': 1.0.8 '@push.rocks/smartpromise': 4.2.3 '@push.rocks/smartstring': 4.0.15 - '@types/default-gateway': 7.2.2 isopen: 1.3.0 - public-ip: 7.0.1 systeminformation: 5.27.8 '@push.rocks/smartnpm@2.0.6': @@ -5694,7 +5846,7 @@ snapshots: '@push.rocks/smartbuffer': 3.0.5 '@push.rocks/smartdelay': 3.0.5 '@push.rocks/smartfile': 11.2.7 - '@push.rocks/smartnetwork': 4.1.2 + '@push.rocks/smartnetwork': 4.2.0 '@push.rocks/smartpath': 6.0.0 '@push.rocks/smartpromise': 4.2.3 '@push.rocks/smartpuppeteer': 2.0.5(typescript@5.9.2) @@ -6457,6 +6609,10 @@ snapshots: tslib: 2.8.1 optional: true + '@types/bn.js@5.2.0': + dependencies: + '@types/node': 22.15.19 + '@types/body-parser@1.19.6': dependencies: '@types/connect': 3.4.38 @@ -6481,7 +6637,13 @@ snapshots: dependencies: '@types/ms': 2.1.0 - '@types/default-gateway@7.2.2': {} + '@types/dns-packet@5.6.5': + dependencies: + '@types/node': 22.15.19 + + '@types/elliptic@6.4.18': + dependencies: + '@types/bn.js': 5.2.0 '@types/express-serve-static-core@5.0.7': dependencies: @@ -6628,6 +6790,16 @@ snapshots: mime-types: 3.0.1 negotiator: 1.0.0 + acme-client@5.4.0: + dependencies: + '@peculiar/x509': 1.14.0 + asn1js: 3.0.6 + axios: 1.12.1(debug@4.4.1) + debug: 4.4.1 + node-forge: 1.3.1 + transitivePeerDependencies: + - supports-color + agent-base@7.1.4: {} agentkeepalive@4.6.0: @@ -6658,6 +6830,12 @@ snapshots: argparse@2.0.1: {} + asn1js@3.0.6: + dependencies: + pvtsutils: 1.3.6 + pvutils: 1.1.3 + tslib: 2.8.1 + ast-types@0.13.4: dependencies: tslib: 2.8.1 @@ -6670,6 +6848,14 @@ snapshots: asynckit@0.4.0: {} + axios@1.12.1(debug@4.4.1): + dependencies: + follow-redirects: 1.15.11(debug@4.4.1) + form-data: 4.0.4 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + b4a@1.7.1: {} bail@2.0.2: {} @@ -6718,6 +6904,8 @@ snapshots: basic-ftp@5.0.5: {} + bn.js@4.12.2: {} + body-parser@2.2.0: dependencies: bytes: 3.1.2 @@ -6754,6 +6942,8 @@ snapshots: p-queue: 6.6.2 unload: 2.4.1 + brorand@1.1.0: {} + bson@6.10.4: {} buffer-crc32@0.2.13: {} @@ -6850,10 +7040,6 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - clone-regexp@3.0.0: - dependencies: - is-regexp: 3.1.0 - co@4.6.0: {} color-convert@1.9.3: @@ -6912,8 +7098,6 @@ snapshots: content-type@1.0.5: {} - convert-hrtime@5.0.0: {} - cookie-signature@1.2.2: {} cookie@0.7.2: {} @@ -7023,10 +7207,6 @@ snapshots: dependencies: '@leichtgewicht/ip-codec': 2.0.5 - dns-socket@4.2.2: - dependencies: - dns-packet: 5.6.1 - dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -7037,6 +7217,16 @@ snapshots: ee-first@1.1.1: {} + elliptic@6.6.1: + dependencies: + bn.js: 4.12.2 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -7390,8 +7580,6 @@ snapshots: function-bind@1.1.2: {} - function-timeout@0.1.1: {} - get-caller-file@2.0.5: {} get-intrinsic@1.3.0: @@ -7478,20 +7666,6 @@ snapshots: p-cancelable: 3.0.0 responselike: 3.0.0 - got@13.0.0: - dependencies: - '@sindresorhus/is': 5.6.0 - '@szmarczak/http-timer': 5.0.1 - cacheable-lookup: 7.0.0 - cacheable-request: 10.2.14 - decompress-response: 6.0.0 - form-data-encoder: 2.1.4 - get-stream: 6.0.1 - http2-wrapper: 2.2.1 - lowercase-keys: 3.0.0 - p-cancelable: 3.0.0 - responselike: 3.0.0 - graceful-fs@4.2.10: {} graceful-fs@4.2.11: {} @@ -7514,6 +7688,11 @@ snapshots: dependencies: has-symbols: 1.1.0 + hash.js@1.1.7: + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + hasown@2.0.2: dependencies: function-bind: 1.1.2 @@ -7544,6 +7723,12 @@ snapshots: he@1.2.0: {} + hmac-drbg@1.0.1: + dependencies: + hash.js: 1.1.7 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + html-minifier@4.0.0: dependencies: camel-case: 3.0.0 @@ -7630,8 +7815,6 @@ snapshots: ip-address@10.0.1: {} - ip-regex@5.0.0: {} - ipaddr.js@1.9.1: {} is-arrayish@0.2.1: {} @@ -7649,11 +7832,6 @@ snapshots: has-tostringtag: 1.0.2 safe-regex-test: 1.1.0 - is-ip@5.0.1: - dependencies: - ip-regex: 5.0.0 - super-regex: 0.2.0 - is-nan@1.3.2: dependencies: call-bind: 1.0.8 @@ -7674,8 +7852,6 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 - is-regexp@3.1.0: {} - is-stream@2.0.1: {} is-stream@4.0.1: {} @@ -8248,6 +8424,10 @@ snapshots: min-indent@1.0.1: {} + minimalistic-assert@1.0.1: {} + + minimalistic-crypto-utils@1.0.1: {} + minimatch@10.0.1: dependencies: brace-expansion: 2.0.1 @@ -8523,12 +8703,6 @@ snapshots: proxy-from-env@1.1.0: {} - public-ip@7.0.1: - dependencies: - dns-socket: 4.2.2 - got: 13.0.0 - is-ip: 5.0.1 - pump@3.0.3: dependencies: end-of-stream: 1.4.5 @@ -8570,6 +8744,12 @@ snapshots: - typescript - utf-8-validate + pvtsutils@1.3.6: + dependencies: + tslib: 2.8.1 + + pvutils@1.1.3: {} + qs@6.14.0: dependencies: side-channel: 1.1.0 @@ -8606,6 +8786,8 @@ snapshots: readdirp@4.1.2: {} + reflect-metadata@0.2.2: {} + regenerator-runtime@0.14.1: {} registry-auth-token@5.1.0: @@ -8976,12 +9158,6 @@ snapshots: '@tokenizer/token': 0.3.0 peek-readable: 5.4.2 - super-regex@0.2.0: - dependencies: - clone-regexp: 3.0.0 - function-timeout: 0.1.1 - time-span: 5.1.0 - supports-color@5.5.0: dependencies: has-flag: 3.0.0 @@ -9036,10 +9212,6 @@ snapshots: through@2.3.8: {} - time-span@5.1.0: - dependencies: - convert-hrtime: 5.0.0 - tiny-worker@2.3.0: dependencies: esm: 3.2.25 @@ -9082,6 +9254,10 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + tsyringe@4.10.0: + dependencies: + tslib: 1.14.1 + turndown-plugin-gfm@1.0.2: {} turndown@7.2.1: diff --git a/readme.md b/readme.md index b33fd6c..46dfe0a 100644 --- a/readme.md +++ b/readme.md @@ -17,9 +17,9 @@ pnpm install @push.rocks/smartnetwork --save ### ✨ Key Features - **🏎️ Speed Testing** - Measure download/upload speeds using Cloudflare's infrastructure -- **🔌 Port Management** - Check local/remote port availability, find free ports +- **🔌 Port Management** - Check local/remote port availability, find free ports (sequential or random) - **📡 Connectivity Testing** - Ping hosts, trace routes, check endpoints -- **🌍 DNS Operations** - Resolve A, AAAA, and MX records +- **🌍 DNS Operations** - Resolve A, AAAA, and MX records with smart local/remote resolution - **🔍 Network Discovery** - Get network interfaces, gateways, public IPs - **⚡ Performance Caching** - Built-in caching for expensive operations - **🔧 Plugin Architecture** - Extend functionality with custom plugins @@ -87,7 +87,7 @@ Automatically discover available ports: ```typescript const findFreePort = async () => { - // Find a free port between 3000 and 3100 + // Find a free port between 3000 and 3100 (sequential - returns first available) const freePort = await network.findFreePort(3000, 3100); if (freePort) { @@ -95,6 +95,10 @@ const findFreePort = async () => { } else { console.log('😢 No free ports available in range'); } + + // Find a random free port in range (useful to avoid port conflicts) + const randomPort = await network.findFreePort(3000, 3100, { randomize: true }); + console.log(`🎲 Random free port: ${randomPort}`); }; ``` @@ -175,7 +179,7 @@ hops.forEach(hop => { ### 🌍 DNS Operations -Resolve various DNS record types: +Resolve various DNS record types using @push.rocks/smartdns with intelligent resolution strategy: ```typescript const dnsRecords = await network.resolveDns('example.com'); @@ -188,8 +192,14 @@ console.log(' AAAA records:', dnsRecords.AAAA); // IPv6 addresses dnsRecords.MX.forEach(mx => { console.log(` 📧 Mail server: ${mx.exchange} (priority: ${mx.priority})`); }); + +// Properly handles local hostnames (localhost, etc.) +const localDns = await network.resolveDns('localhost'); +console.log(' Localhost:', localDns.A); // Returns ['127.0.0.1'] ``` +*DNS resolution uses a `prefer-system` strategy: tries system resolver first (respects /etc/hosts and local DNS), with automatic fallback to Cloudflare DoH for external domains.* + ### 🏥 HTTP/HTTPS Health Checks Monitor endpoint availability and response times: @@ -321,6 +331,10 @@ interface SmartNetworkOptions { cacheTtl?: number; // Cache TTL in milliseconds } +interface IFindFreePortOptions { + randomize?: boolean; // If true, returns a random free port instead of the first one +} + interface Hop { ttl: number; // Time to live ip: string; // IP address of the hop diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index 19b38fc..16b7fce 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@push.rocks/smartnetwork', - version: '4.2.0', + version: '4.3.0', description: 'A toolkit for network diagnostics including speed tests, port availability checks, and more.' } diff --git a/ts/smartnetwork.classes.smartnetwork.ts b/ts/smartnetwork.classes.smartnetwork.ts index a4068e6..941e16b 100644 --- a/ts/smartnetwork.classes.smartnetwork.ts +++ b/ts/smartnetwork.classes.smartnetwork.ts @@ -24,6 +24,15 @@ export interface Hop { ip: string; rtt: number | null; } + +/** + * Options for the findFreePort method + */ +export interface IFindFreePortOptions { + /** If true, selects a random available port within the range instead of the first one */ + randomize?: boolean; +} + export class SmartNetwork { /** Static registry for external plugins */ public static pluginsRegistry: Map = new Map(); @@ -148,9 +157,10 @@ export class SmartNetwork { * Find the first available port within a given range * @param startPort The start of the port range (inclusive) * @param endPort The end of the port range (inclusive) - * @returns The first available port number, or null if no ports are available + * @param options Optional configuration for port selection behavior + * @returns The first available port number (or random if options.randomize is true), or null if no ports are available */ - public async findFreePort(startPort: number, endPort: number): Promise { + public async findFreePort(startPort: number, endPort: number, options?: IFindFreePortOptions): Promise { // Validate port range if (startPort < 1 || startPort > 65535 || endPort < 1 || endPort > 65535) { throw new NetworkError('Port numbers must be between 1 and 65535', 'EINVAL'); @@ -159,16 +169,38 @@ export class SmartNetwork { throw new NetworkError('Start port must be less than or equal to end port', 'EINVAL'); } - // Check each port in the range - for (let port = startPort; port <= endPort; port++) { - const isUnused = await this.isLocalPortUnused(port); - if (isUnused) { - return port; + // If randomize option is true, collect all available ports and select randomly + if (options?.randomize) { + const availablePorts: number[] = []; + + // Scan the range to find all available ports + for (let port = startPort; port <= endPort; port++) { + const isUnused = await this.isLocalPortUnused(port); + if (isUnused) { + availablePorts.push(port); + } } + + // If there are available ports, select one randomly + if (availablePorts.length > 0) { + const randomIndex = Math.floor(Math.random() * availablePorts.length); + return availablePorts[randomIndex]; + } + + // No free port found in the range + return null; + } else { + // Default behavior: return the first available port (sequential search) + for (let port = startPort; port <= endPort; port++) { + const isUnused = await this.isLocalPortUnused(port); + if (isUnused) { + return port; + } + } + + // No free port found in the range + return null; } - - // No free port found in the range - return null; } /** @@ -277,13 +309,30 @@ export class SmartNetwork { host: string, ): Promise<{ A: string[]; AAAA: string[]; MX: { exchange: string; priority: number }[] }> { try { - const dns = await import('dns'); - const { resolve4, resolve6, resolveMx } = dns.promises; - const [A, AAAA, MX] = await Promise.all([ - resolve4(host).catch(() => []), - resolve6(host).catch(() => []), - resolveMx(host).catch(() => []), + const dnsClient = new plugins.smartdns.dnsClientMod.Smartdns({ + strategy: 'prefer-system', // Try system resolver first (handles localhost), fallback to DoH + allowDohFallback: true, + }); + + const [aRecords, aaaaRecords, mxRecords] = await Promise.all([ + dnsClient.getRecordsA(host).catch((): any[] => []), + dnsClient.getRecordsAAAA(host).catch((): any[] => []), + dnsClient.getRecords(host, 'MX').catch((): any[] => []), ]); + + // Extract values from the record objects + const A = aRecords.map((record: any) => record.value); + const AAAA = aaaaRecords.map((record: any) => record.value); + + // Parse MX records - the value contains "priority exchange" + const MX = mxRecords.map((record: any) => { + const parts = record.value.split(' '); + return { + priority: parseInt(parts[0], 10), + exchange: parts[1] || '', + }; + }); + return { A, AAAA, MX }; } catch (err: any) { throw new NetworkError(err.message, err.code); diff --git a/ts/smartnetwork.plugins.ts b/ts/smartnetwork.plugins.ts index 2a8a439..a7dfaec 100644 --- a/ts/smartnetwork.plugins.ts +++ b/ts/smartnetwork.plugins.ts @@ -6,11 +6,12 @@ import * as perfHooks from 'perf_hooks'; export { os, https, perfHooks }; // @pushrocks scope +import * as smartdns from '@push.rocks/smartdns'; import * as smartping from '@push.rocks/smartping'; import * as smartpromise from '@push.rocks/smartpromise'; import * as smartstring from '@push.rocks/smartstring'; -export { smartpromise, smartping, smartstring }; +export { smartdns, smartpromise, smartping, smartstring }; // @third party scope // @ts-ignore