domain-search-mcp 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.
Files changed (151) hide show
  1. package/.env.example +52 -0
  2. package/Dockerfile +15 -0
  3. package/LICENSE +21 -0
  4. package/README.md +426 -0
  5. package/SECURITY.md +252 -0
  6. package/dist/config.d.ts +25 -0
  7. package/dist/config.d.ts.map +1 -0
  8. package/dist/config.js +117 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/fallbacks/index.d.ts +6 -0
  11. package/dist/fallbacks/index.d.ts.map +1 -0
  12. package/dist/fallbacks/index.js +14 -0
  13. package/dist/fallbacks/index.js.map +1 -0
  14. package/dist/fallbacks/rdap.d.ts +18 -0
  15. package/dist/fallbacks/rdap.d.ts.map +1 -0
  16. package/dist/fallbacks/rdap.js +339 -0
  17. package/dist/fallbacks/rdap.js.map +1 -0
  18. package/dist/fallbacks/whois.d.ts +27 -0
  19. package/dist/fallbacks/whois.d.ts.map +1 -0
  20. package/dist/fallbacks/whois.js +219 -0
  21. package/dist/fallbacks/whois.js.map +1 -0
  22. package/dist/registrars/base.d.ts +89 -0
  23. package/dist/registrars/base.d.ts.map +1 -0
  24. package/dist/registrars/base.js +203 -0
  25. package/dist/registrars/base.js.map +1 -0
  26. package/dist/registrars/index.d.ts +7 -0
  27. package/dist/registrars/index.d.ts.map +1 -0
  28. package/dist/registrars/index.js +15 -0
  29. package/dist/registrars/index.js.map +1 -0
  30. package/dist/registrars/namecheap.d.ts +69 -0
  31. package/dist/registrars/namecheap.d.ts.map +1 -0
  32. package/dist/registrars/namecheap.js +307 -0
  33. package/dist/registrars/namecheap.js.map +1 -0
  34. package/dist/registrars/porkbun.d.ts +63 -0
  35. package/dist/registrars/porkbun.d.ts.map +1 -0
  36. package/dist/registrars/porkbun.js +299 -0
  37. package/dist/registrars/porkbun.js.map +1 -0
  38. package/dist/server.d.ts +19 -0
  39. package/dist/server.d.ts.map +1 -0
  40. package/dist/server.js +209 -0
  41. package/dist/server.js.map +1 -0
  42. package/dist/services/domain-search.d.ts +40 -0
  43. package/dist/services/domain-search.d.ts.map +1 -0
  44. package/dist/services/domain-search.js +438 -0
  45. package/dist/services/domain-search.js.map +1 -0
  46. package/dist/services/index.d.ts +5 -0
  47. package/dist/services/index.d.ts.map +1 -0
  48. package/dist/services/index.js +11 -0
  49. package/dist/services/index.js.map +1 -0
  50. package/dist/tools/bulk_search.d.ts +72 -0
  51. package/dist/tools/bulk_search.d.ts.map +1 -0
  52. package/dist/tools/bulk_search.js +108 -0
  53. package/dist/tools/bulk_search.js.map +1 -0
  54. package/dist/tools/check_socials.d.ts +71 -0
  55. package/dist/tools/check_socials.d.ts.map +1 -0
  56. package/dist/tools/check_socials.js +357 -0
  57. package/dist/tools/check_socials.js.map +1 -0
  58. package/dist/tools/compare_registrars.d.ts +80 -0
  59. package/dist/tools/compare_registrars.d.ts.map +1 -0
  60. package/dist/tools/compare_registrars.js +116 -0
  61. package/dist/tools/compare_registrars.js.map +1 -0
  62. package/dist/tools/index.d.ts +10 -0
  63. package/dist/tools/index.d.ts.map +1 -0
  64. package/dist/tools/index.js +31 -0
  65. package/dist/tools/index.js.map +1 -0
  66. package/dist/tools/search_domain.d.ts +61 -0
  67. package/dist/tools/search_domain.d.ts.map +1 -0
  68. package/dist/tools/search_domain.js +81 -0
  69. package/dist/tools/search_domain.js.map +1 -0
  70. package/dist/tools/suggest_domains.d.ts +82 -0
  71. package/dist/tools/suggest_domains.d.ts.map +1 -0
  72. package/dist/tools/suggest_domains.js +227 -0
  73. package/dist/tools/suggest_domains.js.map +1 -0
  74. package/dist/tools/tld_info.d.ts +56 -0
  75. package/dist/tools/tld_info.d.ts.map +1 -0
  76. package/dist/tools/tld_info.js +273 -0
  77. package/dist/tools/tld_info.js.map +1 -0
  78. package/dist/types.d.ts +193 -0
  79. package/dist/types.d.ts.map +1 -0
  80. package/dist/types.js +9 -0
  81. package/dist/types.js.map +1 -0
  82. package/dist/utils/cache.d.ts +81 -0
  83. package/dist/utils/cache.d.ts.map +1 -0
  84. package/dist/utils/cache.js +192 -0
  85. package/dist/utils/cache.js.map +1 -0
  86. package/dist/utils/errors.d.ts +87 -0
  87. package/dist/utils/errors.d.ts.map +1 -0
  88. package/dist/utils/errors.js +191 -0
  89. package/dist/utils/errors.js.map +1 -0
  90. package/dist/utils/index.d.ts +8 -0
  91. package/dist/utils/index.d.ts.map +1 -0
  92. package/dist/utils/index.js +24 -0
  93. package/dist/utils/index.js.map +1 -0
  94. package/dist/utils/logger.d.ts +27 -0
  95. package/dist/utils/logger.d.ts.map +1 -0
  96. package/dist/utils/logger.js +132 -0
  97. package/dist/utils/logger.js.map +1 -0
  98. package/dist/utils/premium-analyzer.d.ts +33 -0
  99. package/dist/utils/premium-analyzer.d.ts.map +1 -0
  100. package/dist/utils/premium-analyzer.js +273 -0
  101. package/dist/utils/premium-analyzer.js.map +1 -0
  102. package/dist/utils/validators.d.ts +53 -0
  103. package/dist/utils/validators.d.ts.map +1 -0
  104. package/dist/utils/validators.js +159 -0
  105. package/dist/utils/validators.js.map +1 -0
  106. package/docs/marketing/devto-post.md +135 -0
  107. package/docs/marketing/hackernews.md +42 -0
  108. package/docs/marketing/producthunt.md +109 -0
  109. package/docs/marketing/reddit-post.md +59 -0
  110. package/docs/marketing/twitter-thread.md +105 -0
  111. package/examples/bulk-search-50-domains.ts +131 -0
  112. package/examples/cli-interactive.ts +280 -0
  113. package/examples/compare-registrars.ts +78 -0
  114. package/examples/search-single-domain.ts +54 -0
  115. package/examples/suggest-names.ts +110 -0
  116. package/glama.json +6 -0
  117. package/jest.config.js +35 -0
  118. package/package.json +62 -0
  119. package/smithery.yaml +36 -0
  120. package/src/config.ts +121 -0
  121. package/src/fallbacks/index.ts +6 -0
  122. package/src/fallbacks/rdap.ts +407 -0
  123. package/src/fallbacks/whois.ts +250 -0
  124. package/src/registrars/base.ts +264 -0
  125. package/src/registrars/index.ts +7 -0
  126. package/src/registrars/namecheap.ts +378 -0
  127. package/src/registrars/porkbun.ts +380 -0
  128. package/src/server.ts +276 -0
  129. package/src/services/domain-search.ts +567 -0
  130. package/src/services/index.ts +9 -0
  131. package/src/tools/bulk_search.ts +142 -0
  132. package/src/tools/check_socials.ts +467 -0
  133. package/src/tools/compare_registrars.ts +162 -0
  134. package/src/tools/index.ts +45 -0
  135. package/src/tools/search_domain.ts +93 -0
  136. package/src/tools/suggest_domains.ts +284 -0
  137. package/src/tools/tld_info.ts +294 -0
  138. package/src/types.ts +289 -0
  139. package/src/utils/cache.ts +238 -0
  140. package/src/utils/errors.ts +262 -0
  141. package/src/utils/index.ts +8 -0
  142. package/src/utils/logger.ts +162 -0
  143. package/src/utils/premium-analyzer.ts +303 -0
  144. package/src/utils/validators.ts +193 -0
  145. package/tests/premium-analyzer.test.ts +310 -0
  146. package/tests/unit/cache.test.ts +123 -0
  147. package/tests/unit/errors.test.ts +190 -0
  148. package/tests/unit/tld-info.test.ts +62 -0
  149. package/tests/unit/tools.test.ts +200 -0
  150. package/tests/unit/validators.test.ts +146 -0
  151. package/tsconfig.json +25 -0
