wildcard-domain-finder-plus 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,37 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented here.
4
+
5
+ This project follows Semantic Versioning:
6
+ MAJOR.MINOR.PATCH
7
+
8
+ ---
9
+
10
+ ## 1.0.0 — Initial Public Release
11
+
12
+ ### Added
13
+ - Wildcard domain generation
14
+ - Regex mode
15
+ - Premium TLD support
16
+ - Filtering (tld, length, starts, ends)
17
+ - Sorting (comfirst, tld, length, alpha)
18
+ - Output formats: txt, json, jsonl, csv
19
+ - Streaming generation (no memory blowups)
20
+ - Caching + resume mode
21
+ - Interactive mode
22
+ - Concurrency + timeout controls
23
+ - Full CLI help system
24
+ - Complete README with usage guide and regex helper
25
+
26
+ ---
27
+
28
+ ## 1.0.1 — Documentation Improvements
29
+
30
+ ### Added
31
+ - Quick Start section
32
+ - Common Recipes section
33
+ - Performance Tips section
34
+ - CONTRIBUTING.md
35
+ - CHANGELOG.md
36
+
37
+ ---
@@ -0,0 +1,112 @@
1
+ # Contributing to Wildcard Domain Finder Plus
2
+
3
+ Thank you for your interest in contributing! This project welcomes improvements, bug fixes, documentation updates, and new features.
4
+
5
+ ---
6
+
7
+ ## Code of Conduct
8
+
9
+ By participating in this project, you agree to uphold respectful, constructive communication. Be kind, be clear, and collaborate openly.
10
+
11
+ ---
12
+
13
+ # How to Contribute
14
+
15
+ ## 1. Fork the Repository
16
+
17
+ Create your own fork of the project:
18
+
19
+ https://github.com/nbcr/wildcard-domain-finder-plus
20
+
21
+ Clone your fork:
22
+
23
+ git clone https://github.com/YOUR_USERNAME/wildcard-domain-finder-plus
24
+ cd wildcard-domain-finder-plus
25
+
26
+ ---
27
+
28
+ ## 2. Create a Feature Branch
29
+
30
+ git checkout -b feature/my-new-feature
31
+
32
+ Use descriptive branch names such as:
33
+
34
+ - feature/regex-improvements
35
+ - fix/cache-bug
36
+ - docs/readme-update
37
+
38
+ ---
39
+
40
+ ## 3. Install Dependencies
41
+
42
+ npm install
43
+
44
+ ---
45
+
46
+ ## 4. Make Your Changes
47
+
48
+ Follow these guidelines:
49
+
50
+ - Keep code modular and readable
51
+ - Add comments where clarity helps
52
+ - Maintain consistent formatting
53
+ - Avoid breaking existing functionality
54
+
55
+ ---
56
+
57
+ ## 5. Add or Update Tests (if applicable)
58
+
59
+ Place tests under:
60
+
61
+ /tests
62
+
63
+ Run tests:
64
+
65
+ npm test
66
+
67
+ ---
68
+
69
+ ## 6. Commit Your Changes
70
+
71
+ Use clear, conventional commit messages:
72
+
73
+ git commit -m "feat: add premium TLD filtering"
74
+ git commit -m "fix: correct wildcard expansion bug"
75
+
76
+ ---
77
+
78
+ ## 7. Push and Open a Pull Request
79
+
80
+ git push origin feature/my-new-feature
81
+
82
+ Then open a PR on GitHub:
83
+
84
+ - Describe what you changed
85
+ - Explain why
86
+ - Link related issues
87
+
88
+ A maintainer will review your PR and work with you to merge it.
89
+
90
+ ---
91
+
92
+ ## 8. Style Guidelines
93
+
94
+ - Use modern JavaScript (ES modules)
95
+ - Prefer async/await
96
+ - Avoid unnecessary dependencies
97
+ - Keep CLI output clean and readable
98
+
99
+ ---
100
+
101
+ ## 9. Reporting Issues
102
+
103
+ If you find a bug, open an issue with:
104
+
105
+ - Steps to reproduce
106
+ - Expected behavior
107
+ - Actual behavior
108
+ - Environment details
109
+
110
+ ---
111
+
112
+ Thank you for contributing!
package/README.md ADDED
@@ -0,0 +1,345 @@
1
+ ## Attribution
2
+
3
+ This project is an enhanced fork of
4
+ **besoeasy/wildcard-domain-finder**
5
+ Original work Ā© the respective author(s), licensed under the ISC License.
6
+
7
+ This fork adds major new capabilities including:
8
+ - streaming domain generation (no memory blowups)
9
+ - regex mode
10
+ - wildcard mode
11
+ - TLD selection (explicit, all, premium)
12
+ - filtering (tld, length, starts, ends)
13
+ - sorting (comfirst, tld, length, alpha)
14
+ - JSON / JSONL / CSV / TXT output
15
+ - caching + resume mode
16
+ - interactive pause/resume/quit controls
17
+ - concurrency + timeout controls
18
+ - full CLI help system
19
+
20
+ All original licensing terms are preserved.
21
+
22
+ ---
23
+
24
+ # Wildcard Domain Finder Plus
25
+
26
+ A command-line tool to find available domain names using wildcard patterns, regex patterns, or structured filters — now with streaming generation, caching, and advanced TLD control.
27
+
28
+ ---
29
+
30
+ # Quick Start
31
+
32
+ Install globally:
33
+
34
+ npm install -g wildcard-domain-finder-plus
35
+
36
+ Run a simple wildcard scan:
37
+
38
+ wildcard-domain-finder-plus -d "test*.com"
39
+
40
+ Run a regex scan:
41
+
42
+ wildcard-domain-finder-plus --regex "^[a-z]{3}\\.com$"
43
+
44
+ Scan all TLDs:
45
+
46
+ wildcard-domain-finder-plus -d "go*" --tlds all
47
+
48
+ ---
49
+
50
+ # Installation
51
+
52
+ ### Via NPX (no installation required)
53
+
54
+ npx wildcard-domain-finder-plus
55
+
56
+ ### Or install globally
57
+
58
+ npm install -g wildcard-domain-finder-plus
59
+
60
+ ---
61
+
62
+ # Usage Guide
63
+
64
+ Wildcard Domain Finder Plus supports three primary modes:
65
+
66
+ 1. Wildcard mode
67
+ 2. Regex mode
68
+ 3. Structured filtering mode
69
+
70
+ Each mode can be combined with TLD selection, sorting, output formatting, and caching.
71
+
72
+ ---
73
+
74
+ ## Wildcard Mode
75
+
76
+ Use * to represent any single alphanumeric character (a–z, 0–9).
77
+
78
+ Example:
79
+
80
+ wildcard-domain-finder-plus -d "test*.com"
81
+
82
+ This expands to:
83
+
84
+ - testa.com
85
+ - testb.com
86
+ - test1.com
87
+ - …and so on
88
+
89
+ Wildcard mode is ideal when you know the pattern but not the exact characters.
90
+
91
+ ---
92
+
93
+ ## Regex Mode
94
+
95
+ Regex mode gives you full control over domain label generation.
96
+
97
+ Example:
98
+
99
+ wildcard-domain-finder-plus --regex "^[a-z0-9]{3}\\.com$"
100
+
101
+ This generates:
102
+
103
+ - aaa.com
104
+ - aab.com
105
+ - …
106
+ - zzz.com
107
+
108
+ Regex mode supports:
109
+
110
+ - character classes
111
+ - alternation
112
+ - anchors
113
+ - quantifiers
114
+ - grouping
115
+
116
+ ---
117
+
118
+ # Regex Helper
119
+
120
+ ### Three‑letter domains
121
+
122
+ ^[a-z]{3}\\.(com|net|org)$
123
+
124
+ ### Two letters + one digit
125
+
126
+ ^[a-z]{2}[0-9]\\.com$
127
+
128
+ ### Start with ā€œgoā€, then any 2 chars
129
+
130
+ ^go[a-z0-9]{2}\\.io$
131
+
132
+ ### Premium TLDs only
133
+
134
+ ^[a-z]{3,5}\\.(ai|io|dev)$
135
+
136
+ ### Only letters (no digits)
137
+
138
+ ^[a-z]+\\.(com|net)$
139
+
140
+ ### Letters + optional hyphen
141
+
142
+ ^[a-z]+(-[a-z]+)?\\.com$
143
+
144
+ ### Multiple TLDs
145
+
146
+ ^[a-z]{4}\\.(com|io|ai|co)$
147
+
148
+ ---
149
+
150
+ # TLD Selection
151
+
152
+ Choose from:
153
+
154
+ - explicit list
155
+ - all known TLDs
156
+ - premium curated list
157
+
158
+ Examples:
159
+
160
+ wildcard-domain-finder-plus -d "go*" --tlds all
161
+
162
+ wildcard-domain-finder-plus -d "ai*" --tlds premium
163
+
164
+ wildcard-domain-finder-plus -d "shop*" --tlds com,net,org,io
165
+
166
+ ---
167
+
168
+ # Filtering
169
+
170
+ Filters allow you to refine generated domains.
171
+
172
+ Supported filters:
173
+
174
+ - tld:com
175
+ - length<=3
176
+ - starts:go
177
+ - ends:ai
178
+
179
+ Examples:
180
+
181
+ wildcard-domain-finder-plus -d "***.com" --filter length<=3
182
+
183
+ wildcard-domain-finder-plus -d "*ai" --filter ends:ai
184
+
185
+ wildcard-domain-finder-plus -d "go*" --filter starts:go
186
+
187
+ ---
188
+
189
+ # Sorting
190
+
191
+ Sorting options:
192
+
193
+ - comfirst
194
+ - tld
195
+ - length
196
+ - alpha
197
+
198
+ Example:
199
+
200
+ wildcard-domain-finder-plus -d "***.com" --sort comfirst
201
+
202
+ ---
203
+
204
+ # Output Formats
205
+
206
+ Choose from:
207
+
208
+ - txt
209
+ - json
210
+ - jsonl
211
+ - csv
212
+
213
+ Example:
214
+
215
+ wildcard-domain-finder-plus -d "go*" -F jsonl -o results.jsonl
216
+
217
+ ---
218
+
219
+ # Caching and Resume Mode
220
+
221
+ Large scans can be resumed:
222
+
223
+ wildcard-domain-finder-plus -R
224
+
225
+ Disable caching:
226
+
227
+ wildcard-domain-finder-plus --no-cache
228
+
229
+ ---
230
+
231
+ # Interactive Mode
232
+
233
+ If no domain or regex is provided:
234
+
235
+ wildcard-domain-finder-plus
236
+
237
+ You will be prompted for:
238
+
239
+ - mode
240
+ - pattern
241
+ - TLDs
242
+ - filters
243
+ - output format
244
+
245
+ ---
246
+
247
+ # Common Recipes
248
+
249
+ ### Find all 3‑letter .com domains
250
+
251
+ wildcard-domain-finder-plus --regex "^[a-z]{3}\\.com$"
252
+
253
+ ### Find all domains starting with ā€œgoā€ across all TLDs
254
+
255
+ wildcard-domain-finder-plus -d "go*" --tlds all
256
+
257
+ ### Find short premium domains
258
+
259
+ wildcard-domain-finder-plus -d "***" --tlds premium --filter length<=3
260
+
261
+ ### Find 4‑letter .io or .ai domains
262
+
263
+ wildcard-domain-finder-plus --regex "^[a-z]{4}\\.(io|ai)$"
264
+
265
+ ### Wildcard + filtering + sorting
266
+
267
+ wildcard-domain-finder-plus -d "go**.com" --filter length<=4 --sort alpha
268
+
269
+ ---
270
+
271
+ # Performance Tips
272
+
273
+ ### 1. Increase concurrency for faster scans
274
+
275
+ --concurrency 50
276
+
277
+ ### 2. Reduce DNS timeout for faster failures
278
+
279
+ --timeout 2000
280
+
281
+ ### 3. Use JSONL for huge output sets
282
+
283
+ -F jsonl
284
+
285
+ ### 4. Use resume mode for long scans
286
+
287
+ -R
288
+
289
+ ### 5. Limit search space with filters
290
+
291
+ --filter length<=4
292
+ --filter starts:go
293
+ --filter tld:com
294
+
295
+ ### 6. Prefer regex for structured patterns
296
+
297
+ Regex mode avoids generating unnecessary combinations.
298
+
299
+ ---
300
+
301
+ # Full Examples
302
+
303
+ ### Wildcard + premium TLDs
304
+
305
+ wildcard-domain-finder-plus -d "ai*" --tlds premium
306
+
307
+ ### Regex + JSONL output
308
+
309
+ wildcard-domain-finder-plus --regex "^[a-z]{4}\\.(io|ai)$" -F jsonl
310
+
311
+ ### Resume a long scan
312
+
313
+ wildcard-domain-finder-plus -R
314
+
315
+ ---
316
+
317
+ # Features
318
+
319
+ - ⚔ Streaming domain generation (no memory blowups)
320
+ - šŸƒ Wildcard mode (* = single character)
321
+ - šŸ” Regex mode
322
+ - šŸŒ TLD selection (explicit, all, premium)
323
+ - 🧹 Filtering (tld, length, starts, ends)
324
+ - šŸ”ƒ Sorting (comfirst, tld, length, alpha)
325
+ - šŸ“ Multiple output formats (txt, json, jsonl, csv)
326
+ - šŸ’¾ Caching + resume mode
327
+ - āøļø Interactive pause/resume/quit
328
+ - ā±ļø Concurrency + timeout controls
329
+ - šŸ›”ļø Graceful error handling
330
+ - ā“ Full CLI help system
331
+
332
+ ---
333
+
334
+ # License
335
+
336
+ ISC
337
+ All original licensing terms are preserved.
338
+
339
+ ---
340
+
341
+ # Links
342
+
343
+ - NPM Package: https://www.npmjs.com/package/wildcard-domain-finder-plus
344
+ - GitHub Repository: https://github.com/nbcr/wildcard-domain-finder-plus
345
+ - Issues: https://github.com/nbcr/wildcard-domain-finder-plus/issues
package/README.txt ADDED
@@ -0,0 +1,219 @@
1
+ Attribution
2
+ This project is an enhanced fork of
3
+ besoeasy/wildcard-domain-finder
4
+ Original work Ā© the respective author(s), licensed under the ISC License.
5
+
6
+ This fork adds major new capabilities including:
7
+
8
+ streaming domain generation (no memory blowups)
9
+ regex mode
10
+ wildcard mode
11
+ TLD selection (explicit, all, premium)
12
+ filtering (tld, length, starts, ends)
13
+ sorting (comfirst, tld, length, alpha)
14
+ JSON / JSONL / CSV / TXT output
15
+ caching + resume mode
16
+ interactive pause/resume/quit controls
17
+ concurrency + timeout controls
18
+ full CLI help system
19
+ All original licensing terms are preserved.
20
+
21
+ Wildcard Domain Finder Plus
22
+ A command-line tool to find available domain names using wildcard patterns, regex patterns, or structured filters — now with streaming generation, caching, and advanced TLD control.
23
+
24
+ Quick Start
25
+ Install globally:
26
+
27
+ npm install -g wildcard-domain-finder-plus
28
+ Run a simple wildcard scan:
29
+
30
+ wildcard-domain-finder-plus -d "test*.com"
31
+ Run a regex scan:
32
+
33
+ wildcard-domain-finder-plus --regex "^[a-z]{3}\\.com$"
34
+ Scan all TLDs:
35
+
36
+ wildcard-domain-finder-plus -d "go*" --tlds all
37
+ Installation
38
+ Via NPX (no installation required)
39
+ npx wildcard-domain-finder-plus
40
+ Or install globally
41
+ npm install -g wildcard-domain-finder-plus
42
+ Usage Guide
43
+ Wildcard Domain Finder Plus supports three primary modes:
44
+
45
+ Wildcard mode
46
+ Regex mode
47
+ Structured filtering mode
48
+ Each mode can be combined with TLD selection, sorting, output formatting, and caching.
49
+
50
+ Wildcard Mode
51
+ Use * to represent any single alphanumeric character (a–z, 0–9).
52
+
53
+ Example:
54
+
55
+ wildcard-domain-finder-plus -d "test*.com"
56
+ This expands to:
57
+
58
+ testa.com
59
+ testb.com
60
+ test1.com
61
+ …and so on
62
+ Wildcard mode is ideal when you know the pattern but not the exact characters.
63
+
64
+ Regex Mode
65
+ Regex mode gives you full control over domain label generation.
66
+
67
+ Example:
68
+
69
+ wildcard-domain-finder-plus --regex "^[a-z0-9]{3}\\.com$"
70
+ This generates:
71
+
72
+ aaa.com
73
+ aab.com
74
+ …
75
+ zzz.com
76
+ Regex mode supports:
77
+
78
+ character classes
79
+ alternation
80
+ anchors
81
+ quantifiers
82
+ grouping
83
+ Regex Helper
84
+ Three‑letter domains
85
+ ^[a-z]{3}\\.(com|net|org)$
86
+ Two letters + one digit
87
+ ^[a-z]{2}[0-9]\\.com$
88
+ Start with ā€œgoā€, then any 2 chars
89
+ ^go[a-z0-9]{2}\\.io$
90
+ Premium TLDs only
91
+ ^[a-z]{3,5}\\.(ai|io|dev)$
92
+ Only letters (no digits)
93
+ ^[a-z]+\\.(com|net)$
94
+ Letters + optional hyphen
95
+ ^[a-z]+(-[a-z]+)?\\.com$
96
+ Multiple TLDs
97
+ ^[a-z]{4}\\.(com|io|ai|co)$
98
+ TLD Selection
99
+ Choose from:
100
+
101
+ explicit list
102
+ all known TLDs
103
+ premium curated list
104
+ Examples:
105
+
106
+ wildcard-domain-finder-plus -d "go*" --tlds all
107
+
108
+ wildcard-domain-finder-plus -d "ai*" --tlds premium
109
+
110
+ wildcard-domain-finder-plus -d "shop*" --tlds com,net,org,io
111
+ Filtering
112
+ Filters allow you to refine generated domains.
113
+
114
+ Supported filters:
115
+
116
+ tld:com
117
+ length<=3
118
+ starts:go
119
+ ends:ai
120
+ Examples:
121
+
122
+ wildcard-domain-finder-plus -d "***.com" --filter length<=3
123
+
124
+ wildcard-domain-finder-plus -d "*ai" --filter ends:ai
125
+
126
+ wildcard-domain-finder-plus -d "go*" --filter starts:go
127
+ Sorting
128
+ Sorting options:
129
+
130
+ comfirst
131
+ tld
132
+ length
133
+ alpha
134
+ Example:
135
+
136
+ wildcard-domain-finder-plus -d "***.com" --sort comfirst
137
+ Output Formats
138
+ Choose from:
139
+
140
+ txt
141
+ json
142
+ jsonl
143
+ csv
144
+ Example:
145
+
146
+ wildcard-domain-finder-plus -d "go*" -F jsonl -o results.jsonl
147
+ Caching and Resume Mode
148
+ Large scans can be resumed:
149
+
150
+ wildcard-domain-finder-plus -R
151
+ Disable caching:
152
+
153
+ wildcard-domain-finder-plus --no-cache
154
+ Interactive Mode
155
+ If no domain or regex is provided:
156
+
157
+ wildcard-domain-finder-plus
158
+ You will be prompted for:
159
+
160
+ mode
161
+ pattern
162
+ TLDs
163
+ filters
164
+ output format
165
+ Common Recipes
166
+ Find all 3‑letter .com domains
167
+ wildcard-domain-finder-plus --regex "^[a-z]{3}\\.com$"
168
+ Find all domains starting with ā€œgoā€ across all TLDs
169
+ wildcard-domain-finder-plus -d "go*" --tlds all
170
+ Find short premium domains
171
+ wildcard-domain-finder-plus -d "***" --tlds premium --filter length<=3
172
+ Find 4‑letter .io or .ai domains
173
+ wildcard-domain-finder-plus --regex "^[a-z]{4}\\.(io|ai)$"
174
+ Wildcard + filtering + sorting
175
+ wildcard-domain-finder-plus -d "go**.com" --filter length<=4 --sort alpha
176
+ Performance Tips
177
+ 1. Increase concurrency for faster scans
178
+ --concurrency 50
179
+ 2. Reduce DNS timeout for faster failures
180
+ --timeout 2000
181
+ 3. Use JSONL for huge output sets
182
+ -F jsonl
183
+ 4. Use resume mode for long scans
184
+ -R
185
+ 5. Limit search space with filters
186
+ --filter length<=4
187
+ --filter starts:go
188
+ --filter tld:com
189
+ 6. Prefer regex for structured patterns
190
+ Regex mode avoids generating unnecessary combinations.
191
+
192
+ Full Examples
193
+ Wildcard + premium TLDs
194
+ wildcard-domain-finder-plus -d "ai*" --tlds premium
195
+ Regex + JSONL output
196
+ wildcard-domain-finder-plus --regex "^[a-z]{4}\\.(io|ai)$" -F jsonl
197
+ Resume a long scan
198
+ wildcard-domain-finder-plus -R
199
+ Features
200
+ ⚔ Streaming domain generation (no memory blowups)
201
+ šŸƒ Wildcard mode (* = single character)
202
+ šŸ” Regex mode
203
+ šŸŒ TLD selection (explicit, all, premium)
204
+ 🧹 Filtering (tld, length, starts, ends)
205
+ šŸ”ƒ Sorting (comfirst, tld, length, alpha)
206
+ šŸ“ Multiple output formats (txt, json, jsonl, csv)
207
+ šŸ’¾ Caching + resume mode
208
+ āøļø Interactive pause/resume/quit
209
+ ā±ļø Concurrency + timeout controls
210
+ šŸ›”ļø Graceful error handling
211
+ ā“ Full CLI help system
212
+ License
213
+ ISC
214
+ All original licensing terms are preserved.
215
+
216
+ Links
217
+ NPM Package: https://www.npmjs.com/package/wildcard-domain-finder-plus
218
+ GitHub Repository: https://github.com/nbcr/wildcard-domain-finder-plus
219
+ Issues: https://github.com/nbcr/wildcard-domain-finder-plus/issues
package/app.js ADDED
@@ -0,0 +1,558 @@
1
+ #!/usr/bin/env node
2
+
3
+ // wildcard-domain-finder (upgraded)
4
+ // - Supports wildcard patterns (* = single char)
5
+ // - Optional regex mode
6
+ // - TLD selection (explicit, all, premium)
7
+ // - Filtering (tld, length, starts, ends)
8
+ // - Sorting (comfirst, tld, length, alpha)
9
+ // - Output formats: txt, json, jsonl, csv
10
+ // - Caching + resume via JSONL
11
+ // - Streaming generation (no heap blowups)
12
+ // - Concurrency + timeout
13
+ // - Interactive pause/resume/quit (p/r/q)
14
+
15
+ const fs = require('fs');
16
+ const dns = require('dns').promises;
17
+ const readline = require('readline');
18
+
19
+ const CHARSET = 'abcdefghijklmnopqrstuvwxyz0123456789';
20
+
21
+ const IANA_TLDS = [
22
+ 'com','net','org','edu','gov','mil','int',
23
+ 'ca','us','uk','de','fr','au','jp','cn','io','ai','co','me','tv','cc',
24
+ 'xyz','info','biz','name','pro','tech','dev','app','cloud','store','shop',
25
+ 'site','online','space','fun','live','world','today','news','media','social',
26
+ 'group','club','team','company','agency','solutions','systems','network',
27
+ 'software','digital','finance','capital','partners','ventures','consulting',
28
+ 'services','support','help','care','health','clinic','law','legal',
29
+ 'design','photo','photos','gallery','art','music','video','games','game',
30
+ 'blog','wiki','school','academy','training','university','science',
31
+ 'research','energy','solar','green','eco','earth','bio','farm','garden',
32
+ 'coffee','pizza','bar','restaurant','kitchen','food','wine','beer',
33
+ 'fashion','style','beauty','spa','travel','vacations','holiday','flights',
34
+ 'hotel','rentals','cars','auto','car','bike','homes','house','realty',
35
+ 'estate','property','land','city','zone','global','africa','asia','europe'
36
+ ];
37
+
38
+ const PREMIUM_TLDS = ['com','net','org','io','ai','co','dev','app','xyz','tech'];
39
+
40
+ const DOMAIN_REGEX = /^(?=.{1,253}$)(?!.*\.\.)([A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+[A-Za-z]{2,63}$/;
41
+
42
+ let paused = false;
43
+ let quitting = false;
44
+
45
+ function isValidDomain(domain) {
46
+ return DOMAIN_REGEX.test(domain);
47
+ }
48
+
49
+ function sleep(ms) {
50
+ return new Promise(res => setTimeout(res, ms));
51
+ }
52
+
53
+ function setupInteractiveControls() {
54
+ readline.emitKeypressEvents(process.stdin);
55
+ if (process.stdin.isTTY) process.stdin.setRawMode(true);
56
+
57
+ process.stdin.on('keypress', (str, key) => {
58
+ if (!key) return;
59
+ if (key.name === 'p') {
60
+ paused = true;
61
+ process.stdout.write('\nāøļø Paused. Press r to resume, q to quit.\n');
62
+ }
63
+ if (key.name === 'r') {
64
+ paused = false;
65
+ process.stdout.write('\nā–¶ļø Resumed.\n');
66
+ }
67
+ if (key.name === 'q') {
68
+ quitting = true;
69
+ process.stdout.write('\nšŸ›‘ Quitting gracefully...\n');
70
+ }
71
+ });
72
+ }
73
+
74
+ // ---------- CLI PARSING ----------
75
+
76
+ function parseArgs() {
77
+ const args = process.argv.slice(2);
78
+ const opts = {
79
+ pattern: null,
80
+ regex: null,
81
+ tlds: null,
82
+ allTlds: false,
83
+ premiumTlds: false,
84
+ filters: [],
85
+ sort: null,
86
+ format: 'txt',
87
+ output: 'available_domains.txt',
88
+ concurrency: 10,
89
+ timeout: 5000,
90
+ resume: false,
91
+ cacheFile: 'checked_domains.jsonl',
92
+ useCache: true,
93
+ maxLength: 4
94
+ };
95
+
96
+ for (let i = 0; i < args.length; i++) {
97
+ const a = args[i];
98
+ if (a === '-d' || a === '--domain') {
99
+ opts.pattern = args[++i];
100
+ } else if (a === '-r' || a === '--regex') {
101
+ opts.regex = args[++i];
102
+ } else if (a === '-t' || a === '--tlds') {
103
+ const v = args[++i];
104
+ if (v === 'all') opts.allTlds = true;
105
+ else if (v === 'premium') opts.premiumTlds = true;
106
+ else opts.tlds = v.split(',').map(s => s.trim().toLowerCase()).filter(Boolean);
107
+ } else if (a === '-f' || a === '--filter') {
108
+ opts.filters.push(args[++i]);
109
+ } else if (a === '-s' || a === '--sort') {
110
+ opts.sort = args[++i]; // comfirst | tld | length | alpha
111
+ } else if (a === '-F' || a === '--format') {
112
+ opts.format = args[++i].toLowerCase(); // txt | json | jsonl | csv
113
+ } else if (a === '-o' || a === '--output') {
114
+ opts.output = args[++i];
115
+ } else if (a === '-c' || a === '--concurrency') {
116
+ opts.concurrency = parseInt(args[++i], 10) || 10;
117
+ } else if (a === '-T' || a === '--timeout') {
118
+ opts.timeout = parseInt(args[++i], 10) || 5000;
119
+ } else if (a === '-R' || a === '--resume') {
120
+ opts.resume = true;
121
+ } else if (a === '--no-resume') {
122
+ opts.resume = false;
123
+ } else if (a === '-C' || a === '--cache') {
124
+ opts.cacheFile = args[++i];
125
+ } else if (a === '--no-cache') {
126
+ opts.useCache = false;
127
+ } else if (a === '--max-length') {
128
+ opts.maxLength = parseInt(args[++i], 10) || 4;
129
+ } else if (a === '-h' || a === '--help') {
130
+ printHelp();
131
+ process.exit(0);
132
+ }
133
+ }
134
+
135
+ return opts;
136
+ }
137
+
138
+ function printHelp() {
139
+ console.log(`
140
+ Wildcard Domain Finder (upgraded)
141
+
142
+ Usage:
143
+ wildcard-domain-finder [options]
144
+
145
+ Domain Input:
146
+ -d, --domain <pattern> Wildcard pattern (* = single char)
147
+ -r, --regex <regex> Regex pattern for full domain
148
+ -t, --tlds <list> Comma-separated TLDs (e.g. com,net,io)
149
+ --tlds all Use all known TLDs
150
+ --tlds premium Use premium TLD list
151
+ --max-length <n> Max label length for regex mode (default: 4)
152
+
153
+ Filtering:
154
+ -f, --filter <rule> Filter results:
155
+ tld:com
156
+ tld:com,io,net
157
+ length<=3
158
+ length>=2
159
+ starts:go
160
+ ends:ai
161
+
162
+ Sorting:
163
+ -s, --sort <mode> Sort results:
164
+ comfirst (.com first)
165
+ tld group by TLD
166
+ length shortest first
167
+ alpha alphabetical
168
+
169
+ Output:
170
+ -F, --format <fmt> txt | json | jsonl | csv
171
+ -o, --output <file> Output file path
172
+
173
+ Performance:
174
+ -c, --concurrency <n> DNS concurrency (default: 10)
175
+ -T, --timeout <ms> DNS timeout (default: 5000)
176
+
177
+ Resume / Cache:
178
+ -R, --resume Resume from cache (skip already checked)
179
+ --no-resume Ignore cache
180
+ -C, --cache <file> Cache file (default: checked_domains.jsonl)
181
+ --no-cache Disable caching
182
+
183
+ Interactive Controls:
184
+ p Pause
185
+ r Resume
186
+ q Quit gracefully
187
+ `);
188
+ }
189
+
190
+ // ---------- FILTERS & SORTING ----------
191
+
192
+ function parseFilterRule(rule) {
193
+ // tld:com,io
194
+ if (rule.startsWith('tld:')) {
195
+ const list = rule.slice(4).split(',').map(s => s.trim().toLowerCase()).filter(Boolean);
196
+ return { type: 'tld', list };
197
+ }
198
+
199
+ // length<=3, length>=2
200
+ if (rule.startsWith('length<=')) {
201
+ const n = parseInt(rule.slice('length<='.length), 10);
202
+ return { type: 'lengthMax', value: n };
203
+ }
204
+ if (rule.startsWith('length>=')) {
205
+ const n = parseInt(rule.slice('length>='.length), 10);
206
+ return { type: 'lengthMin', value: n };
207
+ }
208
+
209
+ // starts:go
210
+ if (rule.startsWith('starts:')) {
211
+ const v = rule.slice('starts:'.length).toLowerCase();
212
+ return { type: 'starts', value: v };
213
+ }
214
+
215
+ // ends:ai
216
+ if (rule.startsWith('ends:')) {
217
+ const v = rule.slice('ends:'.length).toLowerCase();
218
+ return { type: 'ends', value: v };
219
+ }
220
+
221
+ return null;
222
+ }
223
+
224
+ function buildFilters(filterStrings) {
225
+ return filterStrings
226
+ .map(parseFilterRule)
227
+ .filter(Boolean);
228
+ }
229
+
230
+ function passesFilters(domain, filters) {
231
+ if (!filters.length) return true;
232
+
233
+ const [name, tld] = (() => {
234
+ const parts = domain.split('.');
235
+ const tld = parts.pop().toLowerCase();
236
+ const name = parts.join('.').toLowerCase();
237
+ return [name, tld];
238
+ })();
239
+
240
+ for (const f of filters) {
241
+ if (f.type === 'tld') {
242
+ if (!f.list.includes(tld)) return false;
243
+ } else if (f.type === 'lengthMax') {
244
+ if (name.length > f.value) return false;
245
+ } else if (f.type === 'lengthMin') {
246
+ if (name.length < f.value) return false;
247
+ } else if (f.type === 'starts') {
248
+ if (!name.startsWith(f.value)) return false;
249
+ } else if (f.type === 'ends') {
250
+ if (!name.endsWith(f.value)) return false;
251
+ }
252
+ }
253
+
254
+ return true;
255
+ }
256
+
257
+ function sortResults(results, mode) {
258
+ if (!mode) return results;
259
+
260
+ if (mode === 'comfirst') {
261
+ return results.sort((a, b) => {
262
+ const aCom = a.tld === 'com' ? 0 : 1;
263
+ const bCom = b.tld === 'com' ? 0 : 1;
264
+ if (aCom !== bCom) return aCom - bCom;
265
+ return a.domain.localeCompare(b.domain);
266
+ });
267
+ }
268
+
269
+ if (mode === 'tld') {
270
+ return results.sort((a, b) => {
271
+ if (a.tld !== b.tld) return a.tld.localeCompare(b.tld);
272
+ return a.domain.localeCompare(b.domain);
273
+ });
274
+ }
275
+
276
+ if (mode === 'length') {
277
+ return results.sort((a, b) => {
278
+ if (a.name.length !== b.name.length) return a.name.length - b.name.length;
279
+ return a.domain.localeCompare(b.domain);
280
+ });
281
+ }
282
+
283
+ if (mode === 'alpha') {
284
+ return results.sort((a, b) => a.domain.localeCompare(b.domain));
285
+ }
286
+
287
+ return results;
288
+ }
289
+
290
+ // ---------- PATTERN / REGEX GENERATION ----------
291
+
292
+ function* expandWildcardPattern(pattern) {
293
+ // * = single char from CHARSET
294
+ function* helper(index, prefix) {
295
+ if (index === pattern.length) {
296
+ yield prefix;
297
+ return;
298
+ }
299
+ const ch = pattern[index];
300
+ if (ch === '*') {
301
+ for (const c of CHARSET) {
302
+ yield* helper(index + 1, prefix + c);
303
+ }
304
+ } else {
305
+ yield* helper(index + 1, prefix + ch);
306
+ }
307
+ }
308
+ yield* helper(0, '');
309
+ }
310
+
311
+ function* expandPatternWithTlds(pattern, tlds) {
312
+ if (pattern.endsWith('.*')) {
313
+ const core = pattern.slice(0, -2); // keep trailing dot
314
+ for (const base of expandWildcardPattern(core)) {
315
+ for (const tld of tlds) {
316
+ yield base + tld;
317
+ }
318
+ }
319
+ } else {
320
+ yield* expandWildcardPattern(pattern);
321
+ }
322
+ }
323
+
324
+ function* generateAllDomainsForRegex(maxLength, tlds) {
325
+ function* build(prefix, depth) {
326
+ if (depth === 0) {
327
+ for (const tld of tlds) {
328
+ yield prefix + '.' + tld;
329
+ }
330
+ return;
331
+ }
332
+ for (const c of CHARSET) {
333
+ yield* build(prefix + c, depth - 1);
334
+ }
335
+ }
336
+
337
+ for (let len = 1; len <= maxLength; len++) {
338
+ yield* build('', len);
339
+ }
340
+ }
341
+
342
+ // ---------- DNS + CACHE ----------
343
+
344
+ async function checkDomain(domain, timeoutMs) {
345
+ const timeout = new Promise((_, reject) =>
346
+ setTimeout(() => reject(new Error('TIMEOUT')), timeoutMs)
347
+ );
348
+
349
+ try {
350
+ await Promise.race([
351
+ dns.resolveAny(domain),
352
+ timeout
353
+ ]);
354
+ return { domain, available: false, error: null };
355
+ } catch (err) {
356
+ if (err.code === 'ENOTFOUND' || err.code === 'ENODATA') {
357
+ return { domain, available: true, error: null };
358
+ }
359
+ if (err.message === 'TIMEOUT') {
360
+ return { domain, available: null, error: 'timeout' };
361
+ }
362
+ return { domain, available: null, error: err.code || err.message };
363
+ }
364
+ }
365
+
366
+ function loadCache(cacheFile) {
367
+ const map = new Map();
368
+ if (!fs.existsSync(cacheFile)) return map;
369
+ const lines = fs.readFileSync(cacheFile, 'utf8').split('\n');
370
+ for (const line of lines) {
371
+ if (!line.trim()) continue;
372
+ try {
373
+ const obj = JSON.parse(line);
374
+ if (obj.domain) map.set(obj.domain, obj);
375
+ } catch {
376
+ // ignore bad lines
377
+ }
378
+ }
379
+ return map;
380
+ }
381
+
382
+ function appendToCache(cacheFile, obj) {
383
+ fs.appendFileSync(cacheFile, JSON.stringify(obj) + '\n');
384
+ }
385
+
386
+ // ---------- OUTPUT ----------
387
+
388
+ function writeOutput(results, opts) {
389
+ const out = opts.output;
390
+ const fmt = opts.format;
391
+
392
+ if (fmt === 'txt') {
393
+ const lines = results.map(r => r.domain);
394
+ fs.writeFileSync(out, lines.join('\n') + '\n', 'utf8');
395
+ console.log(`āœ… Saved ${results.length} domains to ${out} (txt).`);
396
+ return;
397
+ }
398
+
399
+ if (fmt === 'json') {
400
+ fs.writeFileSync(out, JSON.stringify(results, null, 2), 'utf8');
401
+ console.log(`āœ… Saved ${results.length} domains to ${out} (json).`);
402
+ return;
403
+ }
404
+
405
+ if (fmt === 'jsonl') {
406
+ const lines = results.map(r => JSON.stringify(r));
407
+ fs.writeFileSync(out, lines.join('\n') + '\n', 'utf8');
408
+ console.log(`āœ… Saved ${results.length} domains to ${out} (jsonl).`);
409
+ return;
410
+ }
411
+
412
+ if (fmt === 'csv') {
413
+ const header = 'domain,tld,name,available,checkedAt,error\n';
414
+ const rows = results.map(r =>
415
+ `${r.domain},${r.tld},${r.name},${r.available},${r.checkedAt},${r.error || ''}`
416
+ );
417
+ fs.writeFileSync(out, header + rows.join('\n') + '\n', 'utf8');
418
+ console.log(`āœ… Saved ${results.length} domains to ${out} (csv).`);
419
+ return;
420
+ }
421
+
422
+ // fallback
423
+ const lines = results.map(r => r.domain);
424
+ fs.writeFileSync(out, lines.join('\n') + '\n', 'utf8');
425
+ console.log(`āœ… Saved ${results.length} domains to ${out} (txt fallback).`);
426
+ }
427
+
428
+ // ---------- MAIN RUN ----------
429
+
430
+ async function run() {
431
+ const opts = parseArgs();
432
+
433
+ if (!opts.pattern && !opts.regex) {
434
+ printHelp();
435
+ process.exit(1);
436
+ }
437
+
438
+ const filters = buildFilters(opts.filters);
439
+
440
+ let tlds;
441
+ if (opts.allTlds) tlds = IANA_TLDS;
442
+ else if (opts.premiumTlds) tlds = PREMIUM_TLDS;
443
+ else if (opts.tlds && opts.tlds.length) tlds = opts.tlds;
444
+ else tlds = ['com'];
445
+
446
+ let regex = null;
447
+ if (opts.regex) {
448
+ try {
449
+ regex = new RegExp(opts.regex);
450
+ } catch (err) {
451
+ console.error('Invalid regex:', err.message);
452
+ process.exit(1);
453
+ }
454
+ }
455
+
456
+ const cache = opts.useCache ? loadCache(opts.cacheFile) : new Map();
457
+
458
+ console.log(`šŸš€ Starting domain search`);
459
+ if (opts.pattern) console.log(` Pattern: ${opts.pattern}`);
460
+ if (regex) console.log(` Regex: ${opts.regex}`);
461
+ console.log(` TLDs: ${tlds.join(', ')}`);
462
+ console.log(` Concurrency: ${opts.concurrency}, Timeout: ${opts.timeout}ms`);
463
+ console.log(` Output: ${opts.output} (${opts.format})`);
464
+ if (opts.useCache) console.log(` Cache: ${opts.cacheFile} (${cache.size} entries loaded)`);
465
+
466
+ setupInteractiveControls();
467
+
468
+ const iterator = regex
469
+ ? generateAllDomainsForRegex(opts.maxLength, tlds)
470
+ : expandPatternWithTlds(opts.pattern, tlds);
471
+
472
+ const availableResults = [];
473
+ const tasks = [];
474
+ let active = 0;
475
+ let checked = 0;
476
+ let totalCandidates = 0;
477
+ const startTime = Date.now();
478
+
479
+ async function scheduleNext() {
480
+ if (quitting) return;
481
+ while (!paused && active < opts.concurrency) {
482
+ const next = iterator.next();
483
+ if (next.done) break;
484
+ const domain = next.value;
485
+ totalCandidates++;
486
+
487
+ if (!isValidDomain(domain)) continue;
488
+ if (!passesFilters(domain, filters)) continue;
489
+
490
+ if (opts.useCache && cache.has(domain)) {
491
+ continue;
492
+ }
493
+
494
+ active++;
495
+ const task = (async () => {
496
+ const res = await checkDomain(domain, opts.timeout);
497
+ checked++;
498
+
499
+ const [name, tld] = (() => {
500
+ const parts = domain.split('.');
501
+ const tld = parts.pop().toLowerCase();
502
+ const name = parts.join('.').toLowerCase();
503
+ return [name, tld];
504
+ })();
505
+
506
+ const record = {
507
+ domain,
508
+ name,
509
+ tld,
510
+ available: res.available,
511
+ checkedAt: new Date().toISOString(),
512
+ error: res.error
513
+ };
514
+
515
+ if (opts.useCache) {
516
+ cache.set(domain, record);
517
+ appendToCache(opts.cacheFile, record);
518
+ }
519
+
520
+ if (res.available === true) {
521
+ availableResults.push(record);
522
+ process.stdout.write(
523
+ `\rChecked: ${checked.toLocaleString()} | Available: ${availableResults.length.toLocaleString()} `
524
+ );
525
+ }
526
+ })().finally(() => {
527
+ active--;
528
+ });
529
+
530
+ tasks.push(task);
531
+ }
532
+ }
533
+
534
+ while (true) {
535
+ if (quitting) break;
536
+ if (!paused) {
537
+ await scheduleNext();
538
+ }
539
+ if (active === 0 && iterator.next().done) {
540
+ break;
541
+ }
542
+ await sleep(100);
543
+ }
544
+
545
+ await Promise.all(tasks);
546
+
547
+ const duration = ((Date.now() - startTime) / 1000).toFixed(1);
548
+ console.log(`\nā± Done in ${duration}s. Checked ${checked.toLocaleString()} domains.`);
549
+ console.log(`āœ… Available: ${availableResults.length.toLocaleString()}`);
550
+
551
+ const sorted = sortResults(availableResults, opts.sort);
552
+ writeOutput(sorted, opts);
553
+ }
554
+
555
+ run().catch(err => {
556
+ console.error('Fatal error:', err);
557
+ process.exit(1);
558
+ });
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "wildcard-domain-finder-plus",
3
+ "version": "1.0.0",
4
+ "description": "Advanced wildcard and regex-based domain availability scanner with streaming generation, filtering, sorting, and caching.",
5
+ "main": "app.js",
6
+ "bin": {
7
+ "wildcard-domain-finder-plus": "app.js"
8
+ },
9
+ "scripts": {
10
+ "test": "echo \"Error: no test specified\" && exit 1"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/nbcr/wildcard-domain-finder-plus.git"
15
+ },
16
+ "author": "nbcr",
17
+ "license": "ISC",
18
+ "bugs": {
19
+ "url": "https://github.com/nbcr/wildcard-domain-finder-plus/issues"
20
+ },
21
+ "homepage": "https://github.com/nbcr/wildcard-domain-finder-plus#readme",
22
+ "keywords": [
23
+ "domain",
24
+ "dns",
25
+ "wildcard",
26
+ "regex",
27
+ "tld",
28
+ "availability",
29
+ "scanner",
30
+ "cli",
31
+ "domain-finder"
32
+ ]
33
+ }