import * as plugins from './mod.plugins.js'; import * as net from 'net'; /** * Check if a port is available */ export const isPortAvailable = async (port: number): Promise => { return new Promise((resolve) => { const server = net.createServer(); server.once('error', () => { resolve(false); }); server.once('listening', () => { server.close(); resolve(true); }); server.listen(port, '0.0.0.0'); }); }; /** * Get a random available port between 20000 and 30000 */ export const getRandomAvailablePort = async (): Promise => { const maxAttempts = 100; for (let i = 0; i < maxAttempts; i++) { const port = Math.floor(Math.random() * 10001) + 20000; if (await isPortAvailable(port)) { return port; } } // Fallback: let the system assign a port return 0; }; /** * Get the project name from package.json or directory */ export const getProjectName = (): string => { try { const packageJsonPath = plugins.path.join(process.cwd(), 'package.json'); if (plugins.smartfile.fs.fileExistsSync(packageJsonPath)) { const packageJson = plugins.smartfile.fs.toObjectSync(packageJsonPath); if (packageJson.name) { // Sanitize: @fin.cx/skr → fin-cx-skr return packageJson.name.replace(/@/g, '').replace(/[\/\.]/g, '-'); } } } catch (error) { // Ignore errors and fall back to directory name } return plugins.path.basename(process.cwd()); }; /** * Print colored message to console */ export const printMessage = (message: string, color?: 'green' | 'yellow' | 'red' | 'blue' | 'magenta' | 'cyan') => { const logger = new plugins.smartlog.ConsoleLog(); switch (color) { case 'green': logger.log('ok', message); break; case 'yellow': logger.log('note', message); break; case 'red': logger.log('error', message); break; case 'blue': case 'magenta': case 'cyan': logger.log('info', message); break; default: logger.log('info', message); } }; /** * Print a header with decorative lines */ export const printHeader = (title: string) => { console.log(); printMessage('═══════════════════════════════════════════════════════════════', 'cyan'); printMessage(` ${title}`, 'cyan'); printMessage('═══════════════════════════════════════════════════════════════', 'cyan'); console.log(); }; /** * Format bytes to human readable string */ export const formatBytes = (bytes: number): string => { const units = ['B', 'KB', 'MB', 'GB', 'TB']; let size = bytes; let unitIndex = 0; while (size >= 1024 && unitIndex < units.length - 1) { size /= 1024; unitIndex++; } return `${size.toFixed(2)} ${units[unitIndex]}`; }; /** * Get the local network IP address */ export const getLocalNetworkIp = async (): Promise => { const smartnetworkInstance = new plugins.smartnetwork.SmartNetwork(); const gateways = await smartnetworkInstance.getGateways(); // Find the best local IP from network interfaces for (const interfaceName of Object.keys(gateways)) { const interfaces = gateways[interfaceName]; for (const iface of interfaces) { // Skip loopback and internal interfaces if (!iface.internal && iface.family === 'IPv4') { const address = iface.address; // Prefer LAN IPs if (address.startsWith('192.168.') || address.startsWith('10.') || address.startsWith('172.')) { return address; } } } } // Fallback: try to get any non-internal IPv4 for (const interfaceName of Object.keys(gateways)) { const interfaces = gateways[interfaceName]; for (const iface of interfaces) { if (!iface.internal && iface.family === 'IPv4') { return iface.address; } } } // Last resort: localhost return 'localhost'; };