killit
Version:
Simple, fast port killer with zero dependencies
91 lines (90 loc) • 2.99 kB
JavaScript
import { exec } from 'child_process';
import { promisify } from 'util';
const execAsync = promisify(exec);
/**
* Kill process running on the specified port
*/
export async function killPort(port, options = {}) {
const { protocol = 'tcp', verbose = false } = options;
const portNum = typeof port === 'string' ? parseInt(port, 10) : port;
if (!portNum || portNum < 1 || portNum > 65535) {
throw new Error(`Invalid port: ${port}`);
}
const platform = process.platform;
try {
if (platform === 'win32') {
await killPortWindows(portNum, protocol, verbose);
}
else {
await killPortUnix(portNum, protocol, verbose);
}
}
catch (error) {
throw new Error(`Failed to kill process on port ${portNum}: ${error instanceof Error ? error.message : String(error)}`);
}
}
async function killPortWindows(port, protocol, verbose) {
const { stdout } = await execAsync('netstat -ano');
const lines = stdout.split('\n');
const proto = protocol.toUpperCase();
const portRegex = new RegExp(`^\\s*${proto}\\s+[^:]+:${port}\\s`, 'i');
const pids = new Set();
for (const line of lines) {
if (portRegex.test(line)) {
const parts = line.trim().split(/\s+/);
const pid = parts[parts.length - 1];
if (pid && /^\d+$/.test(pid)) {
pids.add(pid);
}
}
}
if (pids.size === 0) {
throw new Error('No process found');
}
for (const pid of pids) {
if (verbose)
console.log(`Killing PID ${pid}`);
await execAsync(`taskkill /F /PID ${pid}`);
}
}
async function killPortUnix(port, protocol, verbose) {
const proto = protocol.toLowerCase();
const grepPattern = protocol === 'udp' ? 'UDP' : 'LISTEN';
try {
const { stdout } = await execAsync(`lsof -i ${proto}:${port} -t`);
const pids = stdout
.trim()
.split('\n')
.filter(pid => pid && /^\d+$/.test(pid));
if (pids.length === 0) {
throw new Error('No process found');
}
for (const pid of pids) {
if (verbose)
console.log(`Killing PID ${pid}`);
await execAsync(`kill -9 ${pid}`);
}
}
catch (error) {
if (error instanceof Error && error.message.includes('Command failed')) {
throw new Error('No process found');
}
throw error;
}
}
/**
* Kill processes on multiple ports
*/
export async function killPorts(ports, options = {}) {
const results = await Promise.allSettled(ports.map(port => killPort(port, options)));
const errors = [];
results.forEach((result, index) => {
if (result.status === 'rejected') {
errors.push(`Port ${ports[index]}: ${result.reason.message}`);
}
});
if (errors.length > 0) {
throw new Error(errors.join('\n'));
}
}
export default killPort;