A simple tool to find an open port on the current machine
82
Unix socket path discovery for finding available socket file paths with configurable directory and permission settings.
Finds and returns an unbound Unix socket path. Creates necessary directories if they don't exist.
/**
* Responds with a unbound socket using the specified directory and base name on the current machine
* @param {SocketFinderOptions} [options] - Socket search options
* @param {function} [callback] - Callback function (err, socketPath) => void
* @returns {Promise<string>} Promise resolving to available socket path (when no callback provided)
*/
function getSocket(options?: SocketFinderOptions): Promise<string>;
function getSocket(callback: (err: Error, socket: string) => void): void;
function getSocket(options: SocketFinderOptions, callback: (err: Error, socket: string) => void): void;Usage Examples:
const portfinder = require('portfinder');
// Basic usage with callback - uses default path
portfinder.getSocket(function (err, socketPath) {
if (err) throw err;
console.log('Available socket:', socketPath); // e.g., '/tmp/portfinder.sock'
});
// Promise-based usage
portfinder.getSocketPromise()
.then((socketPath) => {
console.log('Available socket:', socketPath);
})
.catch((err) => {
console.error('Error finding socket:', err);
});
// With custom path - callback style
portfinder.getSocket({
path: '/var/run/myapp.sock'
}, function(err, socketPath) {
if (err) throw err;
console.log('Socket path:', socketPath); // '/var/run/myapp.sock' or '/var/run/myapp1.sock'
});
// With custom directory permissions - Promise style
portfinder.getSocket({
path: '/tmp/sockets/app.sock',
mod: parseInt('755', 8) // Directory permissions in octal
})
.then(socketPath => {
console.log('Socket with custom permissions:', socketPath);
});Promise-based version of getSocket (alias for getSocket without callback).
/**
* Responds a promise that resolves to an unbound socket path
* @param {SocketFinderOptions} [options] - Socket search options
* @returns {Promise<string>} Promise resolving to available socket path
*/
function getSocketPromise(options?: SocketFinderOptions): Promise<string>;Usage Example:
const portfinder = require('portfinder');
// Equivalent to getSocket without callback
const socketPath = await portfinder.getSocketPromise({
path: '/run/user/1000/app.sock'
});
console.log('Found socket path:', socketPath);Gets the next socket path in sequence by incrementing numeric suffix.
/**
* Gets the next socket path in sequence from the specified socketPath
* @param {string} socketPath - Path to increment from
* @returns {string} Next socket path with incremented numeric suffix
*/
function nextSocket(socketPath: string): string;Usage Examples:
const portfinder = require('portfinder');
// Basic increment
const currentSocket = '/tmp/app.sock';
const nextSocket = portfinder.nextSocket(currentSocket);
console.log('Next socket:', nextSocket); // '/tmp/app1.sock'
// With existing number
const numbered = '/tmp/server5.sock';
const incremented = portfinder.nextSocket(numbered);
console.log('Incremented socket:', incremented); // '/tmp/server6.sock'
// Manual socket iteration
let testSocket = '/var/run/worker.sock';
for (let i = 0; i < 5; i++) {
console.log('Testing socket:', testSocket);
testSocket = portfinder.nextSocket(testSocket);
}
// Outputs: worker.sock, worker1.sock, worker2.sock, worker3.sock, worker4.sock/**
* Options for socket finding operations
*/
interface SocketFinderOptions {
/**
* Path to the socket file to create
* Defaults to ${basePath}.sock (e.g., '/tmp/portfinder.sock')
*/
path?: string;
/**
* Mode to use when creating folder for socket if it doesn't exist
* Should be specified in octal format (e.g., parseInt('755', 8))
* Defaults to 755 (rwxr-xr-x)
*/
mod?: number;
}const portfinder = require('portfinder');
// Uses global basePath setting
console.log('Base path:', portfinder.basePath); // '/tmp/portfinder'
portfinder.getSocketPromise().then(socketPath => {
console.log('Default socket:', socketPath); // '/tmp/portfinder.sock'
});const portfinder = require('portfinder');
const fs = require('fs');
// Create a conflicting socket file
fs.writeFileSync('/tmp/test.sock', '');
portfinder.getSocket({ path: '/tmp/test.sock' }, (err, socketPath) => {
console.log('Resolved path:', socketPath); // '/tmp/test1.sock'
});const portfinder = require('portfinder');
const path = require('path');
const os = require('os');
async function createAppSocket(appName, userId) {
const userRunDir = `/run/user/${userId}`;
const socketPath = path.join(userRunDir, `${appName}.sock`);
try {
const finalPath = await portfinder.getSocketPromise({
path: socketPath,
mod: parseInt('700', 8) // Only user can access
});
return finalPath;
} catch (err) {
// Fallback to temp directory
const tempPath = path.join(os.tmpdir(), `${appName}-${userId}.sock`);
return await portfinder.getSocketPromise({ path: tempPath });
}
}
createAppSocket('myapp', 1000).then(socketPath => {
console.log('App socket path:', socketPath);
});const portfinder = require('portfinder');
async function allocateServiceSockets() {
const services = ['api', 'worker', 'scheduler', 'monitor'];
const baseDir = '/var/run/myapp';
const allocations = await Promise.all(
services.map(async (service) => {
const socketPath = await portfinder.getSocketPromise({
path: `${baseDir}/${service}.sock`,
mod: parseInt('755', 8)
});
return { service, socketPath };
})
);
return allocations;
}
allocateServiceSockets().then(allocations => {
console.log('Service socket allocations:', allocations);
// e.g., [
// { service: 'api', socketPath: '/var/run/myapp/api.sock' },
// { service: 'worker', socketPath: '/var/run/myapp/worker.sock' },
// { service: 'scheduler', socketPath: '/var/run/myapp/scheduler1.sock' }, // if scheduler.sock exists
// { service: 'monitor', socketPath: '/var/run/myapp/monitor.sock' }
// ]
});const portfinder = require('portfinder');
const fs = require('fs').promises;
class SocketManager {
constructor() {
this.activeSockets = new Set();
}
async createSocket(options) {
const socketPath = await portfinder.getSocketPromise(options);
this.activeSockets.add(socketPath);
return socketPath;
}
async cleanup() {
const cleanupPromises = Array.from(this.activeSockets).map(async (socketPath) => {
try {
await fs.unlink(socketPath);
console.log('Cleaned up socket:', socketPath);
} catch (err) {
if (err.code !== 'ENOENT') {
console.error('Failed to cleanup socket:', socketPath, err);
}
}
});
await Promise.all(cleanupPromises);
this.activeSockets.clear();
}
}
// Usage
const manager = new SocketManager();
async function example() {
const socket1 = await manager.createSocket({ path: '/tmp/service1.sock' });
const socket2 = await manager.createSocket({ path: '/tmp/service2.sock' });
console.log('Created sockets:', socket1, socket2);
// Cleanup on process exit
process.on('exit', () => manager.cleanup());
}When a socket path is requested, portfinder automatically handles directory creation:
mod option)fs.mkdir with recursive: truemod option for all created directories in the pathconst portfinder = require('portfinder');
// This will create /deep/nested/path/ if it doesn't exist
portfinder.getSocket({
path: '/deep/nested/path/app.sock',
mod: parseInt('755', 8)
}).then(socketPath => {
console.log('Socket created with full path:', socketPath);
});Install with Tessl CLI
npx tessl i tessl/npm-portfinderevals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7