@push.rocks/smartnetwork 4.5.1 β 4.5.2
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/license +1 -1
- package/package.json +1 -1
- package/readme.md +251 -284
- package/ts/00_commitinfo_data.ts +1 -1
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartnetwork',
|
|
6
|
-
version: '4.5.
|
|
6
|
+
version: '4.5.2',
|
|
7
7
|
description: 'A toolkit for network diagnostics including speed tests, port availability checks, and more.'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSwwQkFBMEI7SUFDaEMsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLDhGQUE4RjtDQUM1RyxDQUFBIn0=
|
package/license
CHANGED
package/package.json
CHANGED
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 IP intelligence for Node.js β speed tests, port scanning, ICMP ping, traceroute, DNS, RDAP, ASN lookups, and geolocation 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,31 @@ 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 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 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
|
+
| π₯οΈ **Network Discovery** | Interfaces, default gateway, public IPv4/IPv6 |
|
|
31
|
+
| β‘ **Caching** | Built-in TTL cache for expensive lookups |
|
|
32
|
+
| π§ **Extensible** | Plugin architecture for custom functionality |
|
|
33
|
+
| π **TypeScript** | Full type definitions, ESM-native |
|
|
27
34
|
|
|
28
35
|
## π» Usage
|
|
29
36
|
|
|
30
37
|
### Basic Setup
|
|
31
38
|
|
|
32
|
-
First, import and initialize SmartNetwork:
|
|
33
|
-
|
|
34
39
|
```typescript
|
|
35
40
|
import { SmartNetwork } from '@push.rocks/smartnetwork';
|
|
36
41
|
|
|
37
|
-
// Basic instance
|
|
38
42
|
const network = new SmartNetwork();
|
|
39
43
|
|
|
40
44
|
// Start the Rust bridge (auto-started on first use, but explicit start is recommended)
|
|
@@ -42,396 +46,359 @@ await network.start();
|
|
|
42
46
|
|
|
43
47
|
// ... use the network instance ...
|
|
44
48
|
|
|
45
|
-
// Clean up when done
|
|
49
|
+
// Clean up when done
|
|
46
50
|
await network.stop();
|
|
47
|
-
|
|
48
|
-
// With caching enabled (60 seconds TTL)
|
|
49
|
-
const cachedNetwork = new SmartNetwork({ cacheTtl: 60000 });
|
|
50
51
|
```
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
Measure your network performance using Cloudflare's global infrastructure:
|
|
53
|
+
Enable caching for repeated lookups:
|
|
55
54
|
|
|
56
55
|
```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
|
-
};
|
|
56
|
+
const network = new SmartNetwork({ cacheTtl: 60000 }); // 60s TTL
|
|
71
57
|
```
|
|
72
58
|
|
|
73
|
-
|
|
59
|
+
---
|
|
74
60
|
|
|
75
|
-
|
|
61
|
+
### π΅οΈ IP Intelligence
|
|
76
62
|
|
|
77
|
-
|
|
63
|
+
Get ASN, organization, geolocation, and RDAP registration data for any IPv4 address. Combines three free public data sources in parallel:
|
|
78
64
|
|
|
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
|
-
};
|
|
65
|
+
- **RDAP** β direct queries to RIRs (RIPE, ARIN, APNIC, LACNIC, AFRINIC) for authoritative registration data
|
|
66
|
+
- **Team Cymru DNS** β fast ASN resolution via DNS TXT records
|
|
67
|
+
- **MaxMind GeoLite2** β in-memory MMDB databases (auto-downloaded from CDN, periodically refreshed)
|
|
88
68
|
|
|
89
|
-
|
|
69
|
+
```typescript
|
|
70
|
+
const intel = await network.getIpIntelligence('8.8.8.8');
|
|
71
|
+
|
|
72
|
+
console.log(intel);
|
|
73
|
+
// {
|
|
74
|
+
// asn: 15169,
|
|
75
|
+
// asnOrg: 'Google LLC',
|
|
76
|
+
// registrantOrg: 'Google LLC',
|
|
77
|
+
// registrantCountry: 'United States',
|
|
78
|
+
// networkRange: '8.8.8.0/24',
|
|
79
|
+
// abuseContact: null,
|
|
80
|
+
// country: null,
|
|
81
|
+
// countryCode: 'US',
|
|
82
|
+
// city: null,
|
|
83
|
+
// latitude: 37.751,
|
|
84
|
+
// longitude: -97.822,
|
|
85
|
+
// accuracyRadius: null,
|
|
86
|
+
// timezone: 'America/Chicago'
|
|
87
|
+
// }
|
|
90
88
|
```
|
|
91
89
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
Automatically discover available ports:
|
|
90
|
+
Works great for your own IP too:
|
|
95
91
|
|
|
96
92
|
```typescript
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
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
|
-
};
|
|
93
|
+
const publicIps = await network.getPublicIps();
|
|
94
|
+
if (publicIps.v4) {
|
|
95
|
+
const myIntel = await network.getIpIntelligence(publicIps.v4);
|
|
96
|
+
console.log(`You're on AS${myIntel.asn} (${myIntel.asnOrg}) in ${myIntel.city}, ${myIntel.countryCode}`);
|
|
97
|
+
}
|
|
124
98
|
```
|
|
125
99
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
Test if services are accessible on remote servers:
|
|
100
|
+
The `IIpIntelligenceResult` interface:
|
|
129
101
|
|
|
130
102
|
```typescript
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
});
|
|
151
|
-
} catch (e) {
|
|
152
|
-
console.error('UDP not supported:', e.code); // ENOTSUP
|
|
103
|
+
interface IIpIntelligenceResult {
|
|
104
|
+
// ASN (Team Cymru primary, MaxMind fallback)
|
|
105
|
+
asn: number | null;
|
|
106
|
+
asnOrg: string | null;
|
|
107
|
+
|
|
108
|
+
// Registration (RDAP)
|
|
109
|
+
registrantOrg: string | null;
|
|
110
|
+
registrantCountry: string | null;
|
|
111
|
+
networkRange: string | null; // CIDR or range
|
|
112
|
+
abuseContact: string | null; // abuse email from RDAP
|
|
113
|
+
|
|
114
|
+
// Geolocation (MaxMind GeoLite2)
|
|
115
|
+
country: string | null;
|
|
116
|
+
countryCode: string | null; // ISO 3166-1 alpha-2
|
|
117
|
+
city: string | null;
|
|
118
|
+
latitude: number | null;
|
|
119
|
+
longitude: number | null;
|
|
120
|
+
accuracyRadius: number | null; // km
|
|
121
|
+
timezone: string | null; // IANA timezone
|
|
153
122
|
}
|
|
154
123
|
```
|
|
155
124
|
|
|
156
|
-
|
|
125
|
+
> π‘ 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.
|
|
157
126
|
|
|
158
|
-
|
|
127
|
+
---
|
|
159
128
|
|
|
160
|
-
|
|
129
|
+
### ποΈ Speed Testing
|
|
130
|
+
|
|
131
|
+
Measure network performance via Cloudflare's global infrastructure:
|
|
161
132
|
|
|
162
133
|
```typescript
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
console.log(
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
timeout: 1000 // Timeout per ping in ms
|
|
134
|
+
const result = await network.getSpeed();
|
|
135
|
+
console.log(`β¬οΈ Download: ${result.downloadSpeed} Mbps`);
|
|
136
|
+
console.log(`β¬οΈ Upload: ${result.uploadSpeed} Mbps`);
|
|
137
|
+
|
|
138
|
+
// Advanced: parallel streams + fixed duration
|
|
139
|
+
const advanced = await network.getSpeed({
|
|
140
|
+
parallelStreams: 3,
|
|
141
|
+
duration: 5,
|
|
172
142
|
});
|
|
173
|
-
|
|
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`);
|
|
180
143
|
```
|
|
181
144
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
Analyze network paths hop-by-hop:
|
|
145
|
+
---
|
|
185
146
|
|
|
186
|
-
|
|
187
|
-
const hops = await network.traceroute('google.com', {
|
|
188
|
-
maxHops: 10, // Maximum number of hops
|
|
189
|
-
timeout: 5000 // Timeout in ms
|
|
190
|
-
});
|
|
147
|
+
### π Port Management
|
|
191
148
|
|
|
192
|
-
|
|
193
|
-
hops.forEach(hop => {
|
|
194
|
-
const rtt = hop.rtt === null ? '*' : `${hop.rtt} ms`;
|
|
195
|
-
console.log(` ${hop.ttl}\t${hop.ip}\t${rtt}`);
|
|
196
|
-
});
|
|
197
|
-
```
|
|
149
|
+
#### Check Local Port Availability
|
|
198
150
|
|
|
199
|
-
|
|
151
|
+
Checks both IPv4 and IPv6:
|
|
200
152
|
|
|
201
|
-
|
|
153
|
+
```typescript
|
|
154
|
+
const isUnused = await network.isLocalPortUnused(8080);
|
|
155
|
+
console.log(isUnused ? 'β
Port 8080 is free' : 'β Port 8080 is in use');
|
|
156
|
+
```
|
|
202
157
|
|
|
203
|
-
|
|
158
|
+
#### Find Free Port in Range
|
|
204
159
|
|
|
205
160
|
```typescript
|
|
206
|
-
|
|
161
|
+
// First available
|
|
162
|
+
const port = await network.findFreePort(3000, 3100);
|
|
207
163
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
console.log(' AAAA records:', dnsRecords.AAAA); // IPv6 addresses
|
|
164
|
+
// Random pick (avoids clustering)
|
|
165
|
+
const randomPort = await network.findFreePort(3000, 3100, { randomize: true });
|
|
211
166
|
|
|
212
|
-
//
|
|
213
|
-
|
|
214
|
-
|
|
167
|
+
// With exclusions
|
|
168
|
+
const port2 = await network.findFreePort(3000, 3100, {
|
|
169
|
+
randomize: true,
|
|
170
|
+
exclude: [3000, 3001, 3005],
|
|
215
171
|
});
|
|
216
|
-
|
|
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
172
|
```
|
|
221
173
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
### π₯ HTTP/HTTPS Health Checks
|
|
225
|
-
|
|
226
|
-
Monitor endpoint availability and response times:
|
|
174
|
+
#### Check Remote Port
|
|
227
175
|
|
|
228
176
|
```typescript
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
});
|
|
177
|
+
// Simple
|
|
178
|
+
const isOpen = await network.isRemotePortAvailable('example.com', 443);
|
|
232
179
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
180
|
+
// With retries and timeout
|
|
181
|
+
const isOpen2 = await network.isRemotePortAvailable('example.com', {
|
|
182
|
+
port: 443,
|
|
183
|
+
retries: 3,
|
|
184
|
+
timeout: 5000,
|
|
185
|
+
});
|
|
237
186
|
```
|
|
238
187
|
|
|
239
|
-
|
|
188
|
+
---
|
|
240
189
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
List all network adapters on the system:
|
|
190
|
+
### π‘ Ping & Traceroute
|
|
244
191
|
|
|
245
192
|
```typescript
|
|
246
|
-
|
|
193
|
+
// Simple ping
|
|
194
|
+
const ping = await network.ping('google.com');
|
|
195
|
+
console.log(`Alive: ${ping.alive}, RTT: ${ping.time} ms`);
|
|
247
196
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
197
|
+
// Multi-ping with statistics
|
|
198
|
+
const stats = await network.ping('google.com', { count: 10, timeout: 2000 });
|
|
199
|
+
console.log(`π min=${stats.min} avg=${stats.avg.toFixed(1)} max=${stats.max} loss=${stats.packetLoss}%`);
|
|
200
|
+
|
|
201
|
+
// Traceroute
|
|
202
|
+
const hops = await network.traceroute('google.com', { maxHops: 20 });
|
|
203
|
+
hops.forEach(hop => {
|
|
204
|
+
const rtt = hop.rtt === null ? '*' : `${hop.rtt} ms`;
|
|
205
|
+
console.log(` ${hop.ttl}\t${hop.ip}\t${rtt}`);
|
|
255
206
|
});
|
|
256
207
|
```
|
|
257
208
|
|
|
258
|
-
|
|
209
|
+
> β οΈ ICMP ping requires `CAP_NET_RAW` or appropriate `ping_group_range` sysctl on Linux.
|
|
259
210
|
|
|
260
|
-
|
|
211
|
+
---
|
|
261
212
|
|
|
262
|
-
|
|
263
|
-
const defaultGateway = await network.getDefaultGateway();
|
|
213
|
+
### π DNS Resolution
|
|
264
214
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
215
|
+
Uses `@push.rocks/smartdns` with a system-first strategy and automatic DoH (DNS-over-HTTPS) fallback:
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
const dns = await network.resolveDns('example.com');
|
|
219
|
+
console.log('A records:', dns.A); // ['93.184.216.34']
|
|
220
|
+
console.log('AAAA records:', dns.AAAA); // ['2606:2800:220:1:248:1893:25c8:1946']
|
|
221
|
+
dns.MX.forEach(mx => {
|
|
222
|
+
console.log(`π§ ${mx.exchange} (priority ${mx.priority})`);
|
|
223
|
+
});
|
|
270
224
|
```
|
|
271
225
|
|
|
272
|
-
|
|
226
|
+
---
|
|
273
227
|
|
|
274
|
-
|
|
228
|
+
### π₯ HTTP/HTTPS Health Checks
|
|
275
229
|
|
|
276
230
|
```typescript
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
console.log(`
|
|
231
|
+
const health = await network.checkEndpoint('https://api.example.com/health', {
|
|
232
|
+
timeout: 5000,
|
|
233
|
+
rejectUnauthorized: true,
|
|
234
|
+
});
|
|
235
|
+
console.log(`Status: ${health.status}, RTT: ${health.rtt.toFixed(0)} ms`);
|
|
282
236
|
```
|
|
283
237
|
|
|
284
|
-
|
|
238
|
+
---
|
|
285
239
|
|
|
286
|
-
|
|
240
|
+
### π₯οΈ Network Interfaces & Public IPs
|
|
287
241
|
|
|
288
242
|
```typescript
|
|
289
|
-
//
|
|
290
|
-
const
|
|
243
|
+
// All interfaces
|
|
244
|
+
const gateways = await network.getGateways();
|
|
245
|
+
Object.entries(gateways).forEach(([name, ifaces]) => {
|
|
246
|
+
console.log(`π ${name}:`);
|
|
247
|
+
ifaces.forEach(i => console.log(` ${i.family}: ${i.address}`));
|
|
248
|
+
});
|
|
291
249
|
|
|
292
|
-
//
|
|
293
|
-
const
|
|
294
|
-
|
|
250
|
+
// Default gateway
|
|
251
|
+
const gw = await network.getDefaultGateway();
|
|
252
|
+
if (gw) {
|
|
253
|
+
console.log(`π Gateway IPv4: ${gw.ipv4.address}`);
|
|
254
|
+
}
|
|
295
255
|
|
|
296
|
-
//
|
|
297
|
-
const
|
|
298
|
-
|
|
256
|
+
// Public IPs (multiple fallback services: ipify, ident.me, seeip, icanhazip)
|
|
257
|
+
const publicIps = await network.getPublicIps();
|
|
258
|
+
console.log(`π IPv4: ${publicIps.v4 || 'N/A'}`);
|
|
259
|
+
console.log(`π IPv6: ${publicIps.v6 || 'N/A'}`);
|
|
299
260
|
```
|
|
300
261
|
|
|
301
|
-
|
|
262
|
+
---
|
|
302
263
|
|
|
303
|
-
|
|
264
|
+
### β‘ Caching
|
|
304
265
|
|
|
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
|
-
}
|
|
315
|
-
|
|
316
|
-
// Register the plugin
|
|
317
|
-
SmartNetwork.registerPlugin('customPlugin', CustomNetworkPlugin);
|
|
266
|
+
Caching applies to `getGateways()`, `getPublicIps()`, and `getIpIntelligence()`:
|
|
318
267
|
|
|
319
|
-
|
|
320
|
-
const network = new SmartNetwork();
|
|
321
|
-
const PluginClass = SmartNetwork.pluginsRegistry.get('customPlugin');
|
|
322
|
-
const plugin = new PluginClass(network);
|
|
323
|
-
await plugin.customMethod();
|
|
268
|
+
```typescript
|
|
269
|
+
const network = new SmartNetwork({ cacheTtl: 60000 }); // 60s
|
|
324
270
|
|
|
325
|
-
|
|
326
|
-
|
|
271
|
+
const ips1 = await network.getPublicIps(); // fetches
|
|
272
|
+
const ips2 = await network.getPublicIps(); // cache hit β‘
|
|
327
273
|
```
|
|
328
274
|
|
|
329
|
-
|
|
275
|
+
---
|
|
330
276
|
|
|
331
|
-
|
|
277
|
+
### π¨ Error Handling
|
|
332
278
|
|
|
333
279
|
```typescript
|
|
334
|
-
import { NetworkError } from '@push.rocks/smartnetwork';
|
|
280
|
+
import { SmartNetwork, NetworkError, TimeoutError } from '@push.rocks/smartnetwork';
|
|
335
281
|
|
|
336
282
|
try {
|
|
337
283
|
await network.isRemotePortAvailable('example.com', { protocol: 'udp' });
|
|
338
284
|
} catch (error) {
|
|
339
285
|
if (error instanceof NetworkError) {
|
|
340
|
-
console.error(
|
|
341
|
-
console.error(` Error code: ${error.code}`);
|
|
286
|
+
console.error(`${error.message} (code: ${error.code})`); // ENOTSUP
|
|
342
287
|
}
|
|
343
288
|
}
|
|
344
289
|
```
|
|
345
290
|
|
|
346
|
-
|
|
291
|
+
Error codes: `EINVAL` (invalid argument), `ENOTSUP` (not supported), `ETIMEOUT` (timeout).
|
|
347
292
|
|
|
348
|
-
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
### π§ Plugin Architecture
|
|
349
296
|
|
|
350
297
|
```typescript
|
|
351
|
-
|
|
352
|
-
|
|
298
|
+
class MyPlugin {
|
|
299
|
+
constructor(private network: SmartNetwork) {}
|
|
300
|
+
async doStuff() { /* ... */ }
|
|
353
301
|
}
|
|
354
302
|
|
|
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
|
-
}
|
|
303
|
+
SmartNetwork.registerPlugin('myPlugin', MyPlugin);
|
|
359
304
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
rtt: number | null; // Round trip time in ms
|
|
364
|
-
}
|
|
305
|
+
const PluginClass = SmartNetwork.pluginsRegistry.get('myPlugin');
|
|
306
|
+
const plugin = new PluginClass(network);
|
|
307
|
+
await plugin.doStuff();
|
|
365
308
|
|
|
366
|
-
|
|
309
|
+
SmartNetwork.unregisterPlugin('myPlugin');
|
|
367
310
|
```
|
|
368
311
|
|
|
369
|
-
|
|
312
|
+
---
|
|
370
313
|
|
|
371
|
-
###
|
|
314
|
+
### π Custom Logging
|
|
315
|
+
|
|
316
|
+
Replace the default `console` logger:
|
|
372
317
|
|
|
373
318
|
```typescript
|
|
374
|
-
|
|
319
|
+
import { setLogger } from '@push.rocks/smartnetwork';
|
|
320
|
+
|
|
321
|
+
setLogger({
|
|
322
|
+
debug: (msg) => myLogger.debug(msg),
|
|
323
|
+
info: (msg) => myLogger.info(msg),
|
|
324
|
+
warn: (msg) => myLogger.warn(msg),
|
|
325
|
+
error: (msg) => myLogger.error(msg),
|
|
326
|
+
});
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## π οΈ Advanced Example: Network Monitor
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
const monitor = async () => {
|
|
375
335
|
const network = new SmartNetwork({ cacheTtl: 30000 });
|
|
376
|
-
|
|
336
|
+
|
|
377
337
|
// Check critical services
|
|
378
338
|
const services = [
|
|
379
|
-
{ name: 'Web
|
|
380
|
-
{ name: '
|
|
381
|
-
{ name: 'Cache', host: 'redis.internal', port: 6379 }
|
|
339
|
+
{ name: 'Web', host: 'example.com', port: 443 },
|
|
340
|
+
{ name: 'DB', host: 'db.internal', port: 5432 },
|
|
382
341
|
];
|
|
383
|
-
|
|
384
|
-
for (const
|
|
385
|
-
const
|
|
386
|
-
console.log(`${
|
|
342
|
+
|
|
343
|
+
for (const svc of services) {
|
|
344
|
+
const up = await network.isRemotePortAvailable(svc.host, svc.port);
|
|
345
|
+
console.log(`${svc.name}: ${up ? 'β
UP' : 'β DOWN'}`);
|
|
387
346
|
}
|
|
388
|
-
|
|
389
|
-
// Check internet connectivity
|
|
390
|
-
const ping = await network.ping('8.8.8.8');
|
|
391
|
-
console.log(`Internet: ${ping.alive ? 'β
Connected' : 'β Disconnected'}`);
|
|
392
|
-
|
|
393
|
-
// Measure network performance
|
|
394
|
-
const speed = await network.getSpeed();
|
|
395
|
-
console.log(`Speed: β¬οΈ ${speed.downloadSpeed} Mbps / β¬οΈ ${speed.uploadSpeed} Mbps`);
|
|
396
|
-
};
|
|
397
347
|
|
|
398
|
-
//
|
|
399
|
-
|
|
400
|
-
|
|
348
|
+
// Internet connectivity + latency
|
|
349
|
+
const ping = await network.ping('8.8.8.8');
|
|
350
|
+
console.log(`Internet: ${ping.alive ? 'β
' : 'β'} (${ping.time} ms)`);
|
|
401
351
|
|
|
402
|
-
|
|
352
|
+
// Speed
|
|
353
|
+
const speed = await network.getSpeed();
|
|
354
|
+
console.log(`Speed: β¬οΈ ${speed.downloadSpeed} / β¬οΈ ${speed.uploadSpeed} Mbps`);
|
|
403
355
|
|
|
404
|
-
|
|
405
|
-
const
|
|
406
|
-
|
|
407
|
-
|
|
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
|
-
}
|
|
356
|
+
// Who am I?
|
|
357
|
+
const ips = await network.getPublicIps();
|
|
358
|
+
if (ips.v4) {
|
|
359
|
+
const intel = await network.getIpIntelligence(ips.v4);
|
|
360
|
+
console.log(`AS${intel.asn} (${intel.asnOrg}) β ${intel.city || intel.countryCode}`);
|
|
416
361
|
}
|
|
362
|
+
|
|
363
|
+
await network.stop();
|
|
417
364
|
};
|
|
418
365
|
```
|
|
419
366
|
|
|
367
|
+
## π Full API Reference
|
|
368
|
+
|
|
369
|
+
| Method | Description | Requires Rust |
|
|
370
|
+
|--------|-------------|:---:|
|
|
371
|
+
| `start()` / `stop()` | Start/stop the Rust binary bridge | β |
|
|
372
|
+
| `getSpeed(opts?)` | Cloudflare speed test (download + upload) | No |
|
|
373
|
+
| `ping(host, opts?)` | ICMP ping with optional multi-ping stats | Yes |
|
|
374
|
+
| `traceroute(host, opts?)` | Hop-by-hop network path analysis | Yes |
|
|
375
|
+
| `isLocalPortUnused(port)` | Check if local port is free (IPv4+IPv6) | Yes |
|
|
376
|
+
| `findFreePort(start, end, opts?)` | Find available port in range | Yes |
|
|
377
|
+
| `isRemotePortAvailable(target, opts?)` | TCP port check on remote host | Yes |
|
|
378
|
+
| `getGateways()` | List all network interfaces | No |
|
|
379
|
+
| `getDefaultGateway()` | Get default gateway info | Yes |
|
|
380
|
+
| `getPublicIps()` | Discover public IPv4/IPv6 (4 fallback services) | No |
|
|
381
|
+
| `resolveDns(host)` | Resolve A, AAAA, MX records | No |
|
|
382
|
+
| `checkEndpoint(url, opts?)` | HTTP/HTTPS health check with RTT | No |
|
|
383
|
+
| `getIpIntelligence(ip)` | ASN + org + geo + RDAP registration | No |
|
|
384
|
+
|
|
420
385
|
## License and Legal Information
|
|
421
386
|
|
|
422
|
-
This repository contains open-source code
|
|
387
|
+
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
388
|
|
|
424
389
|
**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
390
|
|
|
426
391
|
### Trademarks
|
|
427
392
|
|
|
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.
|
|
393
|
+
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.
|
|
394
|
+
|
|
395
|
+
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
396
|
|
|
430
397
|
### Company Information
|
|
431
398
|
|
|
432
|
-
Task Venture Capital GmbH
|
|
433
|
-
Registered at District
|
|
399
|
+
Task Venture Capital GmbH
|
|
400
|
+
Registered at District Court Bremen HRB 35230 HB, Germany
|
|
434
401
|
|
|
435
|
-
For any legal inquiries or
|
|
402
|
+
For any legal inquiries or further information, please contact us via email at hello@task.vc.
|
|
436
403
|
|
|
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.
|
|
404
|
+
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.
|