UNPKG

killit

Version:

Simple, fast port killer with zero dependencies

91 lines (90 loc) 2.99 kB
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;