netsweep 1.0.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.
@@ -0,0 +1,131 @@
1
+ import chalk from 'chalk';
2
+ import boxen from 'boxen';
3
+ import Table from 'cli-table3';
4
+ import type { Device } from '../scanners/devices';
5
+ import type { ConnectionInfo } from '../scanners/connection';
6
+ import type { SpeedResult } from '../scanners/speed';
7
+ import type { PortResult } from '../scanners/ports';
8
+ import { formatSpeed, formatLatency, padRight } from '../utils/format';
9
+
10
+ const BOX_WIDTH = 62;
11
+
12
+ export function header() {
13
+ console.log(
14
+ boxen(chalk.bold.cyan(' NETPROBE - Network Diagnostics '), {
15
+ padding: 0,
16
+ margin: { top: 1, bottom: 0, left: 0, right: 0 },
17
+ borderStyle: 'round',
18
+ borderColor: 'cyan',
19
+ })
20
+ );
21
+ console.log();
22
+ }
23
+
24
+ export function section(title: string, content: string[]) {
25
+ const titleLine = `─ ${chalk.white.bold(title)} `;
26
+ const dashesNeeded = BOX_WIDTH - title.length - 4;
27
+
28
+ console.log(chalk.gray('┌' + titleLine + '─'.repeat(dashesNeeded) + '┐'));
29
+
30
+ content.forEach(line => {
31
+ const visibleLen = stripAnsi(line).length;
32
+ const padding = BOX_WIDTH - visibleLen - 4;
33
+ console.log(chalk.gray('│ ') + line + ' '.repeat(Math.max(0, padding)) + chalk.gray(' │'));
34
+ });
35
+
36
+ console.log(chalk.gray('└' + '─'.repeat(BOX_WIDTH) + '┘'));
37
+ console.log();
38
+ }
39
+
40
+ export function connectionSection(info: ConnectionInfo) {
41
+ section('CONNECTION', [
42
+ `${chalk.gray('Interface:')} ${chalk.white(info.interface)}`,
43
+ `${chalk.gray('Local IP:')} ${chalk.white(info.localIP)}`,
44
+ `${chalk.gray('Gateway:')} ${chalk.white(info.gateway)}`,
45
+ `${chalk.gray('External IP:')} ${chalk.white(info.externalIP)}`,
46
+ `${chalk.gray('DNS:')} ${chalk.white(info.dns.join(', '))}`,
47
+ ]);
48
+ }
49
+
50
+ export function speedSection(speed: SpeedResult) {
51
+ section('SPEED', [
52
+ `${chalk.green('↓')} ${chalk.gray('Download:')} ${chalk.white.bold(formatSpeed(speed.download))}`,
53
+ `${chalk.blue('↑')} ${chalk.gray('Upload:')} ${chalk.white.bold(formatSpeed(speed.upload))}`,
54
+ `${chalk.gray('Latency:')} ${chalk.white(formatLatency(speed.latency))} ${chalk.gray(`(jitter: ${formatLatency(speed.jitter)})`)}`,
55
+ ]);
56
+ }
57
+
58
+ export function devicesSection(devices: Device[]) {
59
+ const table = new Table({
60
+ head: ['IP', 'MAC', 'Vendor', 'Name'].map(h => chalk.cyan(h)),
61
+ style: {
62
+ head: [],
63
+ border: ['gray'],
64
+ },
65
+ chars: {
66
+ 'top': '─', 'top-mid': '┬', 'top-left': '┌', 'top-right': '┐',
67
+ 'bottom': '─', 'bottom-mid': '┴', 'bottom-left': '└', 'bottom-right': '┘',
68
+ 'left': '│', 'left-mid': '├', 'mid': '─', 'mid-mid': '┼',
69
+ 'right': '│', 'right-mid': '┤', 'middle': '│'
70
+ },
71
+ colWidths: [17, 20, 14, 14],
72
+ });
73
+
74
+ devices.forEach(d => {
75
+ const name = d.isCurrentDevice
76
+ ? chalk.green('This Mac')
77
+ : d.hostname
78
+ ? truncate(d.hostname, 12)
79
+ : chalk.gray('-');
80
+
81
+ table.push([
82
+ d.ip,
83
+ d.mac,
84
+ truncate(d.vendor, 12),
85
+ name,
86
+ ]);
87
+ });
88
+
89
+ console.log(chalk.gray(`┌─ ${chalk.white.bold('DEVICES')} (${devices.length} found) ${'─'.repeat(BOX_WIDTH - 18 - String(devices.length).length)}┐`));
90
+ console.log(table.toString());
91
+ console.log();
92
+ }
93
+
94
+ export function portsSection(ports: PortResult[], host: string) {
95
+ if (ports.length === 0) {
96
+ section(`GATEWAY PORTS (${host})`, [
97
+ chalk.gray('No open ports found'),
98
+ ]);
99
+ return;
100
+ }
101
+
102
+ const lines = ports.map(p => {
103
+ const portStr = padRight(`${p.port}/tcp`, 10);
104
+ const serviceStr = padRight(p.service, 10);
105
+ return `${chalk.white(portStr)}${chalk.gray(serviceStr)}${chalk.green('OPEN')}`;
106
+ });
107
+
108
+ section(`GATEWAY PORTS (${host})`, lines);
109
+ }
110
+
111
+ function truncate(str: string, len: number): string {
112
+ if (str.length <= len) return str;
113
+ return str.slice(0, len - 1) + '…';
114
+ }
115
+
116
+ function stripAnsi(str: string): string {
117
+ // eslint-disable-next-line no-control-regex
118
+ return str.replace(/\x1B\[[0-9;]*m/g, '');
119
+ }
120
+
121
+ export interface ScanResults {
122
+ connection?: ConnectionInfo;
123
+ devices?: Device[];
124
+ speed?: SpeedResult;
125
+ ports?: PortResult[];
126
+ gateway?: string;
127
+ }
128
+
129
+ export function outputJson(results: ScanResults) {
130
+ console.log(JSON.stringify(results, null, 2));
131
+ }
@@ -0,0 +1,29 @@
1
+ import ora, { type Ora } from 'ora';
2
+
3
+ let currentSpinner: Ora | null = null;
4
+
5
+ export function startSpinner(text: string): Ora {
6
+ if (currentSpinner) {
7
+ currentSpinner.stop();
8
+ }
9
+ currentSpinner = ora({
10
+ text,
11
+ spinner: 'dots',
12
+ }).start();
13
+ return currentSpinner;
14
+ }
15
+
16
+ export function updateSpinner(text: string): void {
17
+ if (currentSpinner) {
18
+ currentSpinner.text = text;
19
+ } else {
20
+ startSpinner(text);
21
+ }
22
+ }
23
+
24
+ export function stopSpinner(): void {
25
+ if (currentSpinner) {
26
+ currentSpinner.stop();
27
+ currentSpinner = null;
28
+ }
29
+ }
@@ -0,0 +1,10 @@
1
+ import { $ } from 'bun';
2
+
3
+ export async function exec(command: string): Promise<string> {
4
+ try {
5
+ const result = await $`sh -c ${command}`.text();
6
+ return result;
7
+ } catch (error) {
8
+ return '';
9
+ }
10
+ }
@@ -0,0 +1,18 @@
1
+ export function formatSpeed(mbps: number): string {
2
+ if (mbps >= 1000) {
3
+ return `${(mbps / 1000).toFixed(1)} Gbps`;
4
+ }
5
+ return `${mbps.toFixed(1)} Mbps`;
6
+ }
7
+
8
+ export function formatLatency(ms: number): string {
9
+ return `${Math.round(ms)}ms`;
10
+ }
11
+
12
+ export function padRight(str: string, len: number): string {
13
+ return str.length >= len ? str.slice(0, len) : str + ' '.repeat(len - str.length);
14
+ }
15
+
16
+ export function padLeft(str: string, len: number): string {
17
+ return str.length >= len ? str.slice(0, len) : ' '.repeat(len - str.length) + str;
18
+ }