| 201 | * This follows the Dynamic Args Pattern recommended in component-development.md |
| 202 | */ |
| 203 | const buildSubfinderArgs = (options: BuildSubfinderArgsOptions): string[] => { |
| 204 | const args: string[] = []; |
| 205 | |
| 206 | // Always use silent mode for clean output |
| 207 | args.push('-silent'); |
| 208 | |
| 209 | // Domain list file input |
| 210 | args.push('-dL', options.domainFile); |
| 211 | |
| 212 | // Provider config file (if provided) |
| 213 | if (options.providerConfigFile) { |
| 214 | args.push('-pc', options.providerConfigFile); |
| 215 | } |
| 216 | |
| 217 | // Thread count |
| 218 | if (typeof options.threads === 'number' && options.threads >= 1) { |
| 219 | args.push('-t', String(options.threads)); |
| 220 | } |
| 221 | |
| 222 | // Timeout per source |
| 223 | if (typeof options.timeout === 'number' && options.timeout >= 1) { |
| 224 | args.push('-timeout', String(options.timeout)); |
| 225 | } |
| 226 | |
| 227 | // Max enumeration time |
| 228 | if (typeof options.maxEnumerationTime === 'number' && options.maxEnumerationTime >= 1) { |
| 229 | args.push('-max-time', String(options.maxEnumerationTime)); |
| 230 | } |
| 231 | |
| 232 | // Rate limit |
| 233 | if (typeof options.rateLimit === 'number' && options.rateLimit >= 1) { |
| 234 | args.push('-rl', String(options.rateLimit)); |
| 235 | } |
| 236 | |
| 237 | // All sources |
| 238 | if (options.allSources) { |
| 239 | args.push('-all'); |
| 240 | } |
| 241 | |
| 242 | // Recursive enumeration |
| 243 | if (options.recursive) { |
| 244 | args.push('-recursive'); |
| 245 | } |
| 246 | |
| 247 | // Custom flags (appended last) |
| 248 | for (const flag of options.customFlags) { |
| 249 | if (flag.length > 0) { |
| 250 | args.push(flag); |
| 251 | } |
| 252 | } |
| 253 | |
| 254 | return args; |
| 255 | }; |
| 256 | |
| 257 | // Retry policy for Subfinder - long-running discovery operations |
| 258 | const subfinderRetryPolicy: ComponentRetryPolicy = { |