search-web-api 1.0.13

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 (111) hide show
  1. package/README.md +307 -0
  2. package/demo/index.ts +38 -0
  3. package/demo/openapi.ts +402 -0
  4. package/demo/routes/autocomplete.ts +124 -0
  5. package/demo/routes/search.ts +61 -0
  6. package/docs/AUTOCOMPLETE.md +296 -0
  7. package/docs/CATEGORY_SEARCH.md +265 -0
  8. package/package.json +32 -0
  9. package/src/autocomplete/autocomplete-ai-next-word-predictor.ts +47 -0
  10. package/src/autocomplete/autocomplete-search-engine-backends.ts +231 -0
  11. package/src/category-registry.ts +6 -0
  12. package/src/config/search-engine-constants.ts +216 -0
  13. package/src/constants.ts +6 -0
  14. package/src/engine-descriptions.ts +7 -0
  15. package/src/engine-status.ts +7 -0
  16. package/src/engine.ts +6 -0
  17. package/src/registry/search-engine-category-registry.ts +200 -0
  18. package/src/registry/search-engine-descriptions.ts +121 -0
  19. package/src/registry/search-engine-status-tracker.ts +240 -0
  20. package/src/result-container.ts +8 -0
  21. package/src/search/search-engines-registry-list.ts +205 -0
  22. package/src/search/search-query-executor.ts +168 -0
  23. package/src/search/search-result-container.ts +421 -0
  24. package/src/search-web-types.ts +7 -0
  25. package/src/search.ts +10 -0
  26. package/src/sources/academic/arxiv.ts +72 -0
  27. package/src/sources/academic/core.ts +65 -0
  28. package/src/sources/academic/crossref.ts +75 -0
  29. package/src/sources/academic/doaj.ts +63 -0
  30. package/src/sources/academic/google_scholar.ts +53 -0
  31. package/src/sources/academic/openalex.ts +75 -0
  32. package/src/sources/academic/pubmed.ts +96 -0
  33. package/src/sources/academic/semantic_scholar.ts +77 -0
  34. package/src/sources/academic/wikidata.ts +44 -0
  35. package/src/sources/general/baidu.ts +59 -0
  36. package/src/sources/general/bing.ts +30 -0
  37. package/src/sources/general/brave.ts +54 -0
  38. package/src/sources/general/duckduckgo.ts +49 -0
  39. package/src/sources/general/google.ts +68 -0
  40. package/src/sources/general/mojeek.ts +56 -0
  41. package/src/sources/general/qwant.ts +37 -0
  42. package/src/sources/general/startpage.ts +44 -0
  43. package/src/sources/general/yahoo.ts +41 -0
  44. package/src/sources/general/yandex.ts +56 -0
  45. package/src/sources/images/bing_images.ts +68 -0
  46. package/src/sources/images/deviantart.ts +71 -0
  47. package/src/sources/images/flickr.ts +132 -0
  48. package/src/sources/images/google_images.ts +101 -0
  49. package/src/sources/images/imgur.ts +58 -0
  50. package/src/sources/images/openclipart.ts +52 -0
  51. package/src/sources/images/pixabay.ts +56 -0
  52. package/src/sources/images/unsplash.ts +38 -0
  53. package/src/sources/images/wallhaven.ts +50 -0
  54. package/src/sources/it/crates.ts +41 -0
  55. package/src/sources/it/dockerhub.ts +47 -0
  56. package/src/sources/it/github.ts +37 -0
  57. package/src/sources/it/gitlab.ts +55 -0
  58. package/src/sources/it/npm.ts +36 -0
  59. package/src/sources/it/packagist.ts +43 -0
  60. package/src/sources/it/pypi.ts +30 -0
  61. package/src/sources/it/rubygems.ts +43 -0
  62. package/src/sources/it/stackoverflow.ts +39 -0
  63. package/src/sources/maps/apple_maps.ts +105 -0
  64. package/src/sources/maps/openstreetmap.ts +34 -0
  65. package/src/sources/maps/photon.ts +77 -0
  66. package/src/sources/news/bing_news.ts +95 -0
  67. package/src/sources/news/google_news.ts +80 -0
  68. package/src/sources/news/hackernews.ts +94 -0
  69. package/src/sources/news/yahoo_news.ts +77 -0
  70. package/src/sources/shopping/ebay.ts +96 -0
  71. package/src/sources/social/mastodon.ts +46 -0
  72. package/src/sources/social/medium.ts +52 -0
  73. package/src/sources/social/reddit.ts +48 -0
  74. package/src/sources/social/soundcloud.ts +64 -0
  75. package/src/sources/social/twitter.ts +56 -0
  76. package/src/sources/specialized/annas_archive.ts +97 -0
  77. package/src/sources/specialized/archive.ts +48 -0
  78. package/src/sources/specialized/genius.ts +43 -0
  79. package/src/sources/specialized/goodreads.ts +62 -0
  80. package/src/sources/specialized/imdb.ts +55 -0
  81. package/src/sources/specialized/openlibrary.ts +59 -0
  82. package/src/sources/specialized/wikipedia.ts +37 -0
  83. package/src/sources/specialized/wttr.ts +98 -0
  84. package/src/sources/torrents/1337x.ts +43 -0
  85. package/src/sources/torrents/eztv.ts +47 -0
  86. package/src/sources/torrents/kickass.ts +63 -0
  87. package/src/sources/torrents/nyaa.ts +53 -0
  88. package/src/sources/torrents/solidtorrents.ts +68 -0
  89. package/src/sources/torrents/thepiratebay.ts +57 -0
  90. package/src/sources/torrents/yts.ts +54 -0
  91. package/src/sources/videos/bing_videos.ts +91 -0
  92. package/src/sources/videos/dailymotion.ts +101 -0
  93. package/src/sources/videos/invidious.ts +86 -0
  94. package/src/sources/videos/peertube.ts +76 -0
  95. package/src/sources/videos/vimeo.ts +67 -0
  96. package/src/sources/videos/youtube.ts +78 -0
  97. package/src/suggest-next-words/autocomplete-ai.ts +38 -0
  98. package/src/suggest-next-words/autocomplete-search-engines.ts +384 -0
  99. package/src/suggest-next-words/misspelled-typos-8k.json +1 -0
  100. package/src/types/search-engine-interface.ts +27 -0
  101. package/src/types/search-result-types.ts +405 -0
  102. package/test/api.test.ts +128 -0
  103. package/test/autocomplete-ai.test.ts +20 -0
  104. package/test/autocomplete-engines.test.ts +131 -0
  105. package/test/engine-health-suite.test.ts +350 -0
  106. package/test/search.test.ts +69 -0
  107. package/test/sources-unit.test.ts +1152 -0
  108. package/test/sources.test.ts +182 -0
  109. package/test/test-utils.ts +81 -0
  110. package/tsconfig.json +16 -0
  111. package/vitest.config.ts +20 -0
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Search Engine Interface — Re-exports the core engine types from the canonical
3
+ * types module and provides the `extractResponseData` utility for normalising
4
+ * raw grab-url responses into plain data values. All engine source files
5
+ * import `EngineFunction` and `EngineResult` from here.
6
+ */
7
+
8
+ import { EngineResult, Engine, EngineFunction } from "./search-result-types.js";
9
+
10
+ export { EngineResult, Engine, EngineFunction };
11
+
12
+ /**
13
+ * Extract the actual data from a grab-url response.
14
+ * grab-url returns `{ data: actualContent, error?: string }` or just the data directly.
15
+ */
16
+ export function extractResponseData(response: any): any {
17
+ if (!response) return "";
18
+
19
+ if (typeof response === "string") return response;
20
+
21
+ // Error envelope — return empty string to allow graceful handling
22
+ if (typeof response === "object" && "error" in response) return "";
23
+
24
+ if ("data" in response) return response.data;
25
+
26
+ return response;
27
+ }
@@ -0,0 +1,405 @@
1
+ /**
2
+ * Search Result Types — TypeScript interfaces and types for search results,
3
+ * engine configurations, scoring structures, and metadata used throughout
4
+ * the search API. All shared data contracts live here so every module
5
+ * can import from one canonical location.
6
+ */
7
+
8
+ /**
9
+ * Search Engine Result Item
10
+ */
11
+ export interface EngineResult {
12
+ /**
13
+ * The destination URL of the search result.
14
+ */
15
+ url?: string;
16
+ /**
17
+ * Alternative link field (same as url, depends on engine).
18
+ */
19
+ link?: string;
20
+ /**
21
+ * The title of the search result.
22
+ */
23
+ title: string;
24
+ /**
25
+ * The snippet/content description of the search result.
26
+ */
27
+ content: string;
28
+ /**
29
+ * Source URL for a thumbnail image if available.
30
+ */
31
+ thumbnail?: string;
32
+ /**
33
+ * The name of the engine that produced this result.
34
+ */
35
+ engine?: string;
36
+ /**
37
+ * If the result contains an iframe (e.g., embedded video), its source URL.
38
+ */
39
+ iframe_src?: string;
40
+ /**
41
+ * Author or creator of the content.
42
+ */
43
+ author?: string;
44
+ /**
45
+ * Latitude coordinate for location-based results.
46
+ */
47
+ latitude?: number;
48
+ /**
49
+ * Longitude coordinate for location-based results.
50
+ */
51
+ longitude?: number;
52
+ /**
53
+ * Main image source URL for the result.
54
+ */
55
+ img_src?: string;
56
+ /**
57
+ * Date the content was published, usually as a string representation.
58
+ */
59
+ publishedDate?: string;
60
+ /**
61
+ * The category of the result (e.g., general, images, videos).
62
+ */
63
+ category?: string;
64
+ /**
65
+ * Template to be used for rendering this result in the UI.
66
+ */
67
+ template?: string;
68
+ }
69
+
70
+ /**
71
+ * Definition of a Search Engine
72
+ */
73
+ export interface Engine {
74
+ /**
75
+ * The unique identifier/name of the engine.
76
+ */
77
+ name: string;
78
+ /**
79
+ * Array of categories this engine supports.
80
+ */
81
+ categories?: string[];
82
+ /**
83
+ * Function to handle preparing and making the search request.
84
+ */
85
+ request: (query: string, params?: any) => Promise<any>;
86
+ /**
87
+ * Function to handle formatting the raw response into EngineResult[].
88
+ */
89
+ response: (response: any) => Promise<EngineResult[]>;
90
+ }
91
+
92
+ /**
93
+ * Modern Search Engine Function signature
94
+ */
95
+ export interface EngineFunction {
96
+ (
97
+ /**
98
+ * The search query words and phrases
99
+ */
100
+ query: string,
101
+ /**
102
+ * The page number (optional)
103
+ */
104
+ page?: number,
105
+ /**
106
+ * Base domain to use for the request (optional)
107
+ */
108
+ baseDomain?: number,
109
+ ): Promise<EngineResult[]>;
110
+ }
111
+
112
+ /**
113
+ * Result Priority Level
114
+ */
115
+ export type PriorityType = "low" | "normal" | "high";
116
+
117
+ /**
118
+ * A combined result that merges duplicate results across different engines
119
+ */
120
+ export interface MergedResult extends EngineResult {
121
+ /**
122
+ * Array of engine names that returned this result.
123
+ */
124
+ engines: string[];
125
+ /**
126
+ * The original rank positions of this result from its respective engines.
127
+ */
128
+ positions: number[];
129
+ /**
130
+ * A calculated score used for final ranking.
131
+ */
132
+ score: number;
133
+ /**
134
+ * Priority constraint for ranking calculations.
135
+ */
136
+ priority: PriorityType;
137
+ /**
138
+ * The primary category assigned to this merged result.
139
+ */
140
+ category?: string;
141
+ /**
142
+ * Desired UI template string.
143
+ */
144
+ template?: string;
145
+ /**
146
+ * A hashed unique identifier based on URL and title for deduplication.
147
+ */
148
+ resultHash?: string;
149
+ }
150
+
151
+ /**
152
+ * Weights assigned to individual engines for scoring algorithms
153
+ */
154
+ export interface EngineWeight {
155
+ /**
156
+ * A numeric weight assigned to a specific engine.
157
+ */
158
+ [engineName: string]: number;
159
+ }
160
+
161
+ /**
162
+ * Weights assigned to specific categories
163
+ */
164
+ export interface CategoryWeight {
165
+ /**
166
+ * A numeric weight assigned to a specific category.
167
+ */
168
+ [category: string]: number;
169
+ }
170
+
171
+ /**
172
+ * A rich entity or infobox result, often rendered separately from regular links
173
+ */
174
+ export interface Infobox {
175
+ /**
176
+ * Title or main label of the infobox entity.
177
+ */
178
+ infobox: string;
179
+ /**
180
+ * Unique identifier for the infobox entity.
181
+ */
182
+ id?: string;
183
+ /**
184
+ * Text snippet or description of the entity.
185
+ */
186
+ content?: string;
187
+ /**
188
+ * Source URL for the primary image associated with the entity.
189
+ */
190
+ img_src?: string;
191
+ /**
192
+ * Important URLs related to the entity (e.g., Wikipedia page, official site).
193
+ */
194
+ urls?: Array<{
195
+ /**
196
+ * Link label or title.
197
+ */
198
+ title: string;
199
+ /**
200
+ * Target URL.
201
+ */
202
+ url: string;
203
+ /**
204
+ * Optional entity context.
205
+ */
206
+ entity?: string;
207
+ }>;
208
+ /**
209
+ * Key-value attributes describing the entity.
210
+ */
211
+ attributes?: Array<{
212
+ /**
213
+ * Label or name of the attribute.
214
+ */
215
+ label: string;
216
+ /**
217
+ * Value of the attribute.
218
+ */
219
+ value: string;
220
+ /**
221
+ * Optional entity context.
222
+ */
223
+ entity?: string;
224
+ }>;
225
+ /**
226
+ * The primary engine that provided this infobox.
227
+ */
228
+ engine: string;
229
+ /**
230
+ * Set of engines that provided matching infoboxes (for merging).
231
+ */
232
+ engines: Set<string>;
233
+ }
234
+
235
+ /**
236
+ * Tracks an engine that failed to respond or errored out
237
+ */
238
+ export interface UnresponsiveEngine {
239
+ /**
240
+ * Name of the unresponsive engine.
241
+ */
242
+ engine: string;
243
+ /**
244
+ * Type or description of the error encountered.
245
+ */
246
+ errorType: string;
247
+ /**
248
+ * Whether the engine is currently suspended from further queries.
249
+ */
250
+ suspended: boolean;
251
+ }
252
+
253
+ /**
254
+ * Performance metric for an individual engine's request
255
+ */
256
+ export interface Timing {
257
+ /**
258
+ * Name of the engine being timed.
259
+ */
260
+ engine: string;
261
+ /**
262
+ * Total elapsed time in milliseconds.
263
+ */
264
+ total: number;
265
+ /**
266
+ * The time taken specifically for network parsing or loading.
267
+ */
268
+ load: number;
269
+ }
270
+
271
+ /**
272
+ * Miscellaneous data returned by engines
273
+ */
274
+ export interface EngineData {
275
+ /**
276
+ * Holds arbitrary key-value context or metadata specific to an engine.
277
+ */
278
+ [engineName: string]: {
279
+ [key: string]: any;
280
+ };
281
+ }
282
+
283
+ /**
284
+ * Configuration for a Search Category
285
+ */
286
+ export interface CategoryConfig {
287
+ /**
288
+ * Internal ID or key name of the category.
289
+ */
290
+ name: string;
291
+ /**
292
+ * User-facing display name.
293
+ */
294
+ displayName: string;
295
+ /**
296
+ * Short description of what this category entails.
297
+ */
298
+ description: string;
299
+ /**
300
+ * Standard scoring multiplier for this category.
301
+ */
302
+ defaultWeight: number;
303
+ }
304
+
305
+ /**
306
+ * Metadata for a search engine mapping
307
+ */
308
+ export interface EngineMetadata {
309
+ /**
310
+ * The name/identifier of the engine.
311
+ */
312
+ name: string;
313
+ /**
314
+ * The asynchronous function that runs the actual engine query.
315
+ */
316
+ fn: EngineFunction;
317
+ /**
318
+ * Categories the engine operates under.
319
+ */
320
+ categories: string[];
321
+ /**
322
+ * A short description or summary of the engine.
323
+ */
324
+ description?: string;
325
+ }
326
+
327
+ /**
328
+ * Engine Status Tracking
329
+ */
330
+ export interface EngineStatus {
331
+ /**
332
+ * Name of the engine.
333
+ */
334
+ name: string;
335
+ /**
336
+ * Current health status of the engine.
337
+ */
338
+ status: "active" | "failed" | "disabled";
339
+ /**
340
+ * Timestamp of the last health check.
341
+ */
342
+ lastCheck: Date;
343
+ /**
344
+ * Timestamp of the last successful request.
345
+ */
346
+ lastSuccess: Date | null;
347
+ /**
348
+ * Timestamp of the last failed request.
349
+ */
350
+ lastFailure: Date | null;
351
+ /**
352
+ * Total number of consecutive failures.
353
+ */
354
+ failureCount: number;
355
+ /**
356
+ * Total number of successful requests.
357
+ */
358
+ successCount: number;
359
+ /**
360
+ * Total number of requests made to this engine.
361
+ */
362
+ totalRequests: number;
363
+ /**
364
+ * Average response time in milliseconds.
365
+ */
366
+ averageResponseTime: number;
367
+ /**
368
+ * The last error message encountered.
369
+ */
370
+ lastError?: string;
371
+ /**
372
+ * Categories this engine belongs to.
373
+ */
374
+ categories: string[];
375
+ }
376
+
377
+ /**
378
+ * Log entry for an engine request
379
+ */
380
+ export interface EngineLog {
381
+ /**
382
+ * Timestamp of the log entry.
383
+ */
384
+ timestamp: Date;
385
+ /**
386
+ * Name of the engine.
387
+ */
388
+ engineName: string;
389
+ /**
390
+ * Status of the request.
391
+ */
392
+ status: "success" | "failure";
393
+ /**
394
+ * Response time in milliseconds.
395
+ */
396
+ responseTime: number;
397
+ /**
398
+ * Error message if the request failed.
399
+ */
400
+ error?: string;
401
+ /**
402
+ * The query that was made.
403
+ */
404
+ query?: string;
405
+ }
@@ -0,0 +1,128 @@
1
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
2
+ import { Hono } from 'hono';
3
+ import { Search } from '../src/search';
4
+ import { validateEngineResults, TEST_QUERIES } from './test-utils';
5
+
6
+ // Mock API setup
7
+ const app = new Hono();
8
+ const search = new Search();
9
+
10
+ app.get('/search', async (c) => {
11
+ const query = c.req.query('q') || '';
12
+ const pageno = parseInt(c.req.query('pageno') || '1');
13
+ const engines = c.req.query('engines')?.split(',').filter(Boolean);
14
+ const categories = c.req.query('categories')?.split(',').filter(Boolean);
15
+
16
+ if (!query) {
17
+ return c.json({ error: 'Query parameter is required' }, 400);
18
+ }
19
+
20
+ try {
21
+ const results = await search.search(query, pageno, engines, categories);
22
+ return c.json({
23
+ query,
24
+ pageno,
25
+ engines: engines || 'all',
26
+ categories: categories || 'all',
27
+ results
28
+ });
29
+ } catch (error) {
30
+ return c.json({ error: 'Search failed', message: (error as Error).message }, 500);
31
+ }
32
+ });
33
+
34
+ describe('API Integration Tests', () => {
35
+ it('should handle basic search query', async () => {
36
+ const req = new Request('http://localhost/search?q=javascript');
37
+ const res = await app.request(req);
38
+ const data = await res.json();
39
+
40
+ expect(res.status).toBe(200);
41
+ expect(data.query).toBe('javascript');
42
+ expect(data.results).toBeDefined();
43
+ expect(Array.isArray(data.results)).toBe(true);
44
+ expect(validateEngineResults(data.results)).toBe(true);
45
+ }, 60000);
46
+
47
+ it('should require query parameter', async () => {
48
+ const req = new Request('http://localhost/search');
49
+ const res = await app.request(req);
50
+ const data = await res.json();
51
+
52
+ expect(res.status).toBe(400);
53
+ expect(data.error).toBe('Query parameter is required');
54
+ });
55
+
56
+ it('should filter by engines', async () => {
57
+ const req = new Request('http://localhost/search?q=react&engines=github,npm');
58
+ const res = await app.request(req);
59
+ const data = await res.json();
60
+
61
+ expect(res.status).toBe(200);
62
+ expect(data.engines).toEqual(['github', 'npm']);
63
+
64
+ if (data.results.length > 0) {
65
+ data.results.forEach((result: any) => {
66
+ expect(['github', 'npm']).toContain(result.engine);
67
+ });
68
+ }
69
+ }, 60000);
70
+
71
+ it('should filter by categories', async () => {
72
+ const req = new Request('http://localhost/search?q=ubuntu&categories=torrent');
73
+ const res = await app.request(req);
74
+ const data = await res.json();
75
+
76
+ expect(res.status).toBe(200);
77
+ expect(data.categories).toEqual(['torrent']);
78
+ }, 60000);
79
+
80
+ it('should handle pagination', async () => {
81
+ const req = new Request('http://localhost/search?q=python&pageno=2');
82
+ const res = await app.request(req);
83
+ const data = await res.json();
84
+
85
+ expect(res.status).toBe(200);
86
+ expect(data.pageno).toBe(2);
87
+ }, 60000);
88
+
89
+ describe('Common Query Tests', () => {
90
+ it('should search for "javascript"', async () => {
91
+ const req = new Request('http://localhost/search?q=javascript');
92
+ const res = await app.request(req);
93
+ const data = await res.json();
94
+
95
+ expect(res.status).toBe(200);
96
+ expect(data.results.length).toBeGreaterThan(0);
97
+ }, 60000);
98
+
99
+ it('should search for "linux"', async () => {
100
+ const req = new Request('http://localhost/search?q=linux');
101
+ const res = await app.request(req);
102
+ const data = await res.json();
103
+
104
+ expect(res.status).toBe(200);
105
+ expect(data.results.length).toBeGreaterThan(0);
106
+ }, 60000);
107
+
108
+ it('should search for "ubuntu torrent" in torrent engines', async () => {
109
+ const req = new Request('http://localhost/search?q=ubuntu&categories=torrent');
110
+ const res = await app.request(req);
111
+ const data = await res.json();
112
+
113
+ expect(res.status).toBe(200);
114
+ expect(data.results).toBeDefined();
115
+ }, 60000);
116
+
117
+ it('should search for "github" in code engines', async () => {
118
+ const req = new Request('http://localhost/search?q=react&engines=github');
119
+ const res = await app.request(req);
120
+ const data = await res.json();
121
+
122
+ expect(res.status).toBe(200);
123
+ if (data.results.length > 0) {
124
+ expect(data.results[0].engine).toBe('github');
125
+ }
126
+ }, 60000);
127
+ });
128
+ });
@@ -0,0 +1,20 @@
1
+ import { predictNextWordsWithSmallLocalModel } from "../src/suggest-next-words/autocomplete-ai";
2
+ import { describe, it, expect } from "vitest";
3
+
4
+ describe("predictNextWordsWithSmallLocalModel", () => {
5
+ it("should predict next words to complete the sentence", async () => {
6
+ const samplePrompts = [
7
+ // "ai broker has a lot of potential to",
8
+ // "what can help build ai is that",
9
+ "well-suited for sequence generation and can be",
10
+ "the flagship model is estimated to have",
11
+ ];
12
+
13
+ for (const prompt of samplePrompts) {
14
+ const result = await predictNextWordsWithSmallLocalModel(prompt);
15
+ console.log(prompt, "--->", result);
16
+
17
+ expect(result).toBeDefined();
18
+ }
19
+ });
20
+ });
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Autocomplete Example
3
+ *
4
+ * Demonstrates how to use the autocomplete functionality
5
+ * to get search query suggestions from various search engines.
6
+ */
7
+
8
+ import {
9
+ searchAutocomplete,
10
+ searchAutocompleteMulti,
11
+ backends,
12
+ // Individual backend functions
13
+ google,
14
+ duckduckgo,
15
+ brave,
16
+ wikipedia,
17
+ baidu,
18
+ qwant,
19
+ startpage,
20
+ yandex,
21
+ } from "../src/suggest-next-words/autocomplete-search-engines";
22
+
23
+ async function main() {
24
+ console.log("=== Search Autocomplete Examples ===\n");
25
+
26
+ // Example 1: Single backend autocomplete
27
+ console.log('Example 1: Google autocomplete for "typescript"');
28
+ const googleSuggestions = await searchAutocomplete("google", "typescript");
29
+ console.log("Suggestions:", googleSuggestions);
30
+ console.log("");
31
+
32
+ // Example 2: DuckDuckGo autocomplete
33
+ console.log('Example 2: DuckDuckGo autocomplete for "javascript"');
34
+ const ddgSuggestions = await searchAutocomplete("duckduckgo", "javascript");
35
+ console.log("Suggestions:", ddgSuggestions);
36
+ console.log("");
37
+
38
+ // Example 3: Wikipedia autocomplete with locale
39
+ console.log('Example 3: Wikipedia autocomplete for "quantum" (English)');
40
+ const wikiSuggestions = await searchAutocomplete(
41
+ "wikipedia",
42
+ "quantum",
43
+ "en-US"
44
+ );
45
+ console.log("Suggestions:", wikiSuggestions);
46
+ console.log("");
47
+
48
+ // Example 4: Multi-backend autocomplete
49
+ console.log('Example 4: Multi-backend autocomplete for "python"');
50
+ const multiSuggestions = await searchAutocompleteMulti(
51
+ ["google", "duckduckgo", "wikipedia"],
52
+ "python"
53
+ );
54
+ console.log("Merged suggestions:", multiSuggestions);
55
+ console.log("Total unique suggestions:", multiSuggestions.length);
56
+ console.log("");
57
+
58
+ // Example 5: Using backend functions directly
59
+ console.log("Example 5: Direct backend function calls");
60
+
61
+ console.log('\nGoogle suggestions for "react":');
62
+ const reactGoogle = await google("react");
63
+ console.log(reactGoogle);
64
+
65
+ console.log('\nBrave suggestions for "node":');
66
+ const nodeBrave = await brave("node");
67
+ console.log(nodeBrave);
68
+
69
+ console.log('\nWikipedia suggestions for "artificial intelligence":');
70
+ const aiWiki = await wikipedia("artificial intelligence", "en");
71
+ console.log(aiWiki);
72
+ console.log("");
73
+
74
+ // Example 6: Autocomplete with different locales
75
+ console.log("Example 6: Locale-specific autocomplete");
76
+
77
+ console.log("\nGoogle (English):");
78
+ const enGoogle = await google("machine learning", "en");
79
+ console.log(enGoogle.slice(0, 5));
80
+
81
+ console.log("\nGoogle (German):");
82
+ const deGoogle = await google("machine learning", "de");
83
+ console.log(deGoogle.slice(0, 5));
84
+
85
+ console.log("\nGoogle (French):");
86
+ const frGoogle = await google("machine learning", "fr");
87
+ console.log(frGoogle.slice(0, 5));
88
+ console.log("");
89
+
90
+ // Example 7: List all available backends
91
+ console.log("Example 7: Available autocomplete backends");
92
+ const availableBackends = Object.keys(backends);
93
+ console.log("Available backends:", availableBackends);
94
+ console.log("Total:", availableBackends.length);
95
+ console.log("");
96
+
97
+ // Example 8: Comparing results from different backends
98
+ console.log('Example 8: Comparing autocomplete results for "climate change"');
99
+ const query = "climate change";
100
+
101
+ for (const backendName of ["google", "duckduckgo", "brave", "wikipedia"]) {
102
+ const suggestions = await searchAutocomplete(backendName, query);
103
+ console.log(`\n${backendName}: ${suggestions.length} suggestions`);
104
+ console.log(
105
+ suggestions
106
+ .slice(0, 3)
107
+ .map((s) => ` - ${s}`)
108
+ .join("\n")
109
+ );
110
+ }
111
+ console.log("");
112
+
113
+ // Example 9: Asian language autocomplete
114
+ console.log("Example 9: Chinese autocomplete with Baidu");
115
+ const chineseSuggestions = await baidu("人工智能"); // "artificial intelligence" in Chinese
116
+ console.log("Suggestions:", chineseSuggestions);
117
+ console.log("");
118
+
119
+ console.log("Example 10: Russian autocomplete with Yandex");
120
+ const russianSuggestions = await yandex("программирование"); // "programming" in Russian
121
+ console.log("Suggestions:", russianSuggestions);
122
+ console.log("");
123
+
124
+ console.log("=== Examples Complete ===");
125
+ }
126
+
127
+ // Run the examples
128
+ main().catch((error) => {
129
+ console.error("Error running examples:", error);
130
+ process.exit(1);
131
+ });