fix(docs): refresh README content and align license copyright holder
This commit is contained in:
@@ -1,5 +1,12 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2026-03-26 - 4.5.2 - fix(docs)
|
||||||
|
refresh README content and align license copyright holder
|
||||||
|
|
||||||
|
- Rewrite the README to better present network diagnostics, IP intelligence capabilities, usage examples, and full API reference
|
||||||
|
- Add issue reporting guidance and clarify legal and trademark wording in project documentation
|
||||||
|
- Update the license copyright holder to Task Venture Capital GmbH
|
||||||
|
|
||||||
## 2026-03-26 - 4.5.1 - fix(ipintelligence)
|
## 2026-03-26 - 4.5.1 - fix(ipintelligence)
|
||||||
handle flat geolocation MMDB schema and clean up DNS client lifecycle
|
handle flat geolocation MMDB schema and clean up DNS client lifecycle
|
||||||
|
|
||||||
|
|||||||
2
license
2
license
@@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2015 Lossless GmbH
|
Copyright (c) 2015 Task Venture Capital GmbH
|
||||||
Copyright (c) 2020 Tomás Arias
|
Copyright (c) 2020 Tomás Arias
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
|||||||
549
readme.md
549
readme.md
@@ -1,40 +1,44 @@
|
|||||||
# @push.rocks/smartnetwork 🌐
|
# @push.rocks/smartnetwork 🌐
|
||||||
|
|
||||||
Comprehensive network diagnostics and utilities for Node.js applications
|
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.
|
||||||
|
|
||||||
|
## Issue Reporting and Security
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
## 🚀 Install
|
## 🚀 Install
|
||||||
|
|
||||||
To install `@push.rocks/smartnetwork`, run the following command in your terminal:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm install @push.rocks/smartnetwork --save
|
pnpm install @push.rocks/smartnetwork --save
|
||||||
```
|
```
|
||||||
|
|
||||||
## 🎯 Overview
|
## 🎯 Overview
|
||||||
|
|
||||||
**@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.
|
**@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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
### ✨ Key Features
|
### ✨ Key Features
|
||||||
|
|
||||||
- **🏎️ Speed Testing** - Measure download/upload speeds using Cloudflare's infrastructure
|
| Category | Capabilities |
|
||||||
- **🔌 Port Management** - Check local/remote port availability, find free ports (sequential or random)
|
|----------|-------------|
|
||||||
- **📡 Connectivity Testing** - Ping hosts, trace routes, check endpoints
|
| 🏎️ **Speed Testing** | Download/upload benchmarks via Cloudflare's global infrastructure |
|
||||||
- **🌍 DNS Operations** - Resolve A, AAAA, and MX records with smart local/remote resolution
|
| 🔌 **Port Management** | Local/remote port checks, find free ports (sequential or random), exclusion lists |
|
||||||
- **🔍 Network Discovery** - Get network interfaces, gateways, public IPs
|
| 📡 **Connectivity** | ICMP ping with stats, hop-by-hop traceroute, HTTP/HTTPS health checks |
|
||||||
- **⚡ Performance Caching** - Built-in caching for expensive operations
|
| 🌍 **DNS** | A, AAAA, MX resolution with system-first + DoH fallback strategy |
|
||||||
- **🔧 Plugin Architecture** - Extend functionality with custom plugins
|
| 🔍 **IP Intelligence** | ASN, organization, geolocation, RDAP registration — all from free public sources |
|
||||||
- **📝 Full TypeScript Support** - Complete type definitions included
|
| 🖥️ **Network Discovery** | Interfaces, default gateway, public IPv4/IPv6 |
|
||||||
|
| ⚡ **Caching** | Built-in TTL cache for expensive lookups |
|
||||||
|
| 🔧 **Extensible** | Plugin architecture for custom functionality |
|
||||||
|
| 📝 **TypeScript** | Full type definitions, ESM-native |
|
||||||
|
|
||||||
## 💻 Usage
|
## 💻 Usage
|
||||||
|
|
||||||
### Basic Setup
|
### Basic Setup
|
||||||
|
|
||||||
First, import and initialize SmartNetwork:
|
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { SmartNetwork } from '@push.rocks/smartnetwork';
|
import { SmartNetwork } from '@push.rocks/smartnetwork';
|
||||||
|
|
||||||
// Basic instance
|
|
||||||
const network = new SmartNetwork();
|
const network = new SmartNetwork();
|
||||||
|
|
||||||
// Start the Rust bridge (auto-started on first use, but explicit start is recommended)
|
// Start the Rust bridge (auto-started on first use, but explicit start is recommended)
|
||||||
@@ -42,396 +46,359 @@ await network.start();
|
|||||||
|
|
||||||
// ... use the network instance ...
|
// ... use the network instance ...
|
||||||
|
|
||||||
// Clean up when done (stops the Rust bridge process)
|
// Clean up when done
|
||||||
await network.stop();
|
await network.stop();
|
||||||
|
|
||||||
// With caching enabled (60 seconds TTL)
|
|
||||||
const cachedNetwork = new SmartNetwork({ cacheTtl: 60000 });
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 🏎️ Network Speed Testing
|
Enable caching for repeated lookups:
|
||||||
|
|
||||||
Measure your network performance using Cloudflare's global infrastructure:
|
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const speedTest = async () => {
|
const network = new SmartNetwork({ cacheTtl: 60000 }); // 60s TTL
|
||||||
// Quick speed test
|
|
||||||
const result = await network.getSpeed();
|
|
||||||
console.log(`Download: ${result.downloadSpeed} Mbps`);
|
|
||||||
console.log(`Upload: ${result.uploadSpeed} Mbps`);
|
|
||||||
|
|
||||||
// Advanced configuration
|
|
||||||
const advancedResult = await network.getSpeed({
|
|
||||||
parallelStreams: 3, // Number of concurrent connections
|
|
||||||
duration: 5 // Test duration in seconds
|
|
||||||
});
|
|
||||||
console.log(`Download: ${advancedResult.downloadSpeed} Mbps`);
|
|
||||||
console.log(`Upload: ${advancedResult.uploadSpeed} Mbps`);
|
|
||||||
};
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🕵️ IP Intelligence
|
||||||
|
|
||||||
|
Get ASN, organization, geolocation, and RDAP registration data for any IPv4 address. Combines three free public data sources in parallel:
|
||||||
|
|
||||||
|
- **RDAP** — direct queries to RIRs (RIPE, ARIN, APNIC, LACNIC, AFRINIC) for authoritative registration data
|
||||||
|
- **Team Cymru DNS** — fast ASN resolution via DNS TXT records
|
||||||
|
- **MaxMind GeoLite2** — in-memory MMDB databases (auto-downloaded from CDN, periodically refreshed)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const intel = await network.getIpIntelligence('8.8.8.8');
|
||||||
|
|
||||||
|
console.log(intel);
|
||||||
|
// {
|
||||||
|
// asn: 15169,
|
||||||
|
// asnOrg: 'Google LLC',
|
||||||
|
// registrantOrg: 'Google LLC',
|
||||||
|
// registrantCountry: 'United States',
|
||||||
|
// networkRange: '8.8.8.0/24',
|
||||||
|
// abuseContact: null,
|
||||||
|
// country: null,
|
||||||
|
// countryCode: 'US',
|
||||||
|
// city: null,
|
||||||
|
// latitude: 37.751,
|
||||||
|
// longitude: -97.822,
|
||||||
|
// accuracyRadius: null,
|
||||||
|
// timezone: 'America/Chicago'
|
||||||
|
// }
|
||||||
|
```
|
||||||
|
|
||||||
|
Works great for your own IP too:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const publicIps = await network.getPublicIps();
|
||||||
|
if (publicIps.v4) {
|
||||||
|
const myIntel = await network.getIpIntelligence(publicIps.v4);
|
||||||
|
console.log(`You're on AS${myIntel.asn} (${myIntel.asnOrg}) in ${myIntel.city}, ${myIntel.countryCode}`);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `IIpIntelligenceResult` interface:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface IIpIntelligenceResult {
|
||||||
|
// ASN (Team Cymru primary, MaxMind fallback)
|
||||||
|
asn: number | null;
|
||||||
|
asnOrg: string | null;
|
||||||
|
|
||||||
|
// Registration (RDAP)
|
||||||
|
registrantOrg: string | null;
|
||||||
|
registrantCountry: string | null;
|
||||||
|
networkRange: string | null; // CIDR or range
|
||||||
|
abuseContact: string | null; // abuse email from RDAP
|
||||||
|
|
||||||
|
// Geolocation (MaxMind GeoLite2)
|
||||||
|
country: string | null;
|
||||||
|
countryCode: string | null; // ISO 3166-1 alpha-2
|
||||||
|
city: string | null;
|
||||||
|
latitude: number | null;
|
||||||
|
longitude: number | null;
|
||||||
|
accuracyRadius: number | null; // km
|
||||||
|
timezone: string | null; // IANA timezone
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> 💡 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.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🏎️ Speed Testing
|
||||||
|
|
||||||
|
Measure network performance via Cloudflare's global infrastructure:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const result = await network.getSpeed();
|
||||||
|
console.log(`⬇️ Download: ${result.downloadSpeed} Mbps`);
|
||||||
|
console.log(`⬆️ Upload: ${result.uploadSpeed} Mbps`);
|
||||||
|
|
||||||
|
// Advanced: parallel streams + fixed duration
|
||||||
|
const advanced = await network.getSpeed({
|
||||||
|
parallelStreams: 3,
|
||||||
|
duration: 5,
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### 🔌 Port Management
|
### 🔌 Port Management
|
||||||
|
|
||||||
#### Check Local Port Availability
|
#### Check Local Port Availability
|
||||||
|
|
||||||
Verify if a port is available on your local machine (checks both IPv4 and IPv6):
|
Checks both IPv4 and IPv6:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const checkLocalPort = async (port: number) => {
|
const isUnused = await network.isLocalPortUnused(8080);
|
||||||
const isUnused = await network.isLocalPortUnused(port);
|
console.log(isUnused ? '✅ Port 8080 is free' : '❌ Port 8080 is in use');
|
||||||
if (isUnused) {
|
|
||||||
console.log(`✅ Port ${port} is available`);
|
|
||||||
} else {
|
|
||||||
console.log(`❌ Port ${port} is in use`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
await checkLocalPort(8080);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Find Free Port in Range
|
#### Find Free Port in Range
|
||||||
|
|
||||||
Automatically discover available ports:
|
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const findFreePort = async () => {
|
// First available
|
||||||
// Find a free port between 3000 and 3100 (sequential - returns first available)
|
const port = await network.findFreePort(3000, 3100);
|
||||||
const freePort = await network.findFreePort(3000, 3100);
|
|
||||||
|
|
||||||
if (freePort) {
|
|
||||||
console.log(`🎉 Found free port: ${freePort}`);
|
|
||||||
} else {
|
|
||||||
console.log('😢 No free ports available in range');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find a random free port in range (useful to avoid port conflicts)
|
|
||||||
const randomPort = await network.findFreePort(3000, 3100, { randomize: true });
|
|
||||||
console.log(`🎲 Random free port: ${randomPort}`);
|
|
||||||
|
|
||||||
// Exclude specific ports from the search
|
|
||||||
const portWithExclusions = await network.findFreePort(3000, 3100, {
|
|
||||||
exclude: [3000, 3001, 3005] // Skip these ports even if they're free
|
|
||||||
});
|
|
||||||
console.log(`🚫 Free port (excluding specific ports): ${portWithExclusions}`);
|
|
||||||
|
|
||||||
// Combine randomize with exclude options
|
|
||||||
const randomWithExclusions = await network.findFreePort(3000, 3100, {
|
|
||||||
randomize: true,
|
|
||||||
exclude: [3000, 3001, 3005]
|
|
||||||
});
|
|
||||||
console.log(`🎲🚫 Random free port (with exclusions): ${randomWithExclusions}`);
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Check Remote Port Availability
|
// Random pick (avoids clustering)
|
||||||
|
const randomPort = await network.findFreePort(3000, 3100, { randomize: true });
|
||||||
|
|
||||||
Test if services are accessible on remote servers:
|
// With exclusions
|
||||||
|
const port2 = await network.findFreePort(3000, 3100, {
|
||||||
```typescript
|
randomize: true,
|
||||||
// Method 1: Using "host:port" syntax
|
exclude: [3000, 3001, 3005],
|
||||||
const isOpen1 = await network.isRemotePortAvailable('example.com:443');
|
|
||||||
|
|
||||||
// Method 2: Using separate host and port
|
|
||||||
const isOpen2 = await network.isRemotePortAvailable('example.com', 443);
|
|
||||||
|
|
||||||
// Method 3: With advanced options
|
|
||||||
const isOpen3 = await network.isRemotePortAvailable('example.com', {
|
|
||||||
port: 443,
|
|
||||||
protocol: 'tcp', // Only TCP is supported
|
|
||||||
retries: 3, // Number of connection attempts
|
|
||||||
timeout: 5000 // Timeout per attempt in ms
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Note: UDP is not supported
|
|
||||||
try {
|
|
||||||
await network.isRemotePortAvailable('example.com', {
|
|
||||||
port: 53,
|
|
||||||
protocol: 'udp'
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
console.error('UDP not supported:', e.code); // ENOTSUP
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 📡 Network Connectivity
|
#### Check Remote Port
|
||||||
|
|
||||||
#### Ping Operations
|
```typescript
|
||||||
|
// Simple
|
||||||
|
const isOpen = await network.isRemotePortAvailable('example.com', 443);
|
||||||
|
|
||||||
Test connectivity and measure latency:
|
// With retries and timeout
|
||||||
|
const isOpen2 = await network.isRemotePortAvailable('example.com', {
|
||||||
|
port: 443,
|
||||||
|
retries: 3,
|
||||||
|
timeout: 5000,
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 📡 Ping & Traceroute
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Simple ping
|
// Simple ping
|
||||||
const pingResult = await network.ping('google.com');
|
const ping = await network.ping('google.com');
|
||||||
console.log(`Host alive: ${pingResult.alive}`);
|
console.log(`Alive: ${ping.alive}, RTT: ${ping.time} ms`);
|
||||||
console.log(`RTT: ${pingResult.time} ms`);
|
|
||||||
|
|
||||||
// Detailed ping statistics
|
// Multi-ping with statistics
|
||||||
const pingStats = await network.ping('google.com', {
|
const stats = await network.ping('google.com', { count: 10, timeout: 2000 });
|
||||||
count: 5, // Number of pings
|
console.log(`📊 min=${stats.min} avg=${stats.avg.toFixed(1)} max=${stats.max} loss=${stats.packetLoss}%`);
|
||||||
timeout: 1000 // Timeout per ping in ms
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(`📊 Ping Statistics:`);
|
// Traceroute
|
||||||
console.log(` Packet loss: ${pingStats.packetLoss}%`);
|
const hops = await network.traceroute('google.com', { maxHops: 20 });
|
||||||
console.log(` Min: ${pingStats.min} ms`);
|
|
||||||
console.log(` Max: ${pingStats.max} ms`);
|
|
||||||
console.log(` Avg: ${pingStats.avg.toFixed(2)} ms`);
|
|
||||||
console.log(` Stddev: ${pingStats.stddev.toFixed(2)} ms`);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Traceroute
|
|
||||||
|
|
||||||
Analyze network paths hop-by-hop:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
const hops = await network.traceroute('google.com', {
|
|
||||||
maxHops: 10, // Maximum number of hops
|
|
||||||
timeout: 5000 // Timeout in ms
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('🛤️ Route to destination:');
|
|
||||||
hops.forEach(hop => {
|
hops.forEach(hop => {
|
||||||
const rtt = hop.rtt === null ? '*' : `${hop.rtt} ms`;
|
const rtt = hop.rtt === null ? '*' : `${hop.rtt} ms`;
|
||||||
console.log(` ${hop.ttl}\t${hop.ip}\t${rtt}`);
|
console.log(` ${hop.ttl}\t${hop.ip}\t${rtt}`);
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
*Note: Falls back to a single-hop stub if the `traceroute` binary is unavailable.*
|
> ⚠️ ICMP ping requires `CAP_NET_RAW` or appropriate `ping_group_range` sysctl on Linux.
|
||||||
|
|
||||||
### 🌍 DNS Operations
|
---
|
||||||
|
|
||||||
Resolve various DNS record types using @push.rocks/smartdns with intelligent resolution strategy:
|
### 🌍 DNS Resolution
|
||||||
|
|
||||||
|
Uses `@push.rocks/smartdns` with a system-first strategy and automatic DoH (DNS-over-HTTPS) fallback:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const dnsRecords = await network.resolveDns('example.com');
|
const dns = await network.resolveDns('example.com');
|
||||||
|
console.log('A records:', dns.A); // ['93.184.216.34']
|
||||||
console.log('🔍 DNS Records:');
|
console.log('AAAA records:', dns.AAAA); // ['2606:2800:220:1:248:1893:25c8:1946']
|
||||||
console.log(' A records:', dnsRecords.A); // IPv4 addresses
|
dns.MX.forEach(mx => {
|
||||||
console.log(' AAAA records:', dnsRecords.AAAA); // IPv6 addresses
|
console.log(`📧 ${mx.exchange} (priority ${mx.priority})`);
|
||||||
|
|
||||||
// MX records include priority
|
|
||||||
dnsRecords.MX.forEach(mx => {
|
|
||||||
console.log(` 📧 Mail server: ${mx.exchange} (priority: ${mx.priority})`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Properly handles local hostnames (localhost, etc.)
|
|
||||||
const localDns = await network.resolveDns('localhost');
|
|
||||||
console.log(' Localhost:', localDns.A); // Returns ['127.0.0.1']
|
|
||||||
```
|
```
|
||||||
|
|
||||||
*DNS resolution uses a `prefer-system` strategy: tries system resolver first (respects /etc/hosts and local DNS), with automatic fallback to Cloudflare DoH for external domains.*
|
---
|
||||||
|
|
||||||
### 🏥 HTTP/HTTPS Health Checks
|
### 🏥 HTTP/HTTPS Health Checks
|
||||||
|
|
||||||
Monitor endpoint availability and response times:
|
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const health = await network.checkEndpoint('https://api.example.com/health', {
|
const health = await network.checkEndpoint('https://api.example.com/health', {
|
||||||
timeout: 5000 // Request timeout in ms
|
timeout: 5000,
|
||||||
|
rejectUnauthorized: true,
|
||||||
});
|
});
|
||||||
|
console.log(`Status: ${health.status}, RTT: ${health.rtt.toFixed(0)} ms`);
|
||||||
console.log(`🩺 Endpoint Health:`);
|
|
||||||
console.log(` Status: ${health.status}`);
|
|
||||||
console.log(` RTT: ${health.rtt} ms`);
|
|
||||||
console.log(` Headers:`, health.headers);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 🖥️ Network Interface Information
|
---
|
||||||
|
|
||||||
#### Get All Network Interfaces
|
### 🖥️ Network Interfaces & Public IPs
|
||||||
|
|
||||||
List all network adapters on the system:
|
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
|
// All interfaces
|
||||||
const gateways = await network.getGateways();
|
const gateways = await network.getGateways();
|
||||||
|
Object.entries(gateways).forEach(([name, ifaces]) => {
|
||||||
Object.entries(gateways).forEach(([name, interfaces]) => {
|
console.log(`🔌 ${name}:`);
|
||||||
console.log(`🔌 Interface: ${name}`);
|
ifaces.forEach(i => console.log(` ${i.family}: ${i.address}`));
|
||||||
interfaces.forEach(iface => {
|
|
||||||
console.log(` ${iface.family}: ${iface.address}`);
|
|
||||||
console.log(` Netmask: ${iface.netmask}`);
|
|
||||||
console.log(` MAC: ${iface.mac}`);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
```
|
|
||||||
|
|
||||||
#### Get Default Gateway
|
// Default gateway
|
||||||
|
const gw = await network.getDefaultGateway();
|
||||||
Retrieve the primary network interface:
|
if (gw) {
|
||||||
|
console.log(`🌐 Gateway IPv4: ${gw.ipv4.address}`);
|
||||||
```typescript
|
|
||||||
const defaultGateway = await network.getDefaultGateway();
|
|
||||||
|
|
||||||
if (defaultGateway) {
|
|
||||||
console.log('🌐 Default Gateway:');
|
|
||||||
console.log(' IPv4:', defaultGateway.ipv4.address);
|
|
||||||
console.log(' IPv6:', defaultGateway.ipv6.address);
|
|
||||||
}
|
}
|
||||||
```
|
|
||||||
|
|
||||||
### 🌎 Public IP Discovery
|
// Public IPs (multiple fallback services: ipify, ident.me, seeip, icanhazip)
|
||||||
|
|
||||||
Discover your public-facing IP addresses:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
const publicIps = await network.getPublicIps();
|
const publicIps = await network.getPublicIps();
|
||||||
|
console.log(`🌍 IPv4: ${publicIps.v4 || 'N/A'}`);
|
||||||
console.log(`🌍 Public IPs:`);
|
console.log(`🌍 IPv6: ${publicIps.v6 || 'N/A'}`);
|
||||||
console.log(` IPv4: ${publicIps.v4 || 'Not available'}`);
|
|
||||||
console.log(` IPv6: ${publicIps.v6 || 'Not available'}`);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### ⚡ Performance Caching
|
---
|
||||||
|
|
||||||
Reduce network calls with built-in caching:
|
### ⚡ Caching
|
||||||
|
|
||||||
|
Caching applies to `getGateways()`, `getPublicIps()`, and `getIpIntelligence()`:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Create instance with 60-second cache TTL
|
const network = new SmartNetwork({ cacheTtl: 60000 }); // 60s
|
||||||
const cachedNetwork = new SmartNetwork({ cacheTtl: 60000 });
|
|
||||||
|
|
||||||
// First call fetches from network
|
const ips1 = await network.getPublicIps(); // fetches
|
||||||
const gateways1 = await cachedNetwork.getGateways();
|
const ips2 = await network.getPublicIps(); // cache hit ⚡
|
||||||
const publicIps1 = await cachedNetwork.getPublicIps();
|
|
||||||
|
|
||||||
// Subsequent calls within 60 seconds use cache
|
|
||||||
const gateways2 = await cachedNetwork.getGateways(); // From cache ⚡
|
|
||||||
const publicIps2 = await cachedNetwork.getPublicIps(); // From cache ⚡
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 🔧 Plugin Architecture
|
---
|
||||||
|
|
||||||
Extend SmartNetwork with custom functionality:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Define your plugin
|
|
||||||
class CustomNetworkPlugin {
|
|
||||||
constructor(private smartNetwork: SmartNetwork) {}
|
|
||||||
|
|
||||||
async customMethod() {
|
|
||||||
// Your custom network logic here
|
|
||||||
return 'Custom result';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register the plugin
|
|
||||||
SmartNetwork.registerPlugin('customPlugin', CustomNetworkPlugin);
|
|
||||||
|
|
||||||
// Use the plugin
|
|
||||||
const network = new SmartNetwork();
|
|
||||||
const PluginClass = SmartNetwork.pluginsRegistry.get('customPlugin');
|
|
||||||
const plugin = new PluginClass(network);
|
|
||||||
await plugin.customMethod();
|
|
||||||
|
|
||||||
// Clean up when done
|
|
||||||
SmartNetwork.unregisterPlugin('customPlugin');
|
|
||||||
```
|
|
||||||
|
|
||||||
### 🚨 Error Handling
|
### 🚨 Error Handling
|
||||||
|
|
||||||
Handle network errors gracefully with custom error types:
|
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { NetworkError } from '@push.rocks/smartnetwork';
|
import { SmartNetwork, NetworkError, TimeoutError } from '@push.rocks/smartnetwork';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await network.isRemotePortAvailable('example.com', { protocol: 'udp' });
|
await network.isRemotePortAvailable('example.com', { protocol: 'udp' });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof NetworkError) {
|
if (error instanceof NetworkError) {
|
||||||
console.error(`❌ Network error: ${error.message}`);
|
console.error(`${error.message} (code: ${error.code})`); // ENOTSUP
|
||||||
console.error(` Error code: ${error.code}`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 📚 TypeScript Support
|
Error codes: `EINVAL` (invalid argument), `ENOTSUP` (not supported), `ETIMEOUT` (timeout).
|
||||||
|
|
||||||
This package is written in TypeScript and provides comprehensive type definitions:
|
---
|
||||||
|
|
||||||
|
### 🔧 Plugin Architecture
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
interface SmartNetworkOptions {
|
class MyPlugin {
|
||||||
cacheTtl?: number; // Cache TTL in milliseconds
|
constructor(private network: SmartNetwork) {}
|
||||||
|
async doStuff() { /* ... */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IFindFreePortOptions {
|
SmartNetwork.registerPlugin('myPlugin', MyPlugin);
|
||||||
randomize?: boolean; // If true, returns a random free port instead of the first one
|
|
||||||
exclude?: number[]; // Array of port numbers to exclude from the search
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Hop {
|
const PluginClass = SmartNetwork.pluginsRegistry.get('myPlugin');
|
||||||
ttl: number; // Time to live
|
const plugin = new PluginClass(network);
|
||||||
ip: string; // IP address of the hop
|
await plugin.doStuff();
|
||||||
rtt: number | null; // Round trip time in ms
|
|
||||||
}
|
|
||||||
|
|
||||||
// ... and many more types for complete type safety
|
SmartNetwork.unregisterPlugin('myPlugin');
|
||||||
```
|
```
|
||||||
|
|
||||||
## 🛠️ Advanced Examples
|
---
|
||||||
|
|
||||||
### Building a Network Monitor
|
### 📝 Custom Logging
|
||||||
|
|
||||||
|
Replace the default `console` logger:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const monitorNetwork = async () => {
|
import { setLogger } from '@push.rocks/smartnetwork';
|
||||||
|
|
||||||
|
setLogger({
|
||||||
|
debug: (msg) => myLogger.debug(msg),
|
||||||
|
info: (msg) => myLogger.info(msg),
|
||||||
|
warn: (msg) => myLogger.warn(msg),
|
||||||
|
error: (msg) => myLogger.error(msg),
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ Advanced Example: Network Monitor
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const monitor = async () => {
|
||||||
const network = new SmartNetwork({ cacheTtl: 30000 });
|
const network = new SmartNetwork({ cacheTtl: 30000 });
|
||||||
|
|
||||||
// Check critical services
|
// Check critical services
|
||||||
const services = [
|
const services = [
|
||||||
{ name: 'Web Server', host: 'example.com', port: 443 },
|
{ name: 'Web', host: 'example.com', port: 443 },
|
||||||
{ name: 'Database', host: 'db.internal', port: 5432 },
|
{ name: 'DB', host: 'db.internal', port: 5432 },
|
||||||
{ name: 'Cache', host: 'redis.internal', port: 6379 }
|
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const service of services) {
|
for (const svc of services) {
|
||||||
const isUp = await network.isRemotePortAvailable(service.host, service.port);
|
const up = await network.isRemotePortAvailable(svc.host, svc.port);
|
||||||
console.log(`${service.name}: ${isUp ? '✅ UP' : '❌ DOWN'}`);
|
console.log(`${svc.name}: ${up ? '✅ UP' : '❌ DOWN'}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check internet connectivity
|
// Internet connectivity + latency
|
||||||
const ping = await network.ping('8.8.8.8');
|
const ping = await network.ping('8.8.8.8');
|
||||||
console.log(`Internet: ${ping.alive ? '✅ Connected' : '❌ Disconnected'}`);
|
console.log(`Internet: ${ping.alive ? '✅' : '❌'} (${ping.time} ms)`);
|
||||||
|
|
||||||
// Measure network performance
|
// Speed
|
||||||
const speed = await network.getSpeed();
|
const speed = await network.getSpeed();
|
||||||
console.log(`Speed: ⬇️ ${speed.downloadSpeed} Mbps / ⬆️ ${speed.uploadSpeed} Mbps`);
|
console.log(`Speed: ⬇️ ${speed.downloadSpeed} / ⬆️ ${speed.uploadSpeed} Mbps`);
|
||||||
};
|
|
||||||
|
|
||||||
// Run monitor every minute
|
// Who am I?
|
||||||
setInterval(monitorNetwork, 60000);
|
const ips = await network.getPublicIps();
|
||||||
```
|
if (ips.v4) {
|
||||||
|
const intel = await network.getIpIntelligence(ips.v4);
|
||||||
### Service Discovery
|
console.log(`AS${intel.asn} (${intel.asnOrg}) — ${intel.city || intel.countryCode}`);
|
||||||
|
|
||||||
```typescript
|
|
||||||
const discoverServices = async () => {
|
|
||||||
const network = new SmartNetwork();
|
|
||||||
const commonPorts = [22, 80, 443, 3000, 3306, 5432, 6379, 8080, 9200];
|
|
||||||
|
|
||||||
console.log('🔍 Scanning local services...');
|
|
||||||
|
|
||||||
for (const port of commonPorts) {
|
|
||||||
const isUsed = !(await network.isLocalPortUnused(port));
|
|
||||||
if (isUsed) {
|
|
||||||
console.log(` Port ${port}: In use (possible service running)`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await network.stop();
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 📋 Full API Reference
|
||||||
|
|
||||||
|
| Method | Description | Requires Rust |
|
||||||
|
|--------|-------------|:---:|
|
||||||
|
| `start()` / `stop()` | Start/stop the Rust binary bridge | — |
|
||||||
|
| `getSpeed(opts?)` | Cloudflare speed test (download + upload) | No |
|
||||||
|
| `ping(host, opts?)` | ICMP ping with optional multi-ping stats | Yes |
|
||||||
|
| `traceroute(host, opts?)` | Hop-by-hop network path analysis | Yes |
|
||||||
|
| `isLocalPortUnused(port)` | Check if local port is free (IPv4+IPv6) | Yes |
|
||||||
|
| `findFreePort(start, end, opts?)` | Find available port in range | Yes |
|
||||||
|
| `isRemotePortAvailable(target, opts?)` | TCP port check on remote host | Yes |
|
||||||
|
| `getGateways()` | List all network interfaces | No |
|
||||||
|
| `getDefaultGateway()` | Get default gateway info | Yes |
|
||||||
|
| `getPublicIps()` | Discover public IPv4/IPv6 (4 fallback services) | No |
|
||||||
|
| `resolveDns(host)` | Resolve A, AAAA, MX records | No |
|
||||||
|
| `checkEndpoint(url, opts?)` | HTTP/HTTPS health check with RTT | No |
|
||||||
|
| `getIpIntelligence(ip)` | ASN + org + geo + RDAP registration | No |
|
||||||
|
|
||||||
## License and Legal Information
|
## License and Legal Information
|
||||||
|
|
||||||
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.
|
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](./LICENSE) file.
|
||||||
|
|
||||||
**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.
|
**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.
|
||||||
|
|
||||||
### Trademarks
|
### Trademarks
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
### Company Information
|
### Company Information
|
||||||
|
|
||||||
Task Venture Capital GmbH
|
Task Venture Capital GmbH
|
||||||
Registered at District court Bremen HRB 35230 HB, Germany
|
Registered at District Court Bremen HRB 35230 HB, Germany
|
||||||
|
|
||||||
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
For any legal inquiries or further information, please contact us via email at hello@task.vc.
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@push.rocks/smartnetwork',
|
name: '@push.rocks/smartnetwork',
|
||||||
version: '4.5.1',
|
version: '4.5.2',
|
||||||
description: 'A toolkit for network diagnostics including speed tests, port availability checks, and more.'
|
description: 'A toolkit for network diagnostics including speed tests, port availability checks, and more.'
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user