domain-search-mcp 1.0.0 → 1.1.1

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.
@@ -0,0 +1,483 @@
1
+ /**
2
+ * Semantic Engine for AI-like Domain Suggestions.
3
+ *
4
+ * Provides intelligent domain name generation without external AI dependencies.
5
+ * Uses linguistic algorithms, word databases, and pattern matching.
6
+ */
7
+
8
+ /**
9
+ * Common word synonyms for domain name variations.
10
+ */
11
+ const SYNONYMS: Record<string, string[]> = {
12
+ // Tech terms
13
+ app: ['application', 'software', 'tool', 'platform', 'service'],
14
+ tech: ['technology', 'digital', 'cyber', 'smart', 'intelligent'],
15
+ code: ['coding', 'dev', 'developer', 'programming', 'software'],
16
+ dev: ['developer', 'development', 'code', 'build', 'create'],
17
+ web: ['online', 'internet', 'digital', 'cloud', 'net'],
18
+ cloud: ['sky', 'air', 'vapor', 'hosted', 'saas'],
19
+ data: ['info', 'analytics', 'metrics', 'insights', 'stats'],
20
+ ai: ['intelligent', 'smart', 'ml', 'brain', 'neural', 'cognitive'],
21
+ api: ['connect', 'integrate', 'link', 'bridge', 'hub'],
22
+
23
+ // Business terms
24
+ shop: ['store', 'market', 'mart', 'outlet', 'bazaar', 'emporium'],
25
+ buy: ['purchase', 'get', 'acquire', 'order', 'shop'],
26
+ sell: ['trade', 'market', 'vend', 'deal', 'offer'],
27
+ pay: ['payment', 'checkout', 'billing', 'invoice', 'finance'],
28
+ money: ['cash', 'funds', 'finance', 'capital', 'wealth'],
29
+ business: ['biz', 'enterprise', 'company', 'corp', 'venture'],
30
+
31
+ // Action terms
32
+ get: ['grab', 'fetch', 'obtain', 'acquire', 'access'],
33
+ find: ['search', 'discover', 'locate', 'seek', 'explore'],
34
+ make: ['create', 'build', 'craft', 'forge', 'generate'],
35
+ send: ['deliver', 'ship', 'dispatch', 'transmit', 'share'],
36
+ connect: ['link', 'join', 'unite', 'bridge', 'sync'],
37
+
38
+ // Descriptive terms
39
+ fast: ['quick', 'rapid', 'swift', 'speedy', 'instant', 'turbo'],
40
+ smart: ['clever', 'intelligent', 'bright', 'wise', 'genius'],
41
+ easy: ['simple', 'effortless', 'smooth', 'breeze', 'snap'],
42
+ free: ['gratis', 'open', 'libre', 'zero', 'complimentary'],
43
+ pro: ['professional', 'expert', 'premium', 'elite', 'master'],
44
+
45
+ // Size/Scale
46
+ big: ['large', 'mega', 'giant', 'huge', 'vast', 'grand'],
47
+ small: ['mini', 'tiny', 'micro', 'little', 'compact', 'lite'],
48
+
49
+ // Quality
50
+ best: ['top', 'prime', 'premier', 'superior', 'ultimate', 'optimal'],
51
+ good: ['great', 'awesome', 'excellent', 'superb', 'stellar'],
52
+ new: ['fresh', 'novel', 'modern', 'next', 'neo', 'latest'],
53
+
54
+ // Food & Lifestyle
55
+ food: ['eats', 'cuisine', 'kitchen', 'chef', 'meal', 'dish'],
56
+ coffee: ['cafe', 'brew', 'bean', 'roast', 'espresso', 'java'],
57
+ health: ['wellness', 'fit', 'vital', 'care', 'med', 'life'],
58
+ home: ['house', 'living', 'nest', 'haven', 'dwelling', 'abode'],
59
+
60
+ // Creative
61
+ design: ['creative', 'art', 'studio', 'craft', 'pixel', 'visual'],
62
+ media: ['content', 'channel', 'stream', 'broadcast', 'press'],
63
+ photo: ['image', 'pic', 'snap', 'shot', 'lens', 'capture'],
64
+ video: ['film', 'motion', 'clip', 'reel', 'stream', 'watch'],
65
+ music: ['audio', 'sound', 'tune', 'beat', 'melody', 'sonic'],
66
+
67
+ // Social
68
+ social: ['community', 'network', 'connect', 'share', 'together'],
69
+ team: ['crew', 'squad', 'group', 'tribe', 'collective', 'guild'],
70
+ chat: ['talk', 'message', 'speak', 'convo', 'discuss', 'voice'],
71
+
72
+ // Nature
73
+ green: ['eco', 'earth', 'nature', 'leaf', 'organic', 'bio'],
74
+ blue: ['ocean', 'sky', 'azure', 'aqua', 'marine', 'wave'],
75
+ sun: ['solar', 'bright', 'light', 'ray', 'shine', 'glow'],
76
+ star: ['stellar', 'astro', 'cosmic', 'nova', 'galaxy', 'orbit'],
77
+ };
78
+
79
+ /**
80
+ * Industry-specific vocabulary for contextual suggestions.
81
+ */
82
+ const INDUSTRY_TERMS: Record<string, string[]> = {
83
+ tech: [
84
+ 'stack', 'node', 'byte', 'pixel', 'logic', 'algo', 'kernel', 'cache',
85
+ 'sync', 'async', 'stream', 'flux', 'vector', 'tensor', 'quantum', 'cyber',
86
+ ],
87
+ startup: [
88
+ 'launch', 'venture', 'scale', 'pivot', 'disrupt', 'iterate', 'mvp', 'seed',
89
+ 'growth', 'unicorn', 'rocket', 'boost', 'accelerate', 'incubate',
90
+ ],
91
+ finance: [
92
+ 'capital', 'wealth', 'invest', 'fund', 'equity', 'asset', 'profit', 'yield',
93
+ 'trade', 'market', 'stock', 'bond', 'crypto', 'defi', 'fintech',
94
+ ],
95
+ health: [
96
+ 'vital', 'wellness', 'care', 'heal', 'med', 'clinic', 'therapy', 'fit',
97
+ 'nutrition', 'balance', 'mind', 'body', 'pulse', 'life', 'cure',
98
+ ],
99
+ food: [
100
+ 'kitchen', 'chef', 'bistro', 'grill', 'bake', 'fresh', 'organic', 'farm',
101
+ 'harvest', 'plate', 'taste', 'flavor', 'spice', 'savory', 'delish',
102
+ ],
103
+ creative: [
104
+ 'studio', 'canvas', 'palette', 'brush', 'ink', 'craft', 'artisan', 'muse',
105
+ 'vision', 'imagine', 'dream', 'inspire', 'spark', 'bloom', 'hue',
106
+ ],
107
+ ecommerce: [
108
+ 'cart', 'checkout', 'order', 'ship', 'deal', 'offer', 'sale', 'mart',
109
+ 'bazaar', 'outlet', 'depot', 'warehouse', 'supply', 'merchant',
110
+ ],
111
+ education: [
112
+ 'learn', 'teach', 'course', 'class', 'academy', 'scholar', 'study', 'tutor',
113
+ 'mentor', 'skill', 'knowledge', 'wisdom', 'genius', 'brain', 'mind',
114
+ ],
115
+ gaming: [
116
+ 'play', 'game', 'quest', 'level', 'arena', 'battle', 'guild', 'raid',
117
+ 'loot', 'spawn', 'realm', 'world', 'epic', 'legend', 'hero',
118
+ ],
119
+ social: [
120
+ 'connect', 'share', 'follow', 'friend', 'community', 'tribe', 'circle',
121
+ 'network', 'gather', 'meetup', 'hangout', 'squad', 'crew', 'vibe',
122
+ ],
123
+ };
124
+
125
+ /**
126
+ * Modern domain naming patterns and suffixes.
127
+ */
128
+ const MODERN_SUFFIXES = [
129
+ 'ly', 'ify', 'io', 'ai', 'app', 'hq', 'labs', 'hub', 'now', 'go',
130
+ 'up', 'me', 'co', 'so', 'to', 'it', 'os', 'js', 'py', 'dev',
131
+ 'cloud', 'base', 'stack', 'flow', 'space', 'zone', 'spot', 'pad',
132
+ 'box', 'kit', 'way', 'path', 'link', 'sync', 'dash', 'tap', 'pop',
133
+ ];
134
+
135
+ /**
136
+ * Modern domain naming prefixes.
137
+ */
138
+ const MODERN_PREFIXES = [
139
+ 'get', 'try', 'use', 'go', 'hey', 'hi', 'my', 'our', 'the', 'be',
140
+ 'on', 'in', 'up', 'do', 'we', 'all', 'one', 'super', 'ultra', 'mega',
141
+ 'hyper', 'meta', 'neo', 'pro', 'open', 'true', 'real', 'next', 'ever',
142
+ ];
143
+
144
+ /**
145
+ * Word segmentation - detect words in concatenated strings.
146
+ * Uses a dictionary-based approach with common words.
147
+ */
148
+ const COMMON_WORDS = new Set([
149
+ // Tech
150
+ 'app', 'api', 'web', 'dev', 'code', 'tech', 'data', 'cloud', 'ai', 'ml',
151
+ 'bot', 'net', 'hub', 'lab', 'labs', 'io', 'bit', 'byte', 'node', 'stack',
152
+ 'soft', 'ware', 'software', 'cyber', 'auto', 'smart', 'intel', 'assist',
153
+ // Actions
154
+ 'get', 'set', 'put', 'run', 'go', 'do', 'make', 'find', 'buy', 'pay',
155
+ 'send', 'sync', 'link', 'chat', 'call', 'meet', 'play', 'work', 'ship',
156
+ 'build', 'create', 'start', 'launch', 'grow', 'scale', 'track', 'save',
157
+ // Descriptors
158
+ 'big', 'fast', 'easy', 'free', 'new', 'hot', 'cool', 'top', 'best', 'pro',
159
+ 'smart', 'super', 'ultra', 'mega', 'mini', 'lite', 'plus', 'prime', 'max',
160
+ 'quick', 'rapid', 'swift', 'safe', 'secure', 'clean', 'clear', 'fresh',
161
+ // Business
162
+ 'shop', 'store', 'mart', 'deal', 'sale', 'cash', 'pay', 'bill', 'trade',
163
+ 'biz', 'corp', 'inc', 'co', 'company', 'brand', 'agency', 'firm',
164
+ // General
165
+ 'my', 'our', 'the', 'one', 'all', 'now', 'here', 'next', 'just', 'only',
166
+ 'vibe', 'flow', 'wave', 'spark', 'boost', 'dash', 'snap', 'pop', 'buzz',
167
+ 'zone', 'spot', 'point', 'base', 'core', 'edge', 'peak', 'rise', 'up',
168
+ // Longer common words
169
+ 'hello', 'world', 'cloud', 'space', 'time', 'team', 'group', 'social',
170
+ 'media', 'video', 'photo', 'audio', 'music', 'sound', 'voice', 'chat',
171
+ 'market', 'money', 'health', 'food', 'home', 'life', 'love', 'star',
172
+ 'coding', 'design', 'studio', 'creative', 'digital', 'mobile', 'online',
173
+ // Food & Beverage
174
+ 'coffee', 'cafe', 'brew', 'bean', 'tea', 'juice', 'pizza', 'burger', 'taco',
175
+ 'chef', 'cook', 'kitchen', 'bakery', 'grill', 'diner', 'bistro', 'eatery',
176
+ // Common compound parts
177
+ 'assistant', 'manager', 'finder', 'maker', 'builder', 'tracker', 'planner',
178
+ ]);
179
+
180
+ /**
181
+ * Attempt to segment a concatenated string into words.
182
+ */
183
+ export function segmentWords(input: string): string[] {
184
+ const normalized = input.toLowerCase().replace(/[^a-z0-9]/g, '');
185
+ const result: string[] = [];
186
+ let remaining = normalized;
187
+
188
+ while (remaining.length > 0) {
189
+ let found = false;
190
+
191
+ // Try longest match first (up to 12 chars)
192
+ for (let len = Math.min(12, remaining.length); len >= 2; len--) {
193
+ const candidate = remaining.slice(0, len);
194
+ if (COMMON_WORDS.has(candidate)) {
195
+ result.push(candidate);
196
+ remaining = remaining.slice(len);
197
+ found = true;
198
+ break;
199
+ }
200
+ }
201
+
202
+ // If no word found, take single char and continue
203
+ if (!found) {
204
+ // Try to find a word starting from next position
205
+ let skipCount = 1;
206
+ for (let skip = 1; skip < Math.min(4, remaining.length); skip++) {
207
+ const subRemaining = remaining.slice(skip);
208
+ for (let len = Math.min(12, subRemaining.length); len >= 2; len--) {
209
+ if (COMMON_WORDS.has(subRemaining.slice(0, len))) {
210
+ skipCount = skip;
211
+ break;
212
+ }
213
+ }
214
+ }
215
+
216
+ // Add the prefix as a potential word fragment
217
+ const fragment = remaining.slice(0, skipCount);
218
+ if (fragment.length >= 2) {
219
+ result.push(fragment);
220
+ }
221
+ remaining = remaining.slice(skipCount);
222
+ }
223
+ }
224
+
225
+ return result;
226
+ }
227
+
228
+ /**
229
+ * Get synonyms for a word.
230
+ */
231
+ export function getSynonyms(word: string): string[] {
232
+ const normalized = word.toLowerCase();
233
+ return SYNONYMS[normalized] || [];
234
+ }
235
+
236
+ /**
237
+ * Get industry-specific terms.
238
+ */
239
+ export function getIndustryTerms(industry: string): string[] {
240
+ const normalized = industry.toLowerCase();
241
+ return INDUSTRY_TERMS[normalized] || [];
242
+ }
243
+
244
+ /**
245
+ * Detect likely industry from keywords.
246
+ */
247
+ export function detectIndustry(words: string[]): string | null {
248
+ const wordSet = new Set(words.map(w => w.toLowerCase()));
249
+
250
+ const industryIndicators: Record<string, string[]> = {
251
+ tech: ['app', 'code', 'coding', 'dev', 'tech', 'software', 'api', 'web', 'cloud', 'ai', 'data', 'cyber', 'digital'],
252
+ startup: ['launch', 'venture', 'startup', 'founder', 'scale', 'growth', 'mvp', 'disrupt'],
253
+ finance: ['pay', 'money', 'bank', 'invest', 'trade', 'crypto', 'fund', 'capital', 'finance', 'fintech'],
254
+ health: ['health', 'fit', 'wellness', 'med', 'care', 'clinic', 'therapy', 'vital', 'nutrition'],
255
+ food: ['food', 'eat', 'coffee', 'kitchen', 'chef', 'restaurant', 'cafe', 'bistro', 'brew', 'cook'],
256
+ creative: ['design', 'art', 'studio', 'creative', 'photo', 'video', 'media', 'pixel', 'visual'],
257
+ ecommerce: ['shop', 'store', 'buy', 'sell', 'cart', 'order', 'deal', 'market', 'commerce'],
258
+ education: ['learn', 'teach', 'course', 'academy', 'school', 'tutor', 'study', 'edu', 'skill'],
259
+ gaming: ['game', 'play', 'quest', 'arena', 'guild', 'level', 'gamer', 'esport'],
260
+ social: ['social', 'connect', 'share', 'community', 'network', 'friend', 'chat', 'vibe'],
261
+ };
262
+
263
+ for (const [industry, indicators] of Object.entries(industryIndicators)) {
264
+ for (const indicator of indicators) {
265
+ if (wordSet.has(indicator)) {
266
+ return industry;
267
+ }
268
+ }
269
+ }
270
+
271
+ return null;
272
+ }
273
+
274
+ /**
275
+ * Generate portmanteau (blended word) from two words.
276
+ */
277
+ export function generatePortmanteau(word1: string, word2: string): string[] {
278
+ const results: string[] = [];
279
+
280
+ // Overlap blend: find common letter sequence
281
+ for (let i = 1; i < Math.min(word1.length, 4); i++) {
282
+ const suffix = word1.slice(-i);
283
+ if (word2.toLowerCase().startsWith(suffix.toLowerCase())) {
284
+ results.push(word1 + word2.slice(i));
285
+ }
286
+ }
287
+
288
+ // Truncation blend: first part + second part
289
+ if (word1.length >= 3 && word2.length >= 3) {
290
+ const blend1 = word1.slice(0, Math.ceil(word1.length * 0.6)) + word2.slice(Math.floor(word2.length * 0.4));
291
+ const blend2 = word1.slice(0, Math.ceil(word1.length * 0.5)) + word2.slice(Math.floor(word2.length * 0.5));
292
+ results.push(blend1, blend2);
293
+ }
294
+
295
+ return [...new Set(results)].filter(r => r.length >= 4 && r.length <= 15);
296
+ }
297
+
298
+ /**
299
+ * Generate creative domain name suggestions.
300
+ */
301
+ export interface SmartSuggestionOptions {
302
+ maxSuggestions?: number;
303
+ includePortmanteau?: boolean;
304
+ includeSynonyms?: boolean;
305
+ includeIndustryTerms?: boolean;
306
+ industry?: string;
307
+ }
308
+
309
+ export function generateSmartSuggestions(
310
+ input: string,
311
+ options: SmartSuggestionOptions = {},
312
+ ): string[] {
313
+ const {
314
+ maxSuggestions = 50,
315
+ includePortmanteau = true,
316
+ includeSynonyms = true,
317
+ includeIndustryTerms = true,
318
+ industry,
319
+ } = options;
320
+
321
+ const suggestions = new Set<string>();
322
+ const normalized = input.toLowerCase().replace(/[^a-z0-9]/g, '');
323
+
324
+ // Add original
325
+ suggestions.add(normalized);
326
+
327
+ // Segment into words
328
+ const words = segmentWords(normalized);
329
+
330
+ // Detect or use provided industry
331
+ const detectedIndustry = industry || detectIndustry(words);
332
+
333
+ // 1. Modern prefix variations
334
+ for (const prefix of MODERN_PREFIXES.slice(0, 15)) {
335
+ suggestions.add(prefix + normalized);
336
+ for (const word of words) {
337
+ if (word.length >= 3) {
338
+ suggestions.add(prefix + word);
339
+ }
340
+ }
341
+ }
342
+
343
+ // 2. Modern suffix variations
344
+ for (const suffix of MODERN_SUFFIXES.slice(0, 15)) {
345
+ suggestions.add(normalized + suffix);
346
+ for (const word of words) {
347
+ if (word.length >= 3) {
348
+ suggestions.add(word + suffix);
349
+ }
350
+ }
351
+ }
352
+
353
+ // 3. Synonym-based suggestions
354
+ if (includeSynonyms) {
355
+ for (const word of words) {
356
+ const synonyms = getSynonyms(word);
357
+ for (const synonym of synonyms.slice(0, 3)) {
358
+ // Replace word with synonym
359
+ const newName = words.map(w => w === word ? synonym : w).join('');
360
+ suggestions.add(newName);
361
+
362
+ // Add prefix/suffix to synonym
363
+ suggestions.add('get' + synonym);
364
+ suggestions.add(synonym + 'hub');
365
+ suggestions.add(synonym + 'app');
366
+ }
367
+ }
368
+ }
369
+
370
+ // 4. Industry-specific suggestions
371
+ if (includeIndustryTerms && detectedIndustry) {
372
+ const industryTerms = getIndustryTerms(detectedIndustry);
373
+ for (const term of industryTerms.slice(0, 8)) {
374
+ suggestions.add(normalized + term);
375
+ suggestions.add(term + normalized);
376
+ for (const word of words) {
377
+ if (word.length >= 3) {
378
+ suggestions.add(word + term);
379
+ suggestions.add(term + word);
380
+ }
381
+ }
382
+ }
383
+ }
384
+
385
+ // 5. Portmanteau suggestions
386
+ if (includePortmanteau && words.length >= 2) {
387
+ for (let i = 0; i < words.length - 1; i++) {
388
+ const blends = generatePortmanteau(words[i]!, words[i + 1]!);
389
+ for (const blend of blends) {
390
+ suggestions.add(blend);
391
+ }
392
+ }
393
+ }
394
+
395
+ // 6. Word reordering
396
+ if (words.length >= 2) {
397
+ suggestions.add(words.slice().reverse().join(''));
398
+ }
399
+
400
+ // 7. Abbreviation suggestions
401
+ if (words.length >= 2) {
402
+ // First letters
403
+ const initials = words.map(w => w[0]).join('');
404
+ if (initials.length >= 2) {
405
+ suggestions.add(initials + 'hub');
406
+ suggestions.add(initials + 'app');
407
+ suggestions.add('go' + initials);
408
+ }
409
+ }
410
+
411
+ // 8. Vowel removal (modern style)
412
+ const noVowels = normalized.replace(/[aeiou]/g, '');
413
+ if (noVowels.length >= 3 && noVowels !== normalized) {
414
+ suggestions.add(noVowels);
415
+ suggestions.add(noVowels + 'io');
416
+ suggestions.add(noVowels + 'app');
417
+ }
418
+
419
+ // 9. Double letter simplification
420
+ const simplified = normalized.replace(/(.)\1+/g, '$1');
421
+ if (simplified !== normalized && simplified.length >= 3) {
422
+ suggestions.add(simplified);
423
+ }
424
+
425
+ // 10. Creative endings
426
+ const creativeEndings = ['ster', 'ery', 'ful', 'ness', 'ize', 'able'];
427
+ for (const ending of creativeEndings) {
428
+ if (!normalized.endsWith(ending)) {
429
+ suggestions.add(normalized + ending);
430
+ }
431
+ }
432
+
433
+ // Filter and return
434
+ return Array.from(suggestions)
435
+ .filter(s => s.length >= 3 && s.length <= 20 && /^[a-z0-9]+$/.test(s))
436
+ .slice(0, maxSuggestions);
437
+ }
438
+
439
+ /**
440
+ * Score a domain name based on quality metrics.
441
+ */
442
+ export function scoreDomainName(name: string, originalInput: string): number {
443
+ let score = 50;
444
+
445
+ // Length preference (shorter is better, but not too short)
446
+ if (name.length <= 6) score += 15;
447
+ else if (name.length <= 8) score += 10;
448
+ else if (name.length <= 10) score += 5;
449
+ else if (name.length > 15) score -= 10;
450
+
451
+ // Exact match bonus
452
+ if (name === originalInput.toLowerCase().replace(/[^a-z0-9]/g, '')) {
453
+ score += 20;
454
+ }
455
+
456
+ // Pronounceability (alternating consonants and vowels is good)
457
+ const vowels = (name.match(/[aeiou]/g) || []).length;
458
+ const ratio = vowels / name.length;
459
+ if (ratio >= 0.25 && ratio <= 0.5) score += 10;
460
+
461
+ // No triple letters
462
+ if (/(.)\1\1/.test(name)) score -= 10;
463
+
464
+ // Starts with common word bonus
465
+ if (COMMON_WORDS.has(name.slice(0, 3)) || COMMON_WORDS.has(name.slice(0, 4))) {
466
+ score += 5;
467
+ }
468
+
469
+ // Modern suffix bonus
470
+ for (const suffix of ['io', 'ai', 'ly', 'ify', 'app', 'hub']) {
471
+ if (name.endsWith(suffix)) {
472
+ score += 5;
473
+ break;
474
+ }
475
+ }
476
+
477
+ // No numbers (usually cleaner)
478
+ if (!/\d/.test(name)) score += 5;
479
+
480
+ return score;
481
+ }
482
+
483
+ export { MODERN_SUFFIXES, MODERN_PREFIXES, INDUSTRY_TERMS, SYNONYMS };