leonelsearchapi 1.0.0-beta.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.
Files changed (3) hide show
  1. package/index.js +148 -0
  2. package/package.json +20 -0
  3. package/readme.md +412 -0
package/index.js ADDED
@@ -0,0 +1,148 @@
1
+ export class LeonelSearchAPI {
2
+ /**
3
+ * @param {Object} options
4
+ * @param {string} options.apiKey Your LeonelSearch API key
5
+ * @param {string} [options.apiVersion='v1'] API version
6
+ * @param {boolean} [options.debug=false] Enable debug logs
7
+ */
8
+ constructor({ apiKey, apiVersion = 'v1', debug = false }) {
9
+ if (!apiKey) throw new Error('apiKey is required');
10
+
11
+ this.apiKey = apiKey;
12
+ this.baseURL = `http://leonelsearch.qzz.io:30213/api/${apiVersion}`;
13
+ this.debug = debug;
14
+
15
+ if (this.debug) {
16
+ console.log('[LeonelSearchAPI] Initialized');
17
+ }
18
+ }
19
+
20
+ /**
21
+ * Performs a search request
22
+ * @param {Object} params
23
+ * @param {string} params.query Search query
24
+ * @param {'web'|'image'|'video'|'news'} params.type Search type
25
+ * @param {number} [params.limit=10] Results per page (1-50)
26
+ * @param {number} [params.page=1] Page number (>=1)
27
+ * @returns {Promise<Object>} API response
28
+ */
29
+ async search({ query, type, limit = 10, page = 1 }) {
30
+ if (!query) throw new Error('Param "query" is required');
31
+ if (!type) throw new Error('Param "type" is required');
32
+
33
+ const validTypes = ['web', 'image', 'video', 'news'];
34
+ if (!validTypes.includes(type)) {
35
+ throw new Error(
36
+ `Invalid type "${type}". Must be one of: ${validTypes.join(', ')}`
37
+ );
38
+ }
39
+
40
+ if (limit < 1 || limit > 50) {
41
+ throw new Error('Param "limit" must be between 1 and 50');
42
+ }
43
+
44
+ if (page < 1) {
45
+ throw new Error('Param "page" must be 1 or greater');
46
+ }
47
+
48
+ const payload = { query, type, limit, page };
49
+
50
+ if (this.debug) {
51
+ console.log('[LeonelSearchAPI] → Request');
52
+ console.log(' Endpoint: /search');
53
+ console.log(' Payload:', payload);
54
+ }
55
+
56
+ try {
57
+ const res = await fetch(`${this.baseURL}/search`, {
58
+ method: 'POST',
59
+ headers: {
60
+ 'Content-Type': 'application/json',
61
+ 'x-api-key': this.apiKey
62
+ },
63
+ body: JSON.stringify(payload)
64
+ });
65
+
66
+ // ==============================
67
+ // ERROR RESPONSE
68
+ // ==============================
69
+ if (!res.ok) {
70
+ let message = `${res.status} ${res.statusText}`;
71
+ let data = null;
72
+
73
+ const raw = await res.text();
74
+
75
+ if (raw) {
76
+ try {
77
+ data = JSON.parse(raw);
78
+ if (data?.message) message = data.message;
79
+ } catch {
80
+ message = raw;
81
+ }
82
+ }
83
+
84
+ const error = new Error(message);
85
+ error.status = res.status;
86
+ error.data = data;
87
+
88
+ if (this.debug) {
89
+ console.error('[LeonelSearchAPI] ✖ API Error');
90
+ console.error(' Status:', res.status);
91
+ console.error(' Message:', message);
92
+ if (data) console.error(' Data:', data);
93
+ }
94
+
95
+ throw error;
96
+ }
97
+
98
+ // ==============================
99
+ // SUCCESS RESPONSE
100
+ // ==============================
101
+ const json = await res.json();
102
+
103
+ if (this.debug) {
104
+ console.log('[LeonelSearchAPI] ← Response');
105
+ console.log(' Query:', json.query);
106
+ console.log(
107
+ ' Results:',
108
+ json.meta?.resultCount ??
109
+ json.results?.length ??
110
+ 0
111
+ );
112
+ }
113
+
114
+ return json;
115
+ } catch (err) {
116
+ if (this.debug) {
117
+ console.error('[LeonelSearchAPI] ✖ Request Failed');
118
+ console.error(err);
119
+ }
120
+
121
+ throw err;
122
+ }
123
+ }
124
+
125
+ // ============================================================
126
+ // Shortcuts
127
+ // ============================================================
128
+
129
+ /** Web search */
130
+ searchWeb(query, limit = 10, page = 1) {
131
+ return this.search({ query, type: 'web', limit, page });
132
+ }
133
+
134
+ /** Image search */
135
+ searchImages(query, limit = 10, page = 1) {
136
+ return this.search({ query, type: 'image', limit, page });
137
+ }
138
+
139
+ /** Video search */
140
+ searchVideos(query, limit = 10, page = 1) {
141
+ return this.search({ query, type: 'video', limit, page });
142
+ }
143
+
144
+ /** News search */
145
+ searchNews(query, limit = 10, page = 1) {
146
+ return this.search({ query, type: 'news', limit, page });
147
+ }
148
+ }
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "leonelsearchapi",
3
+ "version": "1.0.0-beta.1",
4
+ "description": "Official JavaScript client for LeonelSearchAPI. Perform searches easily with your API key.",
5
+ "homepage": "https://github.com/LeonelDevStudios/LeonelSearchAPI#readme",
6
+ "bugs": {
7
+ "url": "https://github.com/LeonelDevStudios/LeonelSearchAPI/issues"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/LeonelDevStudios/LeonelSearchAPI.git"
12
+ },
13
+ "license": "MIT",
14
+ "author": "LeonelDev",
15
+ "type": "module",
16
+ "main": "index.js",
17
+ "scripts": {
18
+ "test": "echo \"Error: no test specified\" && exit 1"
19
+ }
20
+ }
package/readme.md ADDED
@@ -0,0 +1,412 @@
1
+ # LeonelSearchAPI
2
+
3
+ Official JavaScript client for the **LeonelSearch API**.
4
+ Easily perform web searches and retrieve structured results using your API key.
5
+
6
+ ---
7
+
8
+ ## Features
9
+
10
+ - 🔍 **Multi-type search support**: `web`, `image`, `video`, and `news`
11
+ - ⚡ **Lightweight**: No dependencies, fast and efficient
12
+ - 📦 **Modern ES Modules**: Built with `import/export` syntax
13
+ - 📑 **Structured results**: Consistent data format across all search types
14
+ - 🔐 **Secure authentication**: API key protected requests
15
+ - 🌐 **Simple integration**: Easy to use in any JavaScript project
16
+ - 🎯 **Convenience methods**: Dedicated methods for each search type
17
+
18
+ ---
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ npm install leonelsearchapi
24
+ ```
25
+
26
+ ---
27
+
28
+ ## Quick Start
29
+
30
+ ```javascript
31
+ import { LeonelSearchAPI } from 'leonelsearchapi';
32
+
33
+ // Initialize the client
34
+ const client = new LeonelSearchAPI({
35
+ apiKey: 'YOUR_API_KEY', // Get your key from leonelsearch.com
36
+ debug: false // Set true to enable debug logs
37
+ });
38
+
39
+ // Perform a web search
40
+ async function searchExample() {
41
+ try {
42
+ const results = await client.search({
43
+ query: 'latest space news',
44
+ type: 'web', // Search type: 'web', 'image', 'video', or 'news'
45
+ limit: 5,
46
+ page: 1
47
+ });
48
+
49
+ console.log(results);
50
+ } catch (err) {
51
+ console.error('Error:', err.message);
52
+ }
53
+ }
54
+
55
+ searchExample();
56
+ ```
57
+
58
+ ---
59
+
60
+ ## API Reference
61
+
62
+ ### `new LeonelSearchAPI({ apiKey })`
63
+
64
+ * **apiKey** *(string, required)*: Your personal LeonelSearch API key
65
+
66
+ ### `client.search({ query, type, limit, page })`
67
+
68
+ The main search method supporting all search types.
69
+
70
+ | Parameter | Type | Required | Default | Description | Valid Values |
71
+ |-----------|--------|----------|---------|----------------------------|-------------------------------|
72
+ | query | string | ✅ | — | The search term | Any string |
73
+ | type | string | ✅ | — | Type of search to perform | `'web'`, `'image'`, `'video'`, `'news'` |
74
+ | limit | number | ❌ | 10 | Number of results per page | 1-50 |
75
+ | page | number | ❌ | 1 | Page number | ≥1 |
76
+
77
+ **Returns:** A Promise resolving to a structured response object:
78
+
79
+ ```json
80
+ {
81
+ "query": "search query",
82
+ "results": [
83
+ {
84
+ "type": "result type",
85
+ "url": "source URL",
86
+ "title": "result title",
87
+ "text": "description or excerpt",
88
+ "score": 0
89
+ }
90
+ ]
91
+ }
92
+ ```
93
+
94
+ ### Convenience Methods
95
+
96
+ For easier use, the client provides dedicated methods for each search type:
97
+
98
+ #### `client.searchWeb(query, limit = 10, page = 1)`
99
+ Performs a web search.
100
+
101
+ #### `client.searchImages(query, limit = 10, page = 1)`
102
+ Performs an image search.
103
+
104
+ #### `client.searchVideos(query, limit = 10, page = 1)`
105
+ Performs a video search.
106
+
107
+ #### `client.searchNews(query, limit = 10, page = 1)`
108
+ Performs a news search.
109
+
110
+ ---
111
+
112
+ ## Examples
113
+
114
+ ### Using the Main Search Method
115
+
116
+ ```javascript
117
+ // Web search
118
+ const webResults = await client.search({
119
+ query: 'latest space exploration',
120
+ type: 'web',
121
+ limit: 5
122
+ });
123
+
124
+ // Image search
125
+ const imageResults = await client.search({
126
+ query: 'mars rover photos',
127
+ type: 'image',
128
+ limit: 10
129
+ });
130
+
131
+ // Video search
132
+ const videoResults = await client.search({
133
+ query: 'quantum computing explained',
134
+ type: 'video',
135
+ limit: 3
136
+ });
137
+
138
+ // News search
139
+ const newsResults = await client.search({
140
+ query: 'artificial intelligence breakthroughs',
141
+ type: 'news',
142
+ limit: 5,
143
+ page: 2
144
+ });
145
+ ```
146
+
147
+ ### Using Convenience Methods
148
+
149
+ ```javascript
150
+ // More concise syntax for common use cases
151
+ const webResults = await client.searchWeb('space exploration', 10, 1);
152
+ const imageResults = await client.searchImages('natural landscapes', 15, 1);
153
+ const videoResults = await client.searchVideos('cooking tutorials', 5, 1);
154
+ const newsResults = await client.searchNews('technology trends', 8, 1);
155
+ ```
156
+
157
+ ### Complete Example with Error Handling
158
+
159
+ ```javascript
160
+ import { LeonelSearchAPI } from 'leonelsearchapi';
161
+
162
+ const client = new LeonelSearchAPI({
163
+ apiKey: 'your-api-key-here'
164
+ });
165
+
166
+ async function performComprehensiveSearch() {
167
+ try {
168
+ console.log('=== Performing Multiple Search Types ===\n');
169
+
170
+ // Search for web results
171
+ const webSearch = await client.searchWeb('renewable energy innovations', 3);
172
+ console.log('Web Results:', webSearch.results.length, 'items found');
173
+
174
+ // Search for images
175
+ const imageSearch = await client.searchImages('solar panels installation', 4);
176
+ console.log('Image Results:', imageSearch.results.length, 'items found');
177
+
178
+ // Search for news
179
+ const newsSearch = await client.searchNews('climate policy updates', 5);
180
+ console.log('News Results:', newsSearch.results.length, 'items found\n');
181
+
182
+ // Display sample results
183
+ console.log('Sample News Headlines:');
184
+ newsSearch.results.slice(0, 3).forEach((result, index) => {
185
+ console.log(`${index + 1}. ${result.title}`);
186
+ });
187
+
188
+ return { webSearch, imageSearch, newsSearch };
189
+ } catch (error) {
190
+ console.error('Search failed:', error.message);
191
+ throw error;
192
+ }
193
+ }
194
+
195
+ performComprehensiveSearch();
196
+ ```
197
+
198
+ ### Pagination Example
199
+
200
+ ```javascript
201
+ async function fetchPaginatedResults() {
202
+ const allResults = [];
203
+ let currentPage = 1;
204
+ const resultsPerPage = 10;
205
+
206
+ try {
207
+ // Fetch first page
208
+ let response = await client.searchNews('economic indicators', resultsPerPage, currentPage);
209
+ allResults.push(...response.results);
210
+
211
+ // Continue fetching while there are results
212
+ while (response.results.length === resultsPerPage) {
213
+ currentPage++;
214
+ response = await client.searchNews('economic indicators', resultsPerPage, currentPage);
215
+ allResults.push(...response.results);
216
+ }
217
+
218
+ console.log(`Total results fetched: ${allResults.length}`);
219
+ return allResults;
220
+ } catch (error) {
221
+ console.error('Pagination error:', error.message);
222
+ return allResults;
223
+ }
224
+ }
225
+ ```
226
+
227
+ ---
228
+
229
+ ## Response Structure
230
+
231
+ All search methods return results in a consistent format:
232
+
233
+ ```javascript
234
+ {
235
+ query: "original search query",
236
+ results: [
237
+ {
238
+ type: "web", // or "image", "video", "news"
239
+ url: "https://example.com/article",
240
+ title: "Article Title",
241
+ text: "Article excerpt or description...",
242
+ score: 0 // Relevance score
243
+ },
244
+ // ... more results
245
+ ]
246
+ }
247
+ ```
248
+
249
+ ---
250
+
251
+ ## Error Handling
252
+
253
+ ```javascript
254
+ import { LeonelSearchAPI } from 'leonelsearchapi';
255
+
256
+ const client = new LeonelSearchAPI({ apiKey: 'your-key' });
257
+
258
+ async function safeSearch(query, type = 'web') {
259
+ try {
260
+ const results = await client.search({ query, type });
261
+ return results;
262
+ } catch (error) {
263
+ // Handle specific error types
264
+ const errorMessage = error.message.toLowerCase();
265
+
266
+ if (errorMessage.includes('401') || errorMessage.includes('invalid api')) {
267
+ console.error('❌ Authentication failed. Please check your API key.');
268
+ } else if (errorMessage.includes('429') || errorMessage.includes('rate limit')) {
269
+ console.error('⏳ Rate limit exceeded. Please wait before making more requests.');
270
+ } else if (errorMessage.includes('400') || errorMessage.includes('bad request')) {
271
+ console.error('⚠️ Invalid request. Please check your search parameters.');
272
+ } else if (errorMessage.includes('network') || errorMessage.includes('connection')) {
273
+ console.error('🔌 Network error. Please check your internet connection.');
274
+ } else {
275
+ console.error('💥 An unexpected error occurred:', error.message);
276
+ }
277
+
278
+ // Return empty results for graceful degradation
279
+ return { query, results: [] };
280
+ }
281
+ }
282
+
283
+ // Usage
284
+ const results = await safeSearch('test query', 'news');
285
+ ```
286
+
287
+ ---
288
+
289
+ ## TypeScript Support
290
+
291
+ The package includes full TypeScript definitions:
292
+
293
+ ```typescript
294
+ import { LeonelSearchAPI, SearchResult, SearchParams } from 'leonelsearchapi';
295
+
296
+ const client = new LeonelSearchAPI({ apiKey: 'your-key' });
297
+
298
+ // Type-safe search with main method
299
+ async function searchWithTypes(params: SearchParams) {
300
+ const response = await client.search(params);
301
+ return response.results;
302
+ }
303
+
304
+ // Using convenience methods with type inference
305
+ async function convenienceExamples() {
306
+ // These methods are fully typed
307
+ const webResults = await client.searchWeb('typescript tutorial', 5);
308
+ const imageResults = await client.searchImages('typescript logo', 10);
309
+ const newsResults = await client.searchNews('typescript updates', 8);
310
+
311
+ return { webResults, imageResults, newsResults };
312
+ }
313
+
314
+ // Type-safe parameter object
315
+ const searchParams: SearchParams = {
316
+ query: 'typescript vs javascript',
317
+ type: 'web', // TypeScript will validate this value
318
+ limit: 5,
319
+ page: 1
320
+ };
321
+ ```
322
+
323
+ ---
324
+
325
+ ## Best Practices
326
+
327
+ ### 1. **API Key Security**
328
+ ```javascript
329
+ // Store API key in environment variables, not in code
330
+ const client = new LeonelSearchAPI({
331
+ apiKey: process.env.LEONELSEARCH_API_KEY
332
+ });
333
+ ```
334
+
335
+ ### 2. **Request Optimization**
336
+ ```javascript
337
+ // Request only what you need
338
+ const optimalSearch = await client.search({
339
+ query: 'specific topic',
340
+ type: 'web',
341
+ limit: 5 // Smaller limits for faster responses
342
+ });
343
+ ```
344
+
345
+ ### 3. **Implement Caching**
346
+ ```javascript
347
+ // Simple caching strategy
348
+ const searchCache = new Map();
349
+
350
+ async function cachedSearch(query, type = 'web') {
351
+ const cacheKey = `${type}:${query}`;
352
+
353
+ if (searchCache.has(cacheKey)) {
354
+ return searchCache.get(cacheKey);
355
+ }
356
+
357
+ const results = await client.search({ query, type });
358
+ searchCache.set(cacheKey, results);
359
+
360
+ // Optional: Clear cache after some time
361
+ setTimeout(() => searchCache.delete(cacheKey), 300000); // 5 minutes
362
+
363
+ return results;
364
+ }
365
+ ```
366
+
367
+ ### 4. **Rate Limiting**
368
+ ```javascript
369
+ // Implement request spacing
370
+ async function rateLimitedSearch(query, type) {
371
+ await new Promise(resolve => setTimeout(resolve, 1000)); // 1 second delay
372
+ return client.search({ query, type });
373
+ }
374
+ ```
375
+
376
+ ### 5. **Batch Processing**
377
+ ```javascript
378
+ // Process multiple searches efficiently
379
+ async function batchSearch(queries, type = 'web') {
380
+ const results = [];
381
+
382
+ for (const query of queries) {
383
+ try {
384
+ const result = await client.search({ query, type, limit: 3 });
385
+ results.push({ query, success: true, data: result });
386
+ } catch (error) {
387
+ results.push({ query, success: false, error: error.message });
388
+ }
389
+
390
+ // Delay between requests to respect rate limits
391
+ await new Promise(resolve => setTimeout(resolve, 500));
392
+ }
393
+
394
+ return results;
395
+ }
396
+ ```
397
+
398
+ ---
399
+
400
+ ## License
401
+
402
+ MIT © 2026 LeonelDev
403
+
404
+ ---
405
+
406
+ ## Support
407
+
408
+ For API key registration, documentation, and support, visit [leonelsearchapi.com](https://leonelsearchapi.com)
409
+
410
+ ---
411
+
412
+ *Note: This is a beta release. API responses and features may change during development.*