feat(smartnetwork): Add exclude option to findFreePort and skip excluded ports during search
This commit is contained in:
		| @@ -1,5 +1,12 @@ | |||||||
| # Changelog | # Changelog | ||||||
|  |  | ||||||
|  | ## 2025-09-12 - 4.4.0 - feat(smartnetwork) | ||||||
|  | Add exclude option to findFreePort and skip excluded ports during search | ||||||
|  |  | ||||||
|  | - Add an 'exclude' array to IFindFreePortOptions so callers can specify ports to ignore when searching for a free port. | ||||||
|  | - Respect excluded ports in findFreePort for both random (randomize=true) and sequential searches so excluded ports are never returned. | ||||||
|  | - Add .claude/settings.local.json to include local permissions used for development/CI helpers. | ||||||
|  |  | ||||||
| ## 2025-09-12 - 4.3.0 - feat(smartnetwork) | ## 2025-09-12 - 4.3.0 - feat(smartnetwork) | ||||||
| Add randomizable port search and switch DNS resolution to @push.rocks/smartdns; export smartdns and update docs | Add randomizable port search and switch DNS resolution to @push.rocks/smartdns; export smartdns and update docs | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								readme.md
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								readme.md
									
									
									
									
									
								
							| @@ -99,6 +99,19 @@ const findFreePort = async () => { | |||||||
|   // Find a random free port in range (useful to avoid port conflicts) |   // Find a random free port in range (useful to avoid port conflicts) | ||||||
|   const randomPort = await network.findFreePort(3000, 3100, { randomize: true }); |   const randomPort = await network.findFreePort(3000, 3100, { randomize: true }); | ||||||
|   console.log(`🎲 Random free port: ${randomPort}`); |   console.log(`🎲 Random free port: ${randomPort}`); | ||||||
|  |    | ||||||
|  |   // Exclude specific ports from the search | ||||||
|  |   const portWithExclusions = await network.findFreePort(3000, 3100, { | ||||||
|  |     exclude: [3000, 3001, 3005]  // Skip these ports even if they're free | ||||||
|  |   }); | ||||||
|  |   console.log(`🚫 Free port (excluding specific ports): ${portWithExclusions}`); | ||||||
|  |    | ||||||
|  |   // Combine randomize with exclude options | ||||||
|  |   const randomWithExclusions = await network.findFreePort(3000, 3100, { | ||||||
|  |     randomize: true, | ||||||
|  |     exclude: [3000, 3001, 3005] | ||||||
|  |   }); | ||||||
|  |   console.log(`🎲🚫 Random free port (with exclusions): ${randomWithExclusions}`); | ||||||
| }; | }; | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| @@ -333,6 +346,7 @@ interface SmartNetworkOptions { | |||||||
|  |  | ||||||
| interface IFindFreePortOptions { | interface IFindFreePortOptions { | ||||||
|   randomize?: boolean;  // If true, returns a random free port instead of the first one |   randomize?: boolean;  // If true, returns a random free port instead of the first one | ||||||
|  |   exclude?: number[];   // Array of port numbers to exclude from the search | ||||||
| } | } | ||||||
|  |  | ||||||
| interface Hop { | interface Hop { | ||||||
|   | |||||||
| @@ -3,6 +3,6 @@ | |||||||
|  */ |  */ | ||||||
| export const commitinfo = { | export const commitinfo = { | ||||||
|   name: '@push.rocks/smartnetwork', |   name: '@push.rocks/smartnetwork', | ||||||
|   version: '4.3.0', |   version: '4.4.0', | ||||||
|   description: 'A toolkit for network diagnostics including speed tests, port availability checks, and more.' |   description: 'A toolkit for network diagnostics including speed tests, port availability checks, and more.' | ||||||
| } | } | ||||||
|   | |||||||
| @@ -31,6 +31,8 @@ export interface Hop { | |||||||
| export interface IFindFreePortOptions { | export interface IFindFreePortOptions { | ||||||
|   /** If true, selects a random available port within the range instead of the first one */ |   /** If true, selects a random available port within the range instead of the first one */ | ||||||
|   randomize?: boolean; |   randomize?: boolean; | ||||||
|  |   /** Array of port numbers to exclude from the search */ | ||||||
|  |   exclude?: number[]; | ||||||
| } | } | ||||||
|  |  | ||||||
| export class SmartNetwork { | export class SmartNetwork { | ||||||
| @@ -169,12 +171,20 @@ export class SmartNetwork { | |||||||
|       throw new NetworkError('Start port must be less than or equal to end port', 'EINVAL'); |       throw new NetworkError('Start port must be less than or equal to end port', 'EINVAL'); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     // Create a set of excluded ports for efficient lookup | ||||||
|  |     const excludedPorts = new Set(options?.exclude || []); | ||||||
|  |  | ||||||
|     // If randomize option is true, collect all available ports and select randomly |     // If randomize option is true, collect all available ports and select randomly | ||||||
|     if (options?.randomize) { |     if (options?.randomize) { | ||||||
|       const availablePorts: number[] = []; |       const availablePorts: number[] = []; | ||||||
|        |        | ||||||
|       // Scan the range to find all available ports |       // Scan the range to find all available ports | ||||||
|       for (let port = startPort; port <= endPort; port++) { |       for (let port = startPort; port <= endPort; port++) { | ||||||
|  |         // Skip excluded ports | ||||||
|  |         if (excludedPorts.has(port)) { | ||||||
|  |           continue; | ||||||
|  |         } | ||||||
|  |          | ||||||
|         const isUnused = await this.isLocalPortUnused(port); |         const isUnused = await this.isLocalPortUnused(port); | ||||||
|         if (isUnused) { |         if (isUnused) { | ||||||
|           availablePorts.push(port); |           availablePorts.push(port); | ||||||
| @@ -192,6 +202,11 @@ export class SmartNetwork { | |||||||
|     } else { |     } else { | ||||||
|       // Default behavior: return the first available port (sequential search) |       // Default behavior: return the first available port (sequential search) | ||||||
|       for (let port = startPort; port <= endPort; port++) { |       for (let port = startPort; port <= endPort; port++) { | ||||||
|  |         // Skip excluded ports | ||||||
|  |         if (excludedPorts.has(port)) { | ||||||
|  |           continue; | ||||||
|  |         } | ||||||
|  |          | ||||||
|         const isUnused = await this.isLocalPortUnused(port); |         const isUnused = await this.isLocalPortUnused(port); | ||||||
|         if (isUnused) { |         if (isUnused) { | ||||||
|           return port; |           return port; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user