@@ -0,0 +1,438 @@
1
+ "use strict";
2
+ /**
3
+ * Domain Search Service.
4
+ *
5
+ * Orchestrates domain availability checks across multiple sources:
6
+ * 1. Porkbun (primary, if configured)
7
+ * 2. Namecheap (secondary, if configured)
8
+ * 3. RDAP (fallback, always available)
9
+ * 4. WHOIS (last resort, always available)
10
+ *
11
+ * Handles:
12
+ * - Smart source selection based on availability and configuration
13
+ * - Graceful fallback on failures
14
+ * - Caching for performance
15
+ * - Insights generation for vibecoding UX
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.searchDomain = searchDomain;
19
+ exports.bulkSearchDomains = bulkSearchDomains;
20
+ exports.compareRegistrars = compareRegistrars;
21
+ const config_js_1 = require("../config.js");
22
+ const logger_js_1 = require("../utils/logger.js");
23
+ const errors_js_1 = require("../utils/errors.js");
24
+ const validators_js_1 = require("../utils/validators.js");
25
+ const cache_js_1 = require("../utils/cache.js");
26
+ const index_js_1 = require("../registrars/index.js");
27
+ const rdap_js_1 = require("../fallbacks/rdap.js");
28
+ const whois_js_1 = require("../fallbacks/whois.js");
29
+ const premium_analyzer_js_1 = require("../utils/premium-analyzer.js");
30
+ /**
31
+ * Search for domain availability across multiple TLDs.
32
+ */
33
+ async function searchDomain(domainName, tlds = ['com', 'io', 'dev'], preferredRegistrars) {
34
+ const startTime = Date.now();
35
+ const normalizedDomain = (0, validators_js_1.validateDomainName)(domainName);
36
+ const normalizedTlds = (0, validators_js_1.validateTlds)(tlds);
37
+ logger_js_1.logger.info('Domain search started', {
38
+ domain: normalizedDomain,
39
+ tlds: normalizedTlds,
40
+ });
41
+ // Search each TLD
42
+ const results = [];
43
+ const errors = [];
44
+ let fromCache = false;
45
+ // Run TLD checks in parallel
46
+ const promises = normalizedTlds.map(async (tld) => {
47
+ try {
48
+ const result = await searchSingleDomain(normalizedDomain, tld, preferredRegistrars);
49
+ if (result.fromCache)
50
+ fromCache = true;
51
+ return { success: true, tld, result: result.result };
52
+ }
53
+ catch (error) {
54
+ const wrapped = (0, errors_js_1.wrapError)(error);
55
+ return { success: false, tld, error: wrapped };
56
+ }
57
+ });
58
+ const outcomes = await Promise.all(promises);
59
+ for (const outcome of outcomes) {
60
+ if (outcome.success) {
61
+ results.push(outcome.result);
62
+ }
63
+ else {
64
+ errors.push(`${outcome.tld}: ${outcome.error.userMessage}`);
65
+ logger_js_1.logger.warn(`Failed to check .${outcome.tld}`, {
66
+ domain: normalizedDomain,
67
+ error: outcome.error.message,
68
+ });
69
+ }
70
+ }
71
+ // Generate insights and next steps
72
+ const insights = generateInsights(results, errors);
73
+ const nextSteps = generateNextSteps(results);
74
+ const duration = Date.now() - startTime;
75
+ logger_js_1.logger.info('Domain search completed', {
76
+ domain: normalizedDomain,
77
+ results_count: results.length,
78
+ errors_count: errors.length,
79
+ duration_ms: duration,
80
+ from_cache: fromCache,
81
+ });
82
+ return {
83
+ results,
84
+ insights,
85
+ next_steps: nextSteps,
86
+ from_cache: fromCache,
87
+ duration_ms: duration,
88
+ };
89
+ }
90
+ /**
91
+ * Search a single domain with fallback chain.
92
+ */
93
+ async function searchSingleDomain(domain, tld, preferredRegistrars) {
94
+ const fullDomain = (0, validators_js_1.buildDomain)(domain, tld);
95
+ const triedSources = [];
96
+ // Check cache first
97
+ for (const source of ['porkbun', 'namecheap', 'rdap', 'whois']) {
98
+ const cacheKey = (0, cache_js_1.domainCacheKey)(fullDomain, source);
99
+ const cached = cache_js_1.domainCache.get(cacheKey);
100
+ if (cached) {
101
+ logger_js_1.logger.debug('Cache hit', { domain: fullDomain, source });
102
+ return { result: cached, fromCache: true };
103
+ }
104
+ }
105
+ // Build source priority
106
+ const sources = buildSourcePriority(tld, preferredRegistrars);
107
+ // Try each source
108
+ for (const source of sources) {
109
+ triedSources.push(source);
110
+ try {
111
+ const result = await trySource(domain, tld, source);
112
+ if (result) {
113
+ // Calculate quality score
114
+ result.score = (0, premium_analyzer_js_1.calculateDomainScore)(result);
115
+ // Enhance premium_reason with analysis
116
+ if (result.premium && !result.premium_reason) {
117
+ const reasons = (0, premium_analyzer_js_1.analyzePremiumReason)(result.domain);
118
+ result.premium_reason = reasons.length > 0
119
+ ? reasons.join(', ')
120
+ : 'Premium domain';
121
+ }
122
+ // Cache the result
123
+ const cacheKey = (0, cache_js_1.domainCacheKey)(fullDomain, source);
124
+ cache_js_1.domainCache.set(cacheKey, result);
125
+ return { result, fromCache: false };
126
+ }
127
+ }
128
+ catch (error) {
129
+ const wrapped = (0, errors_js_1.wrapError)(error);
130
+ logger_js_1.logger.debug(`Source ${source} failed, trying next`, {
131
+ domain: fullDomain,
132
+ error: wrapped.message,
133
+ retryable: wrapped.retryable,
134
+ });
135
+ // If it's not retryable, skip similar sources
136
+ if (!wrapped.retryable && source === 'porkbun') {
137
+ // Skip other registrar APIs, go straight to fallbacks
138
+ continue;
139
+ }
140
+ }
141
+ }
142
+ // All sources failed
143
+ throw new errors_js_1.NoSourceAvailableError(fullDomain, triedSources);
144
+ }
145
+ /**
146
+ * Build the priority list of sources to try.
147
+ */
148
+ function buildSourcePriority(tld, preferredRegistrars) {
149
+ const sources = [];
150
+ // Add preferred registrars first
151
+ if (preferredRegistrars && preferredRegistrars.length > 0) {
152
+ for (const registrar of preferredRegistrars) {
153
+ if (registrar === 'porkbun' && config_js_1.config.porkbun.enabled) {
154
+ sources.push('porkbun');
155
+ }
156
+ else if (registrar === 'namecheap' && config_js_1.config.namecheap.enabled) {
157
+ sources.push('namecheap');
158
+ }
159
+ }
160
+ }
161
+ else {
162
+ // Default priority: Porkbun first (better API), then Namecheap
163
+ if (config_js_1.config.porkbun.enabled)
164
+ sources.push('porkbun');
165
+ if (config_js_1.config.namecheap.enabled)
166
+ sources.push('namecheap');
167
+ }
168
+ // Always add fallbacks
169
+ if ((0, rdap_js_1.isRdapAvailable)(tld))
170
+ sources.push('rdap');
171
+ if ((0, whois_js_1.isWhoisAvailable)(tld))
172
+ sources.push('whois');
173
+ // If no registrar APIs, RDAP should be first
174
+ if (sources.length === 0) {
175
+ sources.push('rdap', 'whois');
176
+ }
177
+ return sources;
178
+ }
179
+ /**
180
+ * Try a specific source for domain lookup.
181
+ */
182
+ async function trySource(domain, tld, source) {
183
+ switch (source) {
184
+ case 'porkbun':
185
+ return index_js_1.porkbunAdapter.search(domain, tld);
186
+ case 'namecheap':
187
+ return index_js_1.namecheapAdapter.search(domain, tld);
188
+ case 'rdap':
189
+ return (0, rdap_js_1.checkRdap)(domain, tld);
190
+ case 'whois':
191
+ return (0, whois_js_1.checkWhois)(domain, tld);
192
+ default:
193
+ logger_js_1.logger.warn(`Unknown source: ${source}`);
194
+ return null;
195
+ }
196
+ }
197
+ /**
198
+ * Generate human-readable insights about the results.
199
+ */
200
+ function generateInsights(results, errors) {
201
+ const insights = [];
202
+ // Available domains summary
203
+ const available = results.filter((r) => r.available);
204
+ const taken = results.filter((r) => !r.available);
205
+ if (available.length > 0) {
206
+ const cheapest = available.reduce((min, r) => r.price_first_year !== null &&
207
+ (min === null || r.price_first_year < min.price_first_year)
208
+ ? r
209
+ : min, null);
210
+ if (cheapest && cheapest.price_first_year !== null) {
211
+ insights.push(`✅ ${available.length} domain${available.length > 1 ? 's' : ''} available! Best price: ${cheapest.domain} at $${cheapest.price_first_year}/year (${cheapest.registrar})`);
212
+ }
213
+ else {
214
+ insights.push(`✅ ${available.length} domain${available.length > 1 ? 's' : ''} available!`);
215
+ }
216
+ }
217
+ if (taken.length > 0) {
218
+ insights.push(`❌ ${taken.length} domain${taken.length > 1 ? 's' : ''} already taken`);
219
+ }
220
+ // TLD-specific advice
221
+ for (const result of results) {
222
+ if (result.available) {
223
+ const tld = result.domain.split('.').pop();
224
+ const advice = getTldAdvice(tld, result);
225
+ if (advice) {
226
+ insights.push(advice);
227
+ }
228
+ }
229
+ }
230
+ // Premium insights (enhanced with analyzer)
231
+ const premiums = results.filter((r) => r.premium && r.available);
232
+ if (premiums.length > 0) {
233
+ // Add detailed insight for each premium domain
234
+ for (const premium of premiums) {
235
+ const premiumInsight = (0, premium_analyzer_js_1.generatePremiumInsight)(premium);
236
+ if (premiumInsight) {
237
+ insights.push(premiumInsight);
238
+ }
239
+ }
240
+ // Add summary insights (alternatives, pricing context)
241
+ const summaryInsights = (0, premium_analyzer_js_1.generatePremiumSummary)(results);
242
+ insights.push(...summaryInsights);
243
+ }
244
+ // Privacy insight
245
+ const withPrivacy = results.filter((r) => r.available && r.privacy_included);
246
+ if (withPrivacy.length > 0) {
247
+ insights.push(`🔒 ${withPrivacy.length} option${withPrivacy.length > 1 ? 's' : ''} include free WHOIS privacy`);
248
+ }
249
+ // Expiration insights for taken domains
250
+ const takenWithExpiration = results.filter((r) => !r.available && r.expires_at && r.days_until_expiration !== undefined);
251
+ for (const domain of takenWithExpiration) {
252
+ if (domain.days_until_expiration !== undefined) {
253
+ if (domain.days_until_expiration <= 0) {
254
+ insights.push(`🕐 ${domain.domain} has EXPIRED — may become available soon!`);
255
+ }
256
+ else if (domain.days_until_expiration <= 30) {
257
+ insights.push(`🕐 ${domain.domain} expires in ${domain.days_until_expiration} days — watch for availability`);
258
+ }
259
+ else if (domain.days_until_expiration <= 90) {
260
+ insights.push(`📅 ${domain.domain} expires in ${Math.round(domain.days_until_expiration / 30)} months`);
261
+ }
262
+ }
263
+ }
264
+ // Error summary
265
+ if (errors.length > 0) {
266
+ insights.push(`⚠️ Could not check some TLDs: ${errors.join(', ')}`);
267
+ }
268
+ return insights;
269
+ }
270
+ /**
271
+ * Get TLD-specific advice.
272
+ */
273
+ function getTldAdvice(tld, result) {
274
+ const advice = {
275
+ com: '💡 .com is the classic, universal choice — trusted worldwide',
276
+ io: '💡 .io is popular with tech startups and SaaS products',
277
+ dev: '💡 .dev signals developer/tech credibility (requires HTTPS)',
278
+ app: '💡 .app is perfect for mobile/web applications (requires HTTPS)',
279
+ co: '💡 .co is a popular alternative to .com for companies',
280
+ ai: '💡 .ai is trending for AI/ML projects',
281
+ sh: '💡 .sh is popular with developers (shell scripts!)',
282
+ };
283
+ return advice[tld] || null;
284
+ }
285
+ /**
286
+ * Generate suggested next steps.
287
+ */
288
+ function generateNextSteps(results) {
289
+ const nextSteps = [];
290
+ const available = results.filter((r) => r.available);
291
+ const taken = results.filter((r) => !r.available);
292
+ const premiumAvailable = available.filter((r) => r.premium);
293
+ const nonPremiumAvailable = available.filter((r) => !r.premium);
294
+ if (available.length > 0) {
295
+ // Check other TLDs
296
+ const checkedTlds = new Set(results.map((r) => r.domain.split('.').pop()));
297
+ const suggestedTlds = ['com', 'io', 'dev', 'app', 'co', 'ai'].filter((t) => !checkedTlds.has(t));
298
+ if (suggestedTlds.length > 0) {
299
+ nextSteps.push(`Check other TLDs: ${suggestedTlds.slice(0, 3).join(', ')}`);
300
+ }
301
+ // Premium-specific advice
302
+ if (premiumAvailable.length > 0 && nonPremiumAvailable.length === 0) {
303
+ // All available domains are premium
304
+ const firstPremium = premiumAvailable[0];
305
+ const alternatives = (0, premium_analyzer_js_1.suggestPremiumAlternatives)(firstPremium.domain);
306
+ if (alternatives.length > 0) {
307
+ nextSteps.push(`Consider alternatives to avoid premium pricing: ${alternatives.join(', ')}`);
308
+ }
309
+ }
310
+ // Compare registrars
311
+ if (available.length === 1 && !available[0].price_first_year) {
312
+ nextSteps.push('Compare prices across registrars for better deals');
313
+ }
314
+ // Check social handles
315
+ nextSteps.push('Check social handle availability (GitHub, X, npm)');
316
+ }
317
+ if (taken.length > 0 && available.length === 0) {
318
+ nextSteps.push('Try name variations (add prefixes, suffixes, or hyphens)');
319
+ nextSteps.push('Check different TLDs for availability');
320
+ }
321
+ if (available.length > 0) {
322
+ // Prefer non-premium for registration suggestion
323
+ const best = nonPremiumAvailable.length > 0
324
+ ? nonPremiumAvailable.reduce((a, b) => (a.price_first_year || Infinity) < (b.price_first_year || Infinity) ? a : b)
325
+ : available[0];
326
+ if (best.premium && best.price_first_year && best.price_first_year > 100) {
327
+ nextSteps.push(`${best.domain} is premium ($${best.price_first_year}) — consider if it fits your budget`);
328
+ }
329
+ else {
330
+ nextSteps.push(`Register ${best.domain} at ${best.registrar} to secure it`);
331
+ }
332
+ }
333
+ return nextSteps;
334
+ }
335
+ /**
336
+ * Bulk search for multiple domains.
337
+ */
338
+ async function bulkSearchDomains(domains, tld = 'com', registrar, maxConcurrent = 5) {
339
+ const startTime = Date.now();
340
+ const results = [];
341
+ logger_js_1.logger.info('Bulk search started', {
342
+ count: domains.length,
343
+ tld,
344
+ registrar,
345
+ });
346
+ // Process in batches
347
+ for (let i = 0; i < domains.length; i += maxConcurrent) {
348
+ const batch = domains.slice(i, i + maxConcurrent);
349
+ const batchPromises = batch.map(async (domain) => {
350
+ try {
351
+ const normalizedDomain = (0, validators_js_1.validateDomainName)(domain);
352
+ const { result } = await searchSingleDomain(normalizedDomain, tld, registrar ? [registrar] : undefined);
353
+ return result;
354
+ }
355
+ catch (error) {
356
+ logger_js_1.logger.warn(`Failed to check ${domain}.${tld}`, {
357
+ error: error instanceof Error ? error.message : String(error),
358
+ });
359
+ return null;
360
+ }
361
+ });
362
+ const batchResults = await Promise.all(batchPromises);
363
+ for (const result of batchResults) {
364
+ if (result)
365
+ results.push(result);
366
+ }
367
+ }
368
+ const duration = Date.now() - startTime;
369
+ logger_js_1.logger.info('Bulk search completed', {
370
+ checked: domains.length,
371
+ results: results.length,
372
+ duration_ms: duration,
373
+ });
374
+ return results;
375
+ }
376
+ /**
377
+ * Compare pricing across registrars.
378
+ */
379
+ async function compareRegistrars(domain, tld, registrars = ['porkbun', 'namecheap']) {
380
+ const normalizedDomain = (0, validators_js_1.validateDomainName)(domain);
381
+ const comparisons = [];
382
+ // Check each registrar
383
+ for (const registrar of registrars) {
384
+ try {
385
+ const { result } = await searchSingleDomain(normalizedDomain, tld, [
386
+ registrar,
387
+ ]);
388
+ comparisons.push(result);
389
+ }
390
+ catch (error) {
391
+ logger_js_1.logger.warn(`Registrar ${registrar} comparison failed`, {
392
+ domain: `${normalizedDomain}.${tld}`,
393
+ error: error instanceof Error ? error.message : String(error),
394
+ });
395
+ }
396
+ }
397
+ // Find best prices
398
+ let bestFirstYear = null;
399
+ let bestRenewal = null;
400
+ for (const result of comparisons) {
401
+ if (result.available && result.price_first_year !== null) {
402
+ if (!bestFirstYear || result.price_first_year < bestFirstYear.price) {
403
+ bestFirstYear = {
404
+ registrar: result.registrar,
405
+ price: result.price_first_year,
406
+ };
407
+ }
408
+ }
409
+ if (result.available && result.price_renewal !== null) {
410
+ if (!bestRenewal || result.price_renewal < bestRenewal.price) {
411
+ bestRenewal = {
412
+ registrar: result.registrar,
413
+ price: result.price_renewal,
414
+ };
415
+ }
416
+ }
417
+ }
418
+ // Generate recommendation
419
+ let recommendation = 'Could not compare registrars';
420
+ if (bestFirstYear && bestRenewal) {
421
+ if (bestFirstYear.registrar === bestRenewal.registrar) {
422
+ recommendation = `${bestFirstYear.registrar} offers the best price for both first year ($${bestFirstYear.price}) and renewal ($${bestRenewal.price})`;
423
+ }
424
+ else {
425
+ recommendation = `${bestFirstYear.registrar} for first year ($${bestFirstYear.price}), ${bestRenewal.registrar} for renewal ($${bestRenewal.price})`;
426
+ }
427
+ }
428
+ else if (bestFirstYear) {
429
+ recommendation = `${bestFirstYear.registrar} has the best first year price: $${bestFirstYear.price}`;
430
+ }
431
+ return {
432
+ comparisons,
433
+ best_first_year: bestFirstYear,
434
+ best_renewal: bestRenewal,
435
+ recommendation,
436
+ };
437
+ }
438
+ //# sourceMappingURL=domain-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain-search.js","sourceRoot":"","sources":["../../src/services/domain-search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Service Exports.
3
+ */
4
+ export { searchDomain, bulkSearchDomains, compareRegistrars, } from './domain-search.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ /**
3
+ * Service Exports.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.compareRegistrars = exports.bulkSearchDomains = exports.searchDomain = void 0;
7
+ var domain_search_js_1 = require("./domain-search.js");
8
+ Object.defineProperty(exports, "searchDomain", { enumerable: true, get: function () { return domain_search_js_1.searchDomain; } });
9
+ Object.defineProperty(exports, "bulkSearchDomains", { enumerable: true, get: function () { return domain_search_js_1.bulkSearchDomains; } });
10
+ Object.defineProperty(exports, "compareRegistrars", { enumerable: true, get: function () { return domain_search_js_1.compareRegistrars; } });
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,uDAI4B;AAH1B,gHAAA,YAAY,OAAA;AACZ,qHAAA,iBAAiB,OAAA;AACjB,qHAAA,iBAAiB,OAAA"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * bulk_search Tool - Search Multiple Domains.
3
+ *
4
+ * Efficiently check availability for many domain names at once.
5
+ * Uses concurrent requests with rate limiting.
6
+ */
7
+ import { z } from 'zod';
8
+ import type { DomainResult } from '../types.js';
9
+ /**
10
+ * Input schema for bulk_search.
11
+ */
12
+ export declare const bulkSearchSchema: z.ZodObject<{
13
+ domains: z.ZodArray<z.ZodString, "many">;
14
+ tld: z.ZodDefault<z.ZodOptional<z.ZodString>>;
15
+ registrar: z.ZodOptional<z.ZodString>;
16
+ }, "strip", z.ZodTypeAny, {
17
+ tld: string;
18
+ domains: string[];
19
+ registrar?: string | undefined;
20
+ }, {
21
+ domains: string[];
22
+ registrar?: string | undefined;
23
+ tld?: string | undefined;
24
+ }>;
25
+ export type BulkSearchInput = z.infer<typeof bulkSearchSchema>;
26
+ /**
27
+ * Tool definition for MCP.
28
+ */
29
+ export declare const bulkSearchTool: {
30
+ name: string;
31
+ description: string;
32
+ inputSchema: {
33
+ type: string;
34
+ properties: {
35
+ domains: {
36
+ type: string;
37
+ items: {
38
+ type: string;
39
+ };
40
+ description: string;
41
+ };
42
+ tld: {
43
+ type: string;
44
+ description: string;
45
+ };
46
+ registrar: {
47
+ type: string;
48
+ description: string;
49
+ };
50
+ };
51
+ required: string[];
52
+ };
53
+ };
54
+ /**
55
+ * Response format for bulk search.
56
+ */
57
+ interface BulkSearchResponse {
58
+ results: DomainResult[];
59
+ summary: {
60
+ total: number;
61
+ available: number;
62
+ taken: number;
63
+ errors: number;
64
+ };
65
+ insights: string[];
66
+ }
67
+ /**
68
+ * Execute the bulk_search tool.
69
+ */
70
+ export declare function executeBulkSearch(input: BulkSearchInput): Promise<BulkSearchResponse>;
71
+ export {};
72
+ //# sourceMappingURL=bulk_search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bulk_search.d.ts","sourceRoot":"","sources":["../../src/tools/bulk_search.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIhD;;GAEG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;EAmB3B,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE/D;;GAEG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;CAkC1B,CAAC;AAEF;;GAEG;AACH,UAAU,kBAAkB;IAC1B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,kBAAkB,CAAC,CA6C7B"}
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ /**
3
+ * bulk_search Tool - Search Multiple Domains.
4
+ *
5
+ * Efficiently check availability for many domain names at once.
6
+ * Uses concurrent requests with rate limiting.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.bulkSearchTool = exports.bulkSearchSchema = void 0;
10
+ exports.executeBulkSearch = executeBulkSearch;
11
+ const zod_1 = require("zod");
12
+ const domain_search_js_1 = require("../services/domain-search.js");
13
+ const errors_js_1 = require("../utils/errors.js");
14
+ /**
15
+ * Input schema for bulk_search.
16
+ */
17
+ exports.bulkSearchSchema = zod_1.z.object({
18
+ domains: zod_1.z
19
+ .array(zod_1.z.string())
20
+ .min(1)
21
+ .max(100)
22
+ .describe("List of domain names to check (e.g., ['vibecoding', 'myapp', 'coolstartup']). Max 100 domains."),
23
+ tld: zod_1.z
24
+ .string()
25
+ .optional()
26
+ .default('com')
27
+ .describe("Single TLD to check for all domains (e.g., 'com'). Defaults to 'com'."),
28
+ registrar: zod_1.z
29
+ .string()
30
+ .optional()
31
+ .describe("Optional: specific registrar to use (e.g., 'porkbun'). Leave empty for fastest source."),
32
+ });
33
+ /**
34
+ * Tool definition for MCP.
35
+ */
36
+ exports.bulkSearchTool = {
37
+ name: 'bulk_search',
38
+ description: `Check availability for multiple domain names at once.
39
+
40
+ Efficiently searches up to 100 domains in parallel with rate limiting.
41
+ Use a single TLD for best performance.
42
+
43
+ Returns:
44
+ - Availability status for each domain
45
+ - Pricing where available
46
+ - Summary statistics
47
+
48
+ Example:
49
+ - bulk_search(["vibecoding", "myapp", "coolstartup"], "io")`,
50
+ inputSchema: {
51
+ type: 'object',
52
+ properties: {
53
+ domains: {
54
+ type: 'array',
55
+ items: { type: 'string' },
56
+ description: "List of domain names to check. Don't include extensions. Max 100.",
57
+ },
58
+ tld: {
59
+ type: 'string',
60
+ description: "TLD to check for all domains (e.g., 'com'). Defaults to 'com'.",
61
+ },
62
+ registrar: {
63
+ type: 'string',
64
+ description: "Optional: specific registrar to use.",
65
+ },
66
+ },
67
+ required: ['domains'],
68
+ },
69
+ };
70
+ /**
71
+ * Execute the bulk_search tool.
72
+ */
73
+ async function executeBulkSearch(input) {
74
+ try {
75
+ const { domains, tld, registrar } = exports.bulkSearchSchema.parse(input);
76
+ const results = await (0, domain_search_js_1.bulkSearchDomains)(domains, tld, registrar);
77
+ const available = results.filter((r) => r.available);
78
+ const taken = results.filter((r) => !r.available);
79
+ const insights = [];
80
+ if (available.length > 0) {
81
+ insights.push(`✅ ${available.length} of ${domains.length} domains available`);
82
+ const cheapest = available
83
+ .filter((r) => r.price_first_year !== null)
84
+ .sort((a, b) => a.price_first_year - b.price_first_year)[0];
85
+ if (cheapest) {
86
+ insights.push(`💰 Best price: ${cheapest.domain} at $${cheapest.price_first_year}/year`);
87
+ }
88
+ }
89
+ else {
90
+ insights.push(`❌ All ${domains.length} domains are taken`);
91
+ insights.push('💡 Try different variations or alternative TLDs');
92
+ }
93
+ return {
94
+ results,
95
+ summary: {
96
+ total: domains.length,
97
+ available: available.length,
98
+ taken: taken.length,
99
+ errors: domains.length - results.length,
100
+ },
101
+ insights,
102
+ };
103
+ }
104
+ catch (error) {
105
+ throw (0, errors_js_1.wrapError)(error);
106
+ }
107
+ }
108
+ //# sourceMappingURL=bulk_search.js.map