@push.rocks/smartnetwork 4.5.1 → 4.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/index.d.ts +2 -0
- package/dist_ts/index.js +2 -1
- package/dist_ts/smartnetwork.classes.domainintelligence.d.ts +170 -0
- package/dist_ts/smartnetwork.classes.domainintelligence.js +542 -0
- package/dist_ts/smartnetwork.classes.ipintelligence.d.ts +9 -0
- package/dist_ts/smartnetwork.classes.ipintelligence.js +13 -8
- package/dist_ts/smartnetwork.classes.smartnetwork.d.ts +23 -2
- package/dist_ts/smartnetwork.classes.smartnetwork.js +52 -8
- package/license +1 -1
- package/package.json +1 -1
- package/readme.md +348 -276
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/index.ts +2 -0
- package/ts/smartnetwork.classes.domainintelligence.ts +659 -0
- package/ts/smartnetwork.classes.ipintelligence.ts +22 -7
- package/ts/smartnetwork.classes.smartnetwork.ts +56 -7
package/readme.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# @push.rocks/smartnetwork 🌐
|
|
2
2
|
|
|
3
|
-
Comprehensive network diagnostics and
|
|
3
|
+
Comprehensive network diagnostics and intelligence for Node.js — speed tests, port scanning, ICMP ping, traceroute, DNS, IP & domain RDAP, ASN lookups, geolocation, and DNS record enrichment in a single, promise-based toolkit.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Issue Reporting and Security
|
|
6
|
+
|
|
7
|
+
For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
## 🚀 Install
|
|
8
10
|
|
|
9
11
|
```bash
|
|
10
12
|
pnpm install @push.rocks/smartnetwork --save
|
|
@@ -12,29 +14,32 @@ pnpm install @push.rocks/smartnetwork --save
|
|
|
12
14
|
|
|
13
15
|
## 🎯 Overview
|
|
14
16
|
|
|
15
|
-
**@push.rocks/smartnetwork** is your Swiss Army knife for network diagnostics in Node.js. Whether you're building
|
|
17
|
+
**@push.rocks/smartnetwork** is your Swiss Army knife for network diagnostics in Node.js. Whether you're building monitoring dashboards, investigating IP/domain ownership, or debugging connectivity — this library has you covered with a clean, async API and zero-config setup.
|
|
18
|
+
|
|
19
|
+
Under the hood, system-level operations (ICMP ping, traceroute, raw-socket port checks, gateway detection) are powered by a bundled **Rust binary** for maximum performance and cross-platform reliability. Everything else — speed tests, DNS, public IP discovery, IP & domain intelligence, HTTP health checks — runs in pure TypeScript.
|
|
16
20
|
|
|
17
21
|
### ✨ Key Features
|
|
18
22
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
| Category | Capabilities |
|
|
24
|
+
|----------|-------------|
|
|
25
|
+
| 🏎️ **Speed Testing** | Download/upload benchmarks via Cloudflare's global infrastructure |
|
|
26
|
+
| 🔌 **Port Management** | Local/remote port checks, find free ports (sequential or random), exclusion lists |
|
|
27
|
+
| 📡 **Connectivity** | ICMP ping with stats, hop-by-hop traceroute, HTTP/HTTPS health checks |
|
|
28
|
+
| 🌍 **DNS** | A, AAAA, MX resolution with system-first + DoH fallback strategy |
|
|
29
|
+
| 🔍 **IP Intelligence** | ASN, organization, geolocation, RDAP registration — all from free public sources |
|
|
30
|
+
| 🏢 **Domain Intelligence** | RDAP registrar/registrant, nameservers, events, DNSSEC, plus DNS enrichment (A/AAAA/MX/TXT/SOA) |
|
|
31
|
+
| 🖥️ **Network Discovery** | Interfaces, default gateway, public IPv4/IPv6 |
|
|
32
|
+
| ⚡ **Caching** | Built-in TTL cache for expensive lookups |
|
|
33
|
+
| 🔧 **Extensible** | Plugin architecture for custom functionality |
|
|
34
|
+
| 📝 **TypeScript** | Full type definitions, ESM-native |
|
|
27
35
|
|
|
28
36
|
## 💻 Usage
|
|
29
37
|
|
|
30
38
|
### Basic Setup
|
|
31
39
|
|
|
32
|
-
First, import and initialize SmartNetwork:
|
|
33
|
-
|
|
34
40
|
```typescript
|
|
35
41
|
import { SmartNetwork } from '@push.rocks/smartnetwork';
|
|
36
42
|
|
|
37
|
-
// Basic instance
|
|
38
43
|
const network = new SmartNetwork();
|
|
39
44
|
|
|
40
45
|
// Start the Rust bridge (auto-started on first use, but explicit start is recommended)
|
|
@@ -42,396 +47,463 @@ await network.start();
|
|
|
42
47
|
|
|
43
48
|
// ... use the network instance ...
|
|
44
49
|
|
|
45
|
-
// Clean up when done
|
|
50
|
+
// Clean up when done — tears down both the Rust bridge and the smartdns backend
|
|
46
51
|
await network.stop();
|
|
47
|
-
|
|
48
|
-
// With caching enabled (60 seconds TTL)
|
|
49
|
-
const cachedNetwork = new SmartNetwork({ cacheTtl: 60000 });
|
|
50
52
|
```
|
|
51
53
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
Measure your network performance using Cloudflare's global infrastructure:
|
|
54
|
+
Enable caching for repeated lookups:
|
|
55
55
|
|
|
56
56
|
```typescript
|
|
57
|
-
const
|
|
58
|
-
// Quick speed test
|
|
59
|
-
const result = await network.getSpeed();
|
|
60
|
-
console.log(`Download: ${result.downloadSpeed} Mbps`);
|
|
61
|
-
console.log(`Upload: ${result.uploadSpeed} Mbps`);
|
|
62
|
-
|
|
63
|
-
// Advanced configuration
|
|
64
|
-
const advancedResult = await network.getSpeed({
|
|
65
|
-
parallelStreams: 3, // Number of concurrent connections
|
|
66
|
-
duration: 5 // Test duration in seconds
|
|
67
|
-
});
|
|
68
|
-
console.log(`Download: ${advancedResult.downloadSpeed} Mbps`);
|
|
69
|
-
console.log(`Upload: ${advancedResult.uploadSpeed} Mbps`);
|
|
70
|
-
};
|
|
57
|
+
const network = new SmartNetwork({ cacheTtl: 60000 }); // 60s TTL
|
|
71
58
|
```
|
|
72
59
|
|
|
73
|
-
|
|
60
|
+
---
|
|
74
61
|
|
|
75
|
-
|
|
62
|
+
### 🕵️ IP Intelligence
|
|
76
63
|
|
|
77
|
-
|
|
64
|
+
Get ASN, organization, geolocation, and RDAP registration data for any IPv4 address. Combines three free public data sources in parallel:
|
|
78
65
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (isUnused) {
|
|
83
|
-
console.log(`✅ Port ${port} is available`);
|
|
84
|
-
} else {
|
|
85
|
-
console.log(`❌ Port ${port} is in use`);
|
|
86
|
-
}
|
|
87
|
-
};
|
|
66
|
+
- **RDAP** — direct queries to RIRs (RIPE, ARIN, APNIC, LACNIC, AFRINIC) for authoritative registration data
|
|
67
|
+
- **Team Cymru DNS** — fast ASN resolution via DNS TXT records
|
|
68
|
+
- **MaxMind GeoLite2** — in-memory MMDB databases (auto-downloaded from CDN, periodically refreshed)
|
|
88
69
|
|
|
89
|
-
|
|
70
|
+
```typescript
|
|
71
|
+
const intel = await network.getIpIntelligence('8.8.8.8');
|
|
72
|
+
|
|
73
|
+
console.log(intel);
|
|
74
|
+
// {
|
|
75
|
+
// asn: 15169,
|
|
76
|
+
// asnOrg: 'Google LLC',
|
|
77
|
+
// registrantOrg: 'Google LLC',
|
|
78
|
+
// registrantCountry: 'United States',
|
|
79
|
+
// networkRange: '8.8.8.0/24',
|
|
80
|
+
// abuseContact: null,
|
|
81
|
+
// country: null,
|
|
82
|
+
// countryCode: 'US',
|
|
83
|
+
// city: null,
|
|
84
|
+
// latitude: 37.751,
|
|
85
|
+
// longitude: -97.822,
|
|
86
|
+
// accuracyRadius: null,
|
|
87
|
+
// timezone: 'America/Chicago'
|
|
88
|
+
// }
|
|
90
89
|
```
|
|
91
90
|
|
|
92
|
-
|
|
91
|
+
Works great for your own IP too:
|
|
93
92
|
|
|
94
|
-
|
|
93
|
+
```typescript
|
|
94
|
+
const publicIps = await network.getPublicIps();
|
|
95
|
+
if (publicIps.v4) {
|
|
96
|
+
const myIntel = await network.getIpIntelligence(publicIps.v4);
|
|
97
|
+
console.log(`You're on AS${myIntel.asn} (${myIntel.asnOrg}) in ${myIntel.city}, ${myIntel.countryCode}`);
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The `IIpIntelligenceResult` interface:
|
|
95
102
|
|
|
96
103
|
```typescript
|
|
97
|
-
|
|
98
|
-
//
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
// Combine randomize with exclude options
|
|
118
|
-
const randomWithExclusions = await network.findFreePort(3000, 3100, {
|
|
119
|
-
randomize: true,
|
|
120
|
-
exclude: [3000, 3001, 3005]
|
|
121
|
-
});
|
|
122
|
-
console.log(`🎲🚫 Random free port (with exclusions): ${randomWithExclusions}`);
|
|
123
|
-
};
|
|
104
|
+
interface IIpIntelligenceResult {
|
|
105
|
+
// ASN (Team Cymru primary, MaxMind fallback)
|
|
106
|
+
asn: number | null;
|
|
107
|
+
asnOrg: string | null;
|
|
108
|
+
|
|
109
|
+
// Registration (RDAP)
|
|
110
|
+
registrantOrg: string | null;
|
|
111
|
+
registrantCountry: string | null;
|
|
112
|
+
networkRange: string | null; // CIDR or range
|
|
113
|
+
abuseContact: string | null; // abuse email from RDAP
|
|
114
|
+
|
|
115
|
+
// Geolocation (MaxMind GeoLite2)
|
|
116
|
+
country: string | null;
|
|
117
|
+
countryCode: string | null; // ISO 3166-1 alpha-2
|
|
118
|
+
city: string | null;
|
|
119
|
+
latitude: number | null;
|
|
120
|
+
longitude: number | null;
|
|
121
|
+
accuracyRadius: number | null; // km
|
|
122
|
+
timezone: string | null; // IANA timezone
|
|
123
|
+
}
|
|
124
124
|
```
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
> 💡 The GeoLite2 databases are fetched into memory from jsDelivr CDN on first use (~32 MB total). They auto-refresh in the background every 7 days (configurable via `IpIntelligence` options). No disk I/O, no API keys, no rate limits.
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
---
|
|
129
129
|
|
|
130
|
-
|
|
131
|
-
// Method 1: Using "host:port" syntax
|
|
132
|
-
const isOpen1 = await network.isRemotePortAvailable('example.com:443');
|
|
130
|
+
### 🏢 Domain Intelligence
|
|
133
131
|
|
|
134
|
-
|
|
135
|
-
const isOpen2 = await network.isRemotePortAvailable('example.com', 443);
|
|
132
|
+
Get comprehensive domain registration and DNS data. Runs an **RDAP layer** and a **DNS layer** in parallel, then merges results:
|
|
136
133
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
port: 443,
|
|
140
|
-
protocol: 'tcp', // Only TCP is supported
|
|
141
|
-
retries: 3, // Number of connection attempts
|
|
142
|
-
timeout: 5000 // Timeout per attempt in ms
|
|
143
|
-
});
|
|
134
|
+
- **RDAP** — queries the correct registry RDAP server (discovered via the [IANA DNS bootstrap](https://data.iana.org/rdap/dns.json)) for registrar, registrant, events, status flags, DNSSEC, and abuse contacts
|
|
135
|
+
- **DNS** — queries A, AAAA, NS, MX, TXT, and SOA records via `@push.rocks/smartdns` (system resolver first, DoH fallback)
|
|
144
136
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
137
|
+
For gTLDs (`.com`, `.org`, `.net`, etc.) you get the full picture from both layers. For ccTLDs without RDAP support (`.de`, `.fr`, `.nl`, etc.), the DNS layer fills in nameservers, resolved IPs, MX, TXT, and SOA — so you still get useful intelligence even when RDAP isn't available.
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
const info = await network.getDomainIntelligence('google.com');
|
|
141
|
+
|
|
142
|
+
console.log(info);
|
|
143
|
+
// {
|
|
144
|
+
// domain: 'google.com',
|
|
145
|
+
// handle: '2138514_DOMAIN_COM-VRSN',
|
|
146
|
+
// status: ['client delete prohibited', 'server transfer prohibited', ...],
|
|
147
|
+
// registrationDate: '1997-09-15T04:00:00Z',
|
|
148
|
+
// expirationDate: '2028-09-14T04:00:00Z',
|
|
149
|
+
// lastChangedDate: '2019-09-09T15:39:04Z',
|
|
150
|
+
// registrarName: 'MarkMonitor Inc.',
|
|
151
|
+
// registrarIanaId: 292,
|
|
152
|
+
// registrantOrg: null, // often redacted under GDPR
|
|
153
|
+
// registrantCountry: null,
|
|
154
|
+
// abuseEmail: 'abusecomplaints@markmonitor.com',
|
|
155
|
+
// abusePhone: '+1.2086851750',
|
|
156
|
+
// nameservers: ['ns1.google.com', 'ns2.google.com', 'ns3.google.com', 'ns4.google.com'],
|
|
157
|
+
// dnssec: false,
|
|
158
|
+
// nameserversSource: 'rdap',
|
|
159
|
+
// resolvedIpv4: ['142.251.20.102', '142.251.20.113', ...],
|
|
160
|
+
// resolvedIpv6: ['2a00:1450:4001:c15::8b', ...],
|
|
161
|
+
// mxRecords: [{ priority: 10, exchange: 'smtp.google.com' }],
|
|
162
|
+
// txtRecords: ['v=spf1 include:_spf.google.com ~all', ...],
|
|
163
|
+
// soaRecord: 'ns1.google.com dns-admin.google.com 895796075 900 900 1800 60'
|
|
164
|
+
// }
|
|
154
165
|
```
|
|
155
166
|
|
|
156
|
-
|
|
167
|
+
Works with ccTLDs that don't have RDAP (like `.de`):
|
|
157
168
|
|
|
158
|
-
|
|
169
|
+
```typescript
|
|
170
|
+
const deInfo = await network.getDomainIntelligence('bund.de');
|
|
171
|
+
console.log(deInfo.registrarName); // null (no .de RDAP)
|
|
172
|
+
console.log(deInfo.nameservers); // ['bamberg.bund.de', 'argon.bund.de', ...]
|
|
173
|
+
console.log(deInfo.nameserversSource); // 'dns' — nameservers came from DNS, not RDAP
|
|
174
|
+
console.log(deInfo.resolvedIpv4); // ['80.245.156.34']
|
|
175
|
+
console.log(deInfo.mxRecords); // [{priority: 10, exchange: 'mx1.bund.de'}, ...]
|
|
176
|
+
```
|
|
159
177
|
|
|
160
|
-
|
|
178
|
+
Handles IDN (internationalized domain names) automatically:
|
|
161
179
|
|
|
162
180
|
```typescript
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
console.log(`RTT: ${pingResult.time} ms`);
|
|
167
|
-
|
|
168
|
-
// Detailed ping statistics
|
|
169
|
-
const pingStats = await network.ping('google.com', {
|
|
170
|
-
count: 5, // Number of pings
|
|
171
|
-
timeout: 1000 // Timeout per ping in ms
|
|
172
|
-
});
|
|
181
|
+
const idn = await network.getDomainIntelligence('münchen.de');
|
|
182
|
+
console.log(idn.domain); // 'xn--mnchen-3ya.de' — normalized to punycode
|
|
183
|
+
```
|
|
173
184
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
185
|
+
The `IDomainIntelligenceResult` interface:
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
interface IDomainIntelligenceResult {
|
|
189
|
+
domain: string | null; // normalized ASCII form
|
|
190
|
+
handle: string | null; // registry handle
|
|
191
|
+
status: string[] | null; // EPP status codes
|
|
192
|
+
|
|
193
|
+
// Registration lifecycle (ISO 8601)
|
|
194
|
+
registrationDate: string | null;
|
|
195
|
+
expirationDate: string | null;
|
|
196
|
+
lastChangedDate: string | null;
|
|
197
|
+
|
|
198
|
+
// Registrar
|
|
199
|
+
registrarName: string | null;
|
|
200
|
+
registrarIanaId: number | null;
|
|
201
|
+
|
|
202
|
+
// Registrant (often redacted under GDPR)
|
|
203
|
+
registrantOrg: string | null;
|
|
204
|
+
registrantCountry: string | null;
|
|
205
|
+
|
|
206
|
+
// Abuse contact
|
|
207
|
+
abuseEmail: string | null;
|
|
208
|
+
abusePhone: string | null;
|
|
209
|
+
|
|
210
|
+
// Technical
|
|
211
|
+
nameservers: string[] | null;
|
|
212
|
+
dnssec: boolean | null; // secureDNS.delegationSigned from RDAP
|
|
213
|
+
nameserversSource: 'rdap' | 'dns' | null;
|
|
214
|
+
|
|
215
|
+
// DNS enrichment
|
|
216
|
+
resolvedIpv4: string[] | null; // A records
|
|
217
|
+
resolvedIpv6: string[] | null; // AAAA records
|
|
218
|
+
mxRecords: { priority: number | null; exchange: string }[] | null;
|
|
219
|
+
txtRecords: string[] | null; // SPF, DKIM, site verification, etc.
|
|
220
|
+
soaRecord: string | null; // raw SOA value
|
|
221
|
+
}
|
|
180
222
|
```
|
|
181
223
|
|
|
182
|
-
|
|
224
|
+
> 💡 **RDAP vs DNS nameservers**: When RDAP is available (most gTLDs), `nameservers` comes from the registry's authoritative parent-zone delegation (`nameserversSource: 'rdap'`). When RDAP is unavailable (many ccTLDs), the DNS layer fills in nameservers via NS record resolution (`nameserversSource: 'dns'`). The `nameserversSource` field tells you which source won.
|
|
183
225
|
|
|
184
|
-
|
|
226
|
+
---
|
|
185
227
|
|
|
186
|
-
|
|
187
|
-
const hops = await network.traceroute('google.com', {
|
|
188
|
-
maxHops: 10, // Maximum number of hops
|
|
189
|
-
timeout: 5000 // Timeout in ms
|
|
190
|
-
});
|
|
228
|
+
### 🏎️ Speed Testing
|
|
191
229
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
230
|
+
Measure network performance via Cloudflare's global infrastructure:
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
const result = await network.getSpeed();
|
|
234
|
+
console.log(`⬇️ Download: ${result.downloadSpeed} Mbps`);
|
|
235
|
+
console.log(`⬆️ Upload: ${result.uploadSpeed} Mbps`);
|
|
236
|
+
|
|
237
|
+
// Advanced: parallel streams + fixed duration
|
|
238
|
+
const advanced = await network.getSpeed({
|
|
239
|
+
parallelStreams: 3,
|
|
240
|
+
duration: 5,
|
|
196
241
|
});
|
|
197
242
|
```
|
|
198
243
|
|
|
199
|
-
|
|
244
|
+
---
|
|
200
245
|
|
|
201
|
-
###
|
|
246
|
+
### 🔌 Port Management
|
|
202
247
|
|
|
203
|
-
|
|
248
|
+
#### Check Local Port Availability
|
|
204
249
|
|
|
205
|
-
|
|
206
|
-
const dnsRecords = await network.resolveDns('example.com');
|
|
250
|
+
Checks both IPv4 and IPv6:
|
|
207
251
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
console.log('
|
|
252
|
+
```typescript
|
|
253
|
+
const isUnused = await network.isLocalPortUnused(8080);
|
|
254
|
+
console.log(isUnused ? '✅ Port 8080 is free' : '❌ Port 8080 is in use');
|
|
255
|
+
```
|
|
211
256
|
|
|
212
|
-
|
|
213
|
-
dnsRecords.MX.forEach(mx => {
|
|
214
|
-
console.log(` 📧 Mail server: ${mx.exchange} (priority: ${mx.priority})`);
|
|
215
|
-
});
|
|
257
|
+
#### Find Free Port in Range
|
|
216
258
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
```
|
|
259
|
+
```typescript
|
|
260
|
+
// First available
|
|
261
|
+
const port = await network.findFreePort(3000, 3100);
|
|
221
262
|
|
|
222
|
-
|
|
263
|
+
// Random pick (avoids clustering)
|
|
264
|
+
const randomPort = await network.findFreePort(3000, 3100, { randomize: true });
|
|
223
265
|
|
|
224
|
-
|
|
266
|
+
// With exclusions
|
|
267
|
+
const port2 = await network.findFreePort(3000, 3100, {
|
|
268
|
+
randomize: true,
|
|
269
|
+
exclude: [3000, 3001, 3005],
|
|
270
|
+
});
|
|
271
|
+
```
|
|
225
272
|
|
|
226
|
-
|
|
273
|
+
#### Check Remote Port
|
|
227
274
|
|
|
228
275
|
```typescript
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
});
|
|
276
|
+
// Simple
|
|
277
|
+
const isOpen = await network.isRemotePortAvailable('example.com', 443);
|
|
232
278
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
279
|
+
// With retries and timeout
|
|
280
|
+
const isOpen2 = await network.isRemotePortAvailable('example.com', {
|
|
281
|
+
port: 443,
|
|
282
|
+
retries: 3,
|
|
283
|
+
timeout: 5000,
|
|
284
|
+
});
|
|
237
285
|
```
|
|
238
286
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
#### Get All Network Interfaces
|
|
287
|
+
---
|
|
242
288
|
|
|
243
|
-
|
|
289
|
+
### 📡 Ping & Traceroute
|
|
244
290
|
|
|
245
291
|
```typescript
|
|
246
|
-
|
|
292
|
+
// Simple ping
|
|
293
|
+
const ping = await network.ping('google.com');
|
|
294
|
+
console.log(`Alive: ${ping.alive}, RTT: ${ping.time} ms`);
|
|
247
295
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
296
|
+
// Multi-ping with statistics
|
|
297
|
+
const stats = await network.ping('google.com', { count: 10, timeout: 2000 });
|
|
298
|
+
console.log(`📊 min=${stats.min} avg=${stats.avg.toFixed(1)} max=${stats.max} loss=${stats.packetLoss}%`);
|
|
299
|
+
|
|
300
|
+
// Traceroute
|
|
301
|
+
const hops = await network.traceroute('google.com', { maxHops: 20 });
|
|
302
|
+
hops.forEach(hop => {
|
|
303
|
+
const rtt = hop.rtt === null ? '*' : `${hop.rtt} ms`;
|
|
304
|
+
console.log(` ${hop.ttl}\t${hop.ip}\t${rtt}`);
|
|
255
305
|
});
|
|
256
306
|
```
|
|
257
307
|
|
|
258
|
-
|
|
308
|
+
> ⚠️ ICMP ping requires `CAP_NET_RAW` or appropriate `ping_group_range` sysctl on Linux.
|
|
259
309
|
|
|
260
|
-
|
|
310
|
+
---
|
|
261
311
|
|
|
262
|
-
|
|
263
|
-
const defaultGateway = await network.getDefaultGateway();
|
|
312
|
+
### 🌍 DNS Resolution
|
|
264
313
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
314
|
+
Uses `@push.rocks/smartdns` with a system-first strategy and automatic DoH (DNS-over-HTTPS) fallback:
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
const dns = await network.resolveDns('example.com');
|
|
318
|
+
console.log('A records:', dns.A); // ['93.184.216.34']
|
|
319
|
+
console.log('AAAA records:', dns.AAAA); // ['2606:2800:220:1:248:1893:25c8:1946']
|
|
320
|
+
dns.MX.forEach(mx => {
|
|
321
|
+
console.log(`📧 ${mx.exchange} (priority ${mx.priority})`);
|
|
322
|
+
});
|
|
270
323
|
```
|
|
271
324
|
|
|
272
|
-
|
|
325
|
+
---
|
|
273
326
|
|
|
274
|
-
|
|
327
|
+
### 🏥 HTTP/HTTPS Health Checks
|
|
275
328
|
|
|
276
329
|
```typescript
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
console.log(`
|
|
330
|
+
const health = await network.checkEndpoint('https://api.example.com/health', {
|
|
331
|
+
timeout: 5000,
|
|
332
|
+
rejectUnauthorized: true,
|
|
333
|
+
});
|
|
334
|
+
console.log(`Status: ${health.status}, RTT: ${health.rtt.toFixed(0)} ms`);
|
|
282
335
|
```
|
|
283
336
|
|
|
284
|
-
|
|
337
|
+
---
|
|
285
338
|
|
|
286
|
-
|
|
339
|
+
### 🖥️ Network Interfaces & Public IPs
|
|
287
340
|
|
|
288
341
|
```typescript
|
|
289
|
-
//
|
|
290
|
-
const
|
|
342
|
+
// All interfaces
|
|
343
|
+
const gateways = await network.getGateways();
|
|
344
|
+
Object.entries(gateways).forEach(([name, ifaces]) => {
|
|
345
|
+
console.log(`🔌 ${name}:`);
|
|
346
|
+
ifaces.forEach(i => console.log(` ${i.family}: ${i.address}`));
|
|
347
|
+
});
|
|
291
348
|
|
|
292
|
-
//
|
|
293
|
-
const
|
|
294
|
-
|
|
349
|
+
// Default gateway
|
|
350
|
+
const gw = await network.getDefaultGateway();
|
|
351
|
+
if (gw) {
|
|
352
|
+
console.log(`🌐 Gateway IPv4: ${gw.ipv4.address}`);
|
|
353
|
+
}
|
|
295
354
|
|
|
296
|
-
//
|
|
297
|
-
const
|
|
298
|
-
|
|
355
|
+
// Public IPs (multiple fallback services: ipify, ident.me, seeip, icanhazip)
|
|
356
|
+
const publicIps = await network.getPublicIps();
|
|
357
|
+
console.log(`🌍 IPv4: ${publicIps.v4 || 'N/A'}`);
|
|
358
|
+
console.log(`🌍 IPv6: ${publicIps.v6 || 'N/A'}`);
|
|
299
359
|
```
|
|
300
360
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
Extend SmartNetwork with custom functionality:
|
|
361
|
+
---
|
|
304
362
|
|
|
305
|
-
|
|
306
|
-
// Define your plugin
|
|
307
|
-
class CustomNetworkPlugin {
|
|
308
|
-
constructor(private smartNetwork: SmartNetwork) {}
|
|
309
|
-
|
|
310
|
-
async customMethod() {
|
|
311
|
-
// Your custom network logic here
|
|
312
|
-
return 'Custom result';
|
|
313
|
-
}
|
|
314
|
-
}
|
|
363
|
+
### ⚡ Caching
|
|
315
364
|
|
|
316
|
-
|
|
317
|
-
SmartNetwork.registerPlugin('customPlugin', CustomNetworkPlugin);
|
|
365
|
+
Caching applies to `getGateways()`, `getPublicIps()`, `getIpIntelligence()`, and `getDomainIntelligence()`:
|
|
318
366
|
|
|
319
|
-
|
|
320
|
-
const network = new SmartNetwork();
|
|
321
|
-
const PluginClass = SmartNetwork.pluginsRegistry.get('customPlugin');
|
|
322
|
-
const plugin = new PluginClass(network);
|
|
323
|
-
await plugin.customMethod();
|
|
367
|
+
```typescript
|
|
368
|
+
const network = new SmartNetwork({ cacheTtl: 60000 }); // 60s
|
|
324
369
|
|
|
325
|
-
|
|
326
|
-
|
|
370
|
+
const ips1 = await network.getPublicIps(); // fetches
|
|
371
|
+
const ips2 = await network.getPublicIps(); // cache hit ⚡
|
|
327
372
|
```
|
|
328
373
|
|
|
329
|
-
|
|
374
|
+
---
|
|
330
375
|
|
|
331
|
-
|
|
376
|
+
### 🚨 Error Handling
|
|
332
377
|
|
|
333
378
|
```typescript
|
|
334
|
-
import { NetworkError } from '@push.rocks/smartnetwork';
|
|
379
|
+
import { SmartNetwork, NetworkError, TimeoutError } from '@push.rocks/smartnetwork';
|
|
335
380
|
|
|
336
381
|
try {
|
|
337
382
|
await network.isRemotePortAvailable('example.com', { protocol: 'udp' });
|
|
338
383
|
} catch (error) {
|
|
339
384
|
if (error instanceof NetworkError) {
|
|
340
|
-
console.error(
|
|
341
|
-
console.error(` Error code: ${error.code}`);
|
|
385
|
+
console.error(`${error.message} (code: ${error.code})`); // ENOTSUP
|
|
342
386
|
}
|
|
343
387
|
}
|
|
344
388
|
```
|
|
345
389
|
|
|
346
|
-
|
|
390
|
+
Error codes: `EINVAL` (invalid argument), `ENOTSUP` (not supported), `ETIMEOUT` (timeout).
|
|
391
|
+
|
|
392
|
+
---
|
|
347
393
|
|
|
348
|
-
|
|
394
|
+
### 🔧 Plugin Architecture
|
|
349
395
|
|
|
350
396
|
```typescript
|
|
351
|
-
|
|
352
|
-
|
|
397
|
+
class MyPlugin {
|
|
398
|
+
constructor(private network: SmartNetwork) {}
|
|
399
|
+
async doStuff() { /* ... */ }
|
|
353
400
|
}
|
|
354
401
|
|
|
355
|
-
|
|
356
|
-
randomize?: boolean; // If true, returns a random free port instead of the first one
|
|
357
|
-
exclude?: number[]; // Array of port numbers to exclude from the search
|
|
358
|
-
}
|
|
402
|
+
SmartNetwork.registerPlugin('myPlugin', MyPlugin);
|
|
359
403
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
rtt: number | null; // Round trip time in ms
|
|
364
|
-
}
|
|
404
|
+
const PluginClass = SmartNetwork.pluginsRegistry.get('myPlugin');
|
|
405
|
+
const plugin = new PluginClass(network);
|
|
406
|
+
await plugin.doStuff();
|
|
365
407
|
|
|
366
|
-
|
|
408
|
+
SmartNetwork.unregisterPlugin('myPlugin');
|
|
367
409
|
```
|
|
368
410
|
|
|
369
|
-
|
|
411
|
+
---
|
|
370
412
|
|
|
371
|
-
###
|
|
413
|
+
### 📝 Custom Logging
|
|
414
|
+
|
|
415
|
+
Replace the default `console` logger:
|
|
372
416
|
|
|
373
417
|
```typescript
|
|
374
|
-
|
|
418
|
+
import { setLogger } from '@push.rocks/smartnetwork';
|
|
419
|
+
|
|
420
|
+
setLogger({
|
|
421
|
+
debug: (msg) => myLogger.debug(msg),
|
|
422
|
+
info: (msg) => myLogger.info(msg),
|
|
423
|
+
warn: (msg) => myLogger.warn(msg),
|
|
424
|
+
error: (msg) => myLogger.error(msg),
|
|
425
|
+
});
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
## 🛠️ Advanced Example: Network Monitor
|
|
431
|
+
|
|
432
|
+
```typescript
|
|
433
|
+
const monitor = async () => {
|
|
375
434
|
const network = new SmartNetwork({ cacheTtl: 30000 });
|
|
376
|
-
|
|
435
|
+
|
|
377
436
|
// Check critical services
|
|
378
437
|
const services = [
|
|
379
|
-
{ name: 'Web
|
|
380
|
-
{ name: '
|
|
381
|
-
{ name: 'Cache', host: 'redis.internal', port: 6379 }
|
|
438
|
+
{ name: 'Web', host: 'example.com', port: 443 },
|
|
439
|
+
{ name: 'DB', host: 'db.internal', port: 5432 },
|
|
382
440
|
];
|
|
383
|
-
|
|
384
|
-
for (const
|
|
385
|
-
const
|
|
386
|
-
console.log(`${
|
|
441
|
+
|
|
442
|
+
for (const svc of services) {
|
|
443
|
+
const up = await network.isRemotePortAvailable(svc.host, svc.port);
|
|
444
|
+
console.log(`${svc.name}: ${up ? '✅ UP' : '❌ DOWN'}`);
|
|
387
445
|
}
|
|
388
|
-
|
|
389
|
-
//
|
|
446
|
+
|
|
447
|
+
// Internet connectivity + latency
|
|
390
448
|
const ping = await network.ping('8.8.8.8');
|
|
391
|
-
console.log(`Internet: ${ping.alive ? '✅
|
|
392
|
-
|
|
393
|
-
//
|
|
449
|
+
console.log(`Internet: ${ping.alive ? '✅' : '❌'} (${ping.time} ms)`);
|
|
450
|
+
|
|
451
|
+
// Speed
|
|
394
452
|
const speed = await network.getSpeed();
|
|
395
|
-
console.log(`Speed: ⬇️ ${speed.downloadSpeed}
|
|
396
|
-
};
|
|
453
|
+
console.log(`Speed: ⬇️ ${speed.downloadSpeed} / ⬆️ ${speed.uploadSpeed} Mbps`);
|
|
397
454
|
|
|
398
|
-
//
|
|
399
|
-
|
|
400
|
-
|
|
455
|
+
// Who am I?
|
|
456
|
+
const ips = await network.getPublicIps();
|
|
457
|
+
if (ips.v4) {
|
|
458
|
+
const intel = await network.getIpIntelligence(ips.v4);
|
|
459
|
+
console.log(`AS${intel.asn} (${intel.asnOrg}) — ${intel.city || intel.countryCode}`);
|
|
460
|
+
}
|
|
401
461
|
|
|
402
|
-
|
|
462
|
+
// Domain recon
|
|
463
|
+
const domain = await network.getDomainIntelligence('example.com');
|
|
464
|
+
console.log(`Registrar: ${domain.registrarName}, expires: ${domain.expirationDate}`);
|
|
465
|
+
console.log(`Nameservers (${domain.nameserversSource}):`, domain.nameservers);
|
|
403
466
|
|
|
404
|
-
|
|
405
|
-
const discoverServices = async () => {
|
|
406
|
-
const network = new SmartNetwork();
|
|
407
|
-
const commonPorts = [22, 80, 443, 3000, 3306, 5432, 6379, 8080, 9200];
|
|
408
|
-
|
|
409
|
-
console.log('🔍 Scanning local services...');
|
|
410
|
-
|
|
411
|
-
for (const port of commonPorts) {
|
|
412
|
-
const isUsed = !(await network.isLocalPortUnused(port));
|
|
413
|
-
if (isUsed) {
|
|
414
|
-
console.log(` Port ${port}: In use (possible service running)`);
|
|
415
|
-
}
|
|
416
|
-
}
|
|
467
|
+
await network.stop();
|
|
417
468
|
};
|
|
418
469
|
```
|
|
419
470
|
|
|
471
|
+
## 📋 Full API Reference
|
|
472
|
+
|
|
473
|
+
| Method | Description | Requires Rust |
|
|
474
|
+
|--------|-------------|:---:|
|
|
475
|
+
| `start()` / `stop()` | Start/stop the Rust bridge and smartdns backend | — |
|
|
476
|
+
| `getSpeed(opts?)` | Cloudflare speed test (download + upload) | No |
|
|
477
|
+
| `ping(host, opts?)` | ICMP ping with optional multi-ping stats | Yes |
|
|
478
|
+
| `traceroute(host, opts?)` | Hop-by-hop network path analysis | Yes |
|
|
479
|
+
| `isLocalPortUnused(port)` | Check if local port is free (IPv4+IPv6) | Yes |
|
|
480
|
+
| `findFreePort(start, end, opts?)` | Find available port in range | Yes |
|
|
481
|
+
| `isRemotePortAvailable(target, opts?)` | TCP port check on remote host | Yes |
|
|
482
|
+
| `getGateways()` | List all network interfaces | No |
|
|
483
|
+
| `getDefaultGateway()` | Get default gateway info | Yes |
|
|
484
|
+
| `getPublicIps()` | Discover public IPv4/IPv6 (4 fallback services) | No |
|
|
485
|
+
| `resolveDns(host)` | Resolve A, AAAA, MX records | No |
|
|
486
|
+
| `checkEndpoint(url, opts?)` | HTTP/HTTPS health check with RTT | No |
|
|
487
|
+
| `getIpIntelligence(ip)` | ASN + org + geo + RDAP registration | No |
|
|
488
|
+
| `getDomainIntelligence(domain)` | Registrar, nameservers, events, DNS records, DNSSEC | No |
|
|
489
|
+
|
|
420
490
|
## License and Legal Information
|
|
421
491
|
|
|
422
|
-
This repository contains open-source code
|
|
492
|
+
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](./LICENSE) file.
|
|
423
493
|
|
|
424
494
|
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
|
425
495
|
|
|
426
496
|
### Trademarks
|
|
427
497
|
|
|
428
|
-
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein.
|
|
498
|
+
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
|
|
499
|
+
|
|
500
|
+
Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
|
|
429
501
|
|
|
430
502
|
### Company Information
|
|
431
503
|
|
|
432
504
|
Task Venture Capital GmbH
|
|
433
|
-
Registered at District
|
|
505
|
+
Registered at District Court Bremen HRB 35230 HB, Germany
|
|
434
506
|
|
|
435
|
-
For any legal inquiries or
|
|
507
|
+
For any legal inquiries or further information, please contact us via email at hello@task.vc.
|
|
436
508
|
|
|
437
|
-
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
|
509
|
+
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|