@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/readme.md CHANGED
@@ -1,10 +1,12 @@
1
1
  # @push.rocks/smartnetwork 🌐
2
2
 
3
- Comprehensive network diagnostics and utilities for Node.js applications
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
- ## 🚀 Install
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
- To install `@push.rocks/smartnetwork`, run the following command in your terminal:
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 network monitoring tools, implementing health checks, or just need to debug connectivity issues, this library has you covered with a clean, promise-based API.
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
- - **🏎️ Speed Testing** - Measure download/upload speeds using Cloudflare's infrastructure
20
- - **🔌 Port Management** - Check local/remote port availability, find free ports (sequential or random)
21
- - **📡 Connectivity Testing** - Ping hosts, trace routes, check endpoints
22
- - **🌍 DNS Operations** - Resolve A, AAAA, and MX records with smart local/remote resolution
23
- - **🔍 Network Discovery** - Get network interfaces, gateways, public IPs
24
- - **⚡ Performance Caching** - Built-in caching for expensive operations
25
- - **🔧 Plugin Architecture** - Extend functionality with custom plugins
26
- - **📝 Full TypeScript Support** - Complete type definitions included
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 (stops the Rust bridge process)
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
- ### 🏎️ Network Speed Testing
53
-
54
- Measure your network performance using Cloudflare's global infrastructure:
54
+ Enable caching for repeated lookups:
55
55
 
56
56
  ```typescript
57
- const speedTest = async () => {
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
- ### 🔌 Port Management
60
+ ---
74
61
 
75
- #### Check Local Port Availability
62
+ ### 🕵️ IP Intelligence
76
63
 
77
- Verify if a port is available on your local machine (checks both IPv4 and IPv6):
64
+ Get ASN, organization, geolocation, and RDAP registration data for any IPv4 address. Combines three free public data sources in parallel:
78
65
 
79
- ```typescript
80
- const checkLocalPort = async (port: number) => {
81
- const isUnused = await network.isLocalPortUnused(port);
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
- await checkLocalPort(8080);
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
- #### Find Free Port in Range
91
+ Works great for your own IP too:
93
92
 
94
- Automatically discover available ports:
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
- const findFreePort = async () => {
98
- // Find a free port between 3000 and 3100 (sequential - returns first available)
99
- const freePort = await network.findFreePort(3000, 3100);
100
-
101
- if (freePort) {
102
- console.log(`🎉 Found free port: ${freePort}`);
103
- } else {
104
- console.log('😢 No free ports available in range');
105
- }
106
-
107
- // Find a random free port in range (useful to avoid port conflicts)
108
- const randomPort = await network.findFreePort(3000, 3100, { randomize: true });
109
- console.log(`🎲 Random free port: ${randomPort}`);
110
-
111
- // Exclude specific ports from the search
112
- const portWithExclusions = await network.findFreePort(3000, 3100, {
113
- exclude: [3000, 3001, 3005] // Skip these ports even if they're free
114
- });
115
- console.log(`🚫 Free port (excluding specific ports): ${portWithExclusions}`);
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
- #### Check Remote Port Availability
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
- Test if services are accessible on remote servers:
128
+ ---
129
129
 
130
- ```typescript
131
- // Method 1: Using "host:port" syntax
132
- const isOpen1 = await network.isRemotePortAvailable('example.com:443');
130
+ ### 🏢 Domain Intelligence
133
131
 
134
- // Method 2: Using separate host and port
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
- // Method 3: With advanced options
138
- const isOpen3 = await network.isRemotePortAvailable('example.com', {
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
- // Note: UDP is not supported
146
- try {
147
- await network.isRemotePortAvailable('example.com', {
148
- port: 53,
149
- protocol: 'udp'
150
- });
151
- } catch (e) {
152
- console.error('UDP not supported:', e.code); // ENOTSUP
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
- ### 📡 Network Connectivity
167
+ Works with ccTLDs that don't have RDAP (like `.de`):
157
168
 
158
- #### Ping Operations
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
- Test connectivity and measure latency:
178
+ Handles IDN (internationalized domain names) automatically:
161
179
 
162
180
  ```typescript
163
- // Simple ping
164
- const pingResult = await network.ping('google.com');
165
- console.log(`Host alive: ${pingResult.alive}`);
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
- console.log(`📊 Ping Statistics:`);
175
- console.log(` Packet loss: ${pingStats.packetLoss}%`);
176
- console.log(` Min: ${pingStats.min} ms`);
177
- console.log(` Max: ${pingStats.max} ms`);
178
- console.log(` Avg: ${pingStats.avg.toFixed(2)} ms`);
179
- console.log(` Stddev: ${pingStats.stddev.toFixed(2)} ms`);
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
- #### Traceroute
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
- Analyze network paths hop-by-hop:
226
+ ---
185
227
 
186
- ```typescript
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
- console.log('🛤️ Route to destination:');
193
- hops.forEach(hop => {
194
- const rtt = hop.rtt === null ? '*' : `${hop.rtt} ms`;
195
- console.log(` ${hop.ttl}\t${hop.ip}\t${rtt}`);
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
- *Note: Falls back to a single-hop stub if the `traceroute` binary is unavailable.*
244
+ ---
200
245
 
201
- ### 🌍 DNS Operations
246
+ ### 🔌 Port Management
202
247
 
203
- Resolve various DNS record types using @push.rocks/smartdns with intelligent resolution strategy:
248
+ #### Check Local Port Availability
204
249
 
205
- ```typescript
206
- const dnsRecords = await network.resolveDns('example.com');
250
+ Checks both IPv4 and IPv6:
207
251
 
208
- console.log('🔍 DNS Records:');
209
- console.log(' A records:', dnsRecords.A); // IPv4 addresses
210
- console.log(' AAAA records:', dnsRecords.AAAA); // IPv6 addresses
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
- // MX records include priority
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
- // Properly handles local hostnames (localhost, etc.)
218
- const localDns = await network.resolveDns('localhost');
219
- console.log(' Localhost:', localDns.A); // Returns ['127.0.0.1']
220
- ```
259
+ ```typescript
260
+ // First available
261
+ const port = await network.findFreePort(3000, 3100);
221
262
 
222
- *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.*
263
+ // Random pick (avoids clustering)
264
+ const randomPort = await network.findFreePort(3000, 3100, { randomize: true });
223
265
 
224
- ### 🏥 HTTP/HTTPS Health Checks
266
+ // With exclusions
267
+ const port2 = await network.findFreePort(3000, 3100, {
268
+ randomize: true,
269
+ exclude: [3000, 3001, 3005],
270
+ });
271
+ ```
225
272
 
226
- Monitor endpoint availability and response times:
273
+ #### Check Remote Port
227
274
 
228
275
  ```typescript
229
- const health = await network.checkEndpoint('https://api.example.com/health', {
230
- timeout: 5000 // Request timeout in ms
231
- });
276
+ // Simple
277
+ const isOpen = await network.isRemotePortAvailable('example.com', 443);
232
278
 
233
- console.log(`🩺 Endpoint Health:`);
234
- console.log(` Status: ${health.status}`);
235
- console.log(` RTT: ${health.rtt} ms`);
236
- console.log(` Headers:`, health.headers);
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
- ### 🖥️ Network Interface Information
240
-
241
- #### Get All Network Interfaces
287
+ ---
242
288
 
243
- List all network adapters on the system:
289
+ ### 📡 Ping & Traceroute
244
290
 
245
291
  ```typescript
246
- const gateways = await network.getGateways();
292
+ // Simple ping
293
+ const ping = await network.ping('google.com');
294
+ console.log(`Alive: ${ping.alive}, RTT: ${ping.time} ms`);
247
295
 
248
- Object.entries(gateways).forEach(([name, interfaces]) => {
249
- console.log(`🔌 Interface: ${name}`);
250
- interfaces.forEach(iface => {
251
- console.log(` ${iface.family}: ${iface.address}`);
252
- console.log(` Netmask: ${iface.netmask}`);
253
- console.log(` MAC: ${iface.mac}`);
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
- #### Get Default Gateway
308
+ > ⚠️ ICMP ping requires `CAP_NET_RAW` or appropriate `ping_group_range` sysctl on Linux.
259
309
 
260
- Retrieve the primary network interface:
310
+ ---
261
311
 
262
- ```typescript
263
- const defaultGateway = await network.getDefaultGateway();
312
+ ### 🌍 DNS Resolution
264
313
 
265
- if (defaultGateway) {
266
- console.log('🌐 Default Gateway:');
267
- console.log(' IPv4:', defaultGateway.ipv4.address);
268
- console.log(' IPv6:', defaultGateway.ipv6.address);
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
- ### 🌎 Public IP Discovery
325
+ ---
273
326
 
274
- Discover your public-facing IP addresses:
327
+ ### 🏥 HTTP/HTTPS Health Checks
275
328
 
276
329
  ```typescript
277
- const publicIps = await network.getPublicIps();
278
-
279
- console.log(`🌍 Public IPs:`);
280
- console.log(` IPv4: ${publicIps.v4 || 'Not available'}`);
281
- console.log(` IPv6: ${publicIps.v6 || 'Not available'}`);
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
- ### ⚡ Performance Caching
337
+ ---
285
338
 
286
- Reduce network calls with built-in caching:
339
+ ### 🖥️ Network Interfaces & Public IPs
287
340
 
288
341
  ```typescript
289
- // Create instance with 60-second cache TTL
290
- const cachedNetwork = new SmartNetwork({ cacheTtl: 60000 });
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
- // First call fetches from network
293
- const gateways1 = await cachedNetwork.getGateways();
294
- const publicIps1 = await cachedNetwork.getPublicIps();
349
+ // Default gateway
350
+ const gw = await network.getDefaultGateway();
351
+ if (gw) {
352
+ console.log(`🌐 Gateway IPv4: ${gw.ipv4.address}`);
353
+ }
295
354
 
296
- // Subsequent calls within 60 seconds use cache
297
- const gateways2 = await cachedNetwork.getGateways(); // From cache ⚡
298
- const publicIps2 = await cachedNetwork.getPublicIps(); // From cache ⚡
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
- ### 🔧 Plugin Architecture
302
-
303
- Extend SmartNetwork with custom functionality:
361
+ ---
304
362
 
305
- ```typescript
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
- // Register the plugin
317
- SmartNetwork.registerPlugin('customPlugin', CustomNetworkPlugin);
365
+ Caching applies to `getGateways()`, `getPublicIps()`, `getIpIntelligence()`, and `getDomainIntelligence()`:
318
366
 
319
- // Use the plugin
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
- // Clean up when done
326
- SmartNetwork.unregisterPlugin('customPlugin');
370
+ const ips1 = await network.getPublicIps(); // fetches
371
+ const ips2 = await network.getPublicIps(); // cache hit ⚡
327
372
  ```
328
373
 
329
- ### 🚨 Error Handling
374
+ ---
330
375
 
331
- Handle network errors gracefully with custom error types:
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(`❌ Network error: ${error.message}`);
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
- ### 📚 TypeScript Support
390
+ Error codes: `EINVAL` (invalid argument), `ENOTSUP` (not supported), `ETIMEOUT` (timeout).
391
+
392
+ ---
347
393
 
348
- This package is written in TypeScript and provides comprehensive type definitions:
394
+ ### 🔧 Plugin Architecture
349
395
 
350
396
  ```typescript
351
- interface SmartNetworkOptions {
352
- cacheTtl?: number; // Cache TTL in milliseconds
397
+ class MyPlugin {
398
+ constructor(private network: SmartNetwork) {}
399
+ async doStuff() { /* ... */ }
353
400
  }
354
401
 
355
- interface IFindFreePortOptions {
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
- interface Hop {
361
- ttl: number; // Time to live
362
- ip: string; // IP address of the hop
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
- // ... and many more types for complete type safety
408
+ SmartNetwork.unregisterPlugin('myPlugin');
367
409
  ```
368
410
 
369
- ## 🛠️ Advanced Examples
411
+ ---
370
412
 
371
- ### Building a Network Monitor
413
+ ### 📝 Custom Logging
414
+
415
+ Replace the default `console` logger:
372
416
 
373
417
  ```typescript
374
- const monitorNetwork = async () => {
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 Server', host: 'example.com', port: 443 },
380
- { name: 'Database', host: 'db.internal', port: 5432 },
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 service of services) {
385
- const isUp = await network.isRemotePortAvailable(service.host, service.port);
386
- console.log(`${service.name}: ${isUp ? '✅ UP' : '❌ DOWN'}`);
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
- // Check internet connectivity
446
+
447
+ // Internet connectivity + latency
390
448
  const ping = await network.ping('8.8.8.8');
391
- console.log(`Internet: ${ping.alive ? '✅ Connected' : '❌ Disconnected'}`);
392
-
393
- // Measure network performance
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} Mbps / ⬆️ ${speed.uploadSpeed} Mbps`);
396
- };
453
+ console.log(`Speed: ⬇️ ${speed.downloadSpeed} / ⬆️ ${speed.uploadSpeed} Mbps`);
397
454
 
398
- // Run monitor every minute
399
- setInterval(monitorNetwork, 60000);
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
- ### Service Discovery
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
- ```typescript
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 that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
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. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
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 court Bremen HRB 35230 HB, Germany
505
+ Registered at District Court Bremen HRB 35230 HB, Germany
434
506
 
435
- For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
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.