@graphext/cuery 0.8.1 → 0.8.2

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 (47) hide show
  1. package/esm/mod.d.ts +3 -0
  2. package/esm/mod.d.ts.map +1 -1
  3. package/esm/mod.js +3 -0
  4. package/esm/src/apis/hasdata/aim.d.ts +4 -0
  5. package/esm/src/apis/hasdata/aim.d.ts.map +1 -0
  6. package/esm/src/apis/hasdata/aim.js +32 -0
  7. package/esm/src/apis/hasdata/aio.d.ts +4 -0
  8. package/esm/src/apis/hasdata/aio.d.ts.map +1 -0
  9. package/esm/src/apis/hasdata/aio.js +42 -0
  10. package/esm/src/apis/hasdata/helpers.d.ts +55 -0
  11. package/esm/src/apis/hasdata/helpers.d.ts.map +1 -0
  12. package/esm/src/apis/hasdata/helpers.js +182 -0
  13. package/esm/src/apis/hasdata/index.d.ts +6 -0
  14. package/esm/src/apis/hasdata/index.d.ts.map +1 -0
  15. package/esm/src/apis/hasdata/index.js +5 -0
  16. package/esm/src/apis/hasdata/scrape.d.ts +73 -0
  17. package/esm/src/apis/hasdata/scrape.d.ts.map +1 -0
  18. package/esm/src/apis/hasdata/scrape.js +310 -0
  19. package/esm/src/apis/hasdata/serp.d.ts +152 -0
  20. package/esm/src/apis/hasdata/serp.d.ts.map +1 -0
  21. package/esm/src/apis/hasdata/serp.js +133 -0
  22. package/esm/src/schemas/index.d.ts +6 -2
  23. package/esm/src/schemas/index.d.ts.map +1 -1
  24. package/package.json +1 -1
  25. package/script/mod.d.ts +3 -0
  26. package/script/mod.d.ts.map +1 -1
  27. package/script/mod.js +3 -0
  28. package/script/src/apis/hasdata/aim.d.ts +4 -0
  29. package/script/src/apis/hasdata/aim.d.ts.map +1 -0
  30. package/script/src/apis/hasdata/aim.js +36 -0
  31. package/script/src/apis/hasdata/aio.d.ts +4 -0
  32. package/script/src/apis/hasdata/aio.d.ts.map +1 -0
  33. package/script/src/apis/hasdata/aio.js +46 -0
  34. package/script/src/apis/hasdata/helpers.d.ts +55 -0
  35. package/script/src/apis/hasdata/helpers.d.ts.map +1 -0
  36. package/script/src/apis/hasdata/helpers.js +222 -0
  37. package/script/src/apis/hasdata/index.d.ts +6 -0
  38. package/script/src/apis/hasdata/index.d.ts.map +1 -0
  39. package/script/src/apis/hasdata/index.js +21 -0
  40. package/script/src/apis/hasdata/scrape.d.ts +73 -0
  41. package/script/src/apis/hasdata/scrape.d.ts.map +1 -0
  42. package/script/src/apis/hasdata/scrape.js +352 -0
  43. package/script/src/apis/hasdata/serp.d.ts +152 -0
  44. package/script/src/apis/hasdata/serp.d.ts.map +1 -0
  45. package/script/src/apis/hasdata/serp.js +137 -0
  46. package/script/src/schemas/index.d.ts +6 -2
  47. package/script/src/schemas/index.d.ts.map +1 -1
@@ -0,0 +1,352 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.scrapeWeb = scrapeWeb;
37
+ exports.scrapeWebBatch = scrapeWebBatch;
38
+ exports.submitBatchScrapeJob = submitBatchScrapeJob;
39
+ exports.getBatchJobStatus = getBatchJobStatus;
40
+ exports.waitForBatchCompletion = waitForBatchCompletion;
41
+ exports.getBatchJobPage = getBatchJobPage;
42
+ exports.runBatchScrape = runBatchScrape;
43
+ /* eslint no-console: ["warn", { allow: ["log", "warn", "error"] }] */
44
+ const dntShim = __importStar(require("../../../_dnt.shims.js"));
45
+ const async_js_1 = require("../../helpers/async.js");
46
+ const HASDATA_CONCURRENCY = 29;
47
+ const HASDATA_RETRY_CONFIG = {
48
+ maxRetries: 3,
49
+ initialDelay: 1000,
50
+ maxDelay: 8000,
51
+ backoffMultiplier: 2,
52
+ statusCodes: [429, 500]
53
+ };
54
+ function cleanMarkdown(markdown, excludeImages = true) {
55
+ if (!markdown) {
56
+ return '';
57
+ }
58
+ if (excludeImages) {
59
+ // Remove markdown images: ![alt text](url)
60
+ markdown = markdown.replace(/!\[([^\]]*)\]\([^)]+\)/g, '');
61
+ // Remove standalone "Image" text between line breaks (from plain text format)
62
+ markdown = markdown.replace(/\n\s*Image\s*\n/g, '\n');
63
+ // Clean up multiple consecutive newlines
64
+ markdown = markdown.replace(/\n{3,}/g, '\n\n').trim();
65
+ }
66
+ markdown = markdown.replace(/\u00a0/g, ' ');
67
+ markdown = markdown.replace(/[ \t]+/g, ' ');
68
+ const lines = markdown.split('\n').map(line => line.trim());
69
+ const cleaned = [];
70
+ for (const line of lines) {
71
+ if (line || (cleaned.length > 0 && cleaned[cleaned.length - 1])) {
72
+ cleaned.push(line);
73
+ }
74
+ }
75
+ return cleaned.join('\n').trim();
76
+ }
77
+ async function fetchWithRetry(url, options, retryConfig = HASDATA_RETRY_CONFIG) {
78
+ const response = await (0, async_js_1.withRetries)(async () => fetch(url, {
79
+ ...options,
80
+ signal: dntShim.dntGlobalThis.abortSignal
81
+ }), retryConfig);
82
+ if (!response.ok) {
83
+ const status = response.status;
84
+ let errorMessage;
85
+ if (status === 400) {
86
+ let details = '';
87
+ try {
88
+ const body = await response.text();
89
+ details = ` - ${body}`;
90
+ }
91
+ catch {
92
+ }
93
+ errorMessage = `HasData API error (400): Bad Request${details}`;
94
+ }
95
+ else if (status === 401) {
96
+ errorMessage = 'HasData API error (401): Invalid API key';
97
+ }
98
+ else if (status === 403) {
99
+ errorMessage = 'HasData API error (403): API credits exhausted';
100
+ }
101
+ else if (status === 404) {
102
+ errorMessage = 'HasData API error (404): Resource not found';
103
+ }
104
+ else if (status === 422) {
105
+ let details = '';
106
+ try {
107
+ const body = await response.text();
108
+ details = ` - ${body}`;
109
+ }
110
+ catch {
111
+ }
112
+ errorMessage = `HasData API error (422): Unprocessable Entity${details}`;
113
+ }
114
+ else if (status === 429) {
115
+ errorMessage = 'HasData API error (429): Rate limit exceeded';
116
+ }
117
+ else {
118
+ errorMessage = `HasData API error: ${status} ${response.statusText}`;
119
+ }
120
+ console.error(errorMessage);
121
+ throw new Error(errorMessage);
122
+ }
123
+ return response;
124
+ }
125
+ function configureRequestBody(body, options) {
126
+ const formats = [...options.formats];
127
+ if (!formats.includes('json')) {
128
+ formats.push('json');
129
+ }
130
+ body.outputFormat = formats;
131
+ if (options.proxyType) {
132
+ body.proxyType = options.proxyType;
133
+ }
134
+ if (options.proxyCountry) {
135
+ body.proxyCountry = options.proxyCountry;
136
+ }
137
+ if (options.extractLinks != null) {
138
+ body.extractLinks = options.extractLinks;
139
+ }
140
+ if (options.wait != null) {
141
+ body.wait = options.wait;
142
+ }
143
+ if (options.waitFor) {
144
+ body.waitFor = options.waitFor;
145
+ }
146
+ if (options.blockResources != null) {
147
+ body.blockResources = options.blockResources;
148
+ }
149
+ if (options.blockAds != null) {
150
+ body.blockAds = options.blockAds;
151
+ }
152
+ if (options.blockUrls) {
153
+ body.blockUrls = options.blockUrls;
154
+ }
155
+ if (options.jsRendering != null) {
156
+ body.jsRendering = options.jsRendering;
157
+ }
158
+ if (options.jsScenario) {
159
+ body.jsScenario = options.jsScenario;
160
+ }
161
+ if (options.headers) {
162
+ body.headers = options.headers;
163
+ }
164
+ return body;
165
+ }
166
+ function getApiKey() {
167
+ const apiKey = dntShim.Deno.env.get('HASDATA_API_KEY');
168
+ if (!apiKey) {
169
+ throw new Error('HASDATA_API_KEY environment variable is required');
170
+ }
171
+ return apiKey;
172
+ }
173
+ async function scrapeWeb(url, options) {
174
+ const apiKey = getApiKey();
175
+ const endpoint = 'https://api.hasdata.com/scrape/web';
176
+ let requestBody = { url: url };
177
+ requestBody = configureRequestBody(requestBody, options);
178
+ try {
179
+ const response = await fetchWithRetry(endpoint, {
180
+ method: 'POST',
181
+ headers: {
182
+ 'Content-Type': 'application/json',
183
+ 'x-api-key': apiKey
184
+ },
185
+ body: JSON.stringify(requestBody)
186
+ });
187
+ const responseJson = await response.json();
188
+ const result = { url: url };
189
+ if (responseJson.markdown) {
190
+ result.markdown = cleanMarkdown(responseJson.markdown);
191
+ }
192
+ if (responseJson.text) {
193
+ result.text = responseJson.text;
194
+ }
195
+ if (responseJson.content) {
196
+ result.html = responseJson.content;
197
+ }
198
+ if (options.extractLinks && responseJson.links) {
199
+ result.links = responseJson.links;
200
+ }
201
+ return result;
202
+ }
203
+ catch (error) {
204
+ console.error('HasData Web Scraping API error:', error);
205
+ return {}; // Return an empty object on error
206
+ }
207
+ }
208
+ async function scrapeWebBatch(urls, options, maxConcurrency = HASDATA_CONCURRENCY) {
209
+ return (0, async_js_1.mapParallel)(urls, maxConcurrency, async (url) => {
210
+ return await scrapeWeb(url, options);
211
+ });
212
+ }
213
+ /** Submit a batch scrape job to HasData API.
214
+ * IMPORTANT: results are not returned in original order! You need to match them by jobId and query.url.
215
+ */
216
+ async function submitBatchScrapeJob(urls, options) {
217
+ const apiKey = getApiKey();
218
+ const endpoint = 'https://api.hasdata.com/scrape/batch/web/';
219
+ const requestPayloads = urls.map((url) => {
220
+ let payload = { url: url };
221
+ payload = configureRequestBody(payload, options);
222
+ return payload;
223
+ });
224
+ const requestBody = { requests: requestPayloads };
225
+ try {
226
+ const response = await fetchWithRetry(endpoint, {
227
+ method: 'POST',
228
+ headers: {
229
+ 'Content-Type': 'application/json',
230
+ 'x-api-key': apiKey
231
+ },
232
+ body: JSON.stringify(requestBody)
233
+ });
234
+ return await response.json();
235
+ }
236
+ catch (error) {
237
+ console.error('HasData Batch Scrape submission error:', error);
238
+ throw error;
239
+ }
240
+ }
241
+ async function getBatchJobStatus(jobId) {
242
+ const apiKey = getApiKey();
243
+ const endpoint = `https://api.hasdata.com/scrape/batch/web/${jobId}`;
244
+ try {
245
+ const response = await fetchWithRetry(endpoint, {
246
+ method: 'GET',
247
+ headers: {
248
+ 'x-api-key': apiKey
249
+ }
250
+ });
251
+ const status = await response.json();
252
+ return status;
253
+ }
254
+ catch (error) {
255
+ console.error('HasData Batch Job status error:', error);
256
+ throw error;
257
+ }
258
+ }
259
+ async function waitForBatchCompletion(jobId, pollInterval = 5000, maxWaitTime = 300000) {
260
+ const startTime = Date.now();
261
+ while (true) {
262
+ const status = await getBatchJobStatus(jobId);
263
+ const endStates = ['done', 'stopped', 'finished', 'failed'];
264
+ if (endStates.includes(status.data.status)) {
265
+ return status;
266
+ }
267
+ else {
268
+ const total = status.data.requestsCount;
269
+ const completed = status.data.responsesCount;
270
+ console.log(`Batch job ${jobId} in progress: ${completed}/${total} completed.`);
271
+ }
272
+ const elapsed = Date.now() - startTime;
273
+ if (elapsed >= maxWaitTime) {
274
+ throw new Error(`Batch job ${jobId} did not complete within ${maxWaitTime}ms`);
275
+ }
276
+ await new Promise(resolve => setTimeout(resolve, pollInterval));
277
+ }
278
+ }
279
+ async function getBatchJobPage(jobId, page = 0, limit = 100) {
280
+ const apiKey = getApiKey();
281
+ const url = new URL(`https://api.hasdata.com/scrape/batch/web/${jobId}/results`);
282
+ url.searchParams.set('page', page.toString());
283
+ url.searchParams.set('limit', limit.toString());
284
+ console.log(`Fetching batch job results from: ${url.toString()}`);
285
+ try {
286
+ const response = await fetchWithRetry(url.toString(), {
287
+ method: 'GET',
288
+ headers: {
289
+ 'x-api-key': apiKey
290
+ }
291
+ });
292
+ return await response.json();
293
+ }
294
+ catch (error) {
295
+ console.error('HasData Batch Job results error:', error);
296
+ throw error;
297
+ }
298
+ }
299
+ async function runBatchScrape(urls, options, pageSize = 100, pollInterval = 5000, maxWaitTime = 300000) {
300
+ const { jobId } = await submitBatchScrapeJob(urls, options);
301
+ const status = await waitForBatchCompletion(jobId, pollInterval, maxWaitTime);
302
+ if (status.data.status === 'done') {
303
+ console.log(`Batch job ${jobId} finished successfully.`);
304
+ }
305
+ else {
306
+ throw new Error(`Batch job failed with status:\n${JSON.stringify(status, null, 2)}`);
307
+ }
308
+ const aggregatedResults = [];
309
+ let currentPage = 0;
310
+ let hasMore = true;
311
+ while (hasMore) {
312
+ const pageResults = await getBatchJobPage(jobId, currentPage, pageSize);
313
+ console.log(`Fetched page ${pageResults.page} with ${pageResults.results.length} results.`);
314
+ const scrapeResponses = await (0, async_js_1.mapParallel)(pageResults.results, HASDATA_CONCURRENCY, async (item) => {
315
+ if (item.result.status === 'ok' && item.result.json) {
316
+ try {
317
+ const response = await fetchWithRetry(item.result.json, { method: 'GET' });
318
+ const fullResponse = await response.json();
319
+ const scrapeResponse = {
320
+ url: item.query.url
321
+ };
322
+ if (options.formats.includes('markdown') && fullResponse.markdown) {
323
+ scrapeResponse.markdown = cleanMarkdown(fullResponse.markdown);
324
+ }
325
+ if (options.formats.includes('text') && fullResponse.text) {
326
+ scrapeResponse.text = fullResponse.text;
327
+ }
328
+ if (options.formats.includes('html') && fullResponse.content) {
329
+ scrapeResponse.html = fullResponse.content;
330
+ }
331
+ if (options.extractLinks && fullResponse.links) {
332
+ scrapeResponse.links = fullResponse.links;
333
+ }
334
+ return scrapeResponse;
335
+ }
336
+ catch (error) {
337
+ console.error(`Failed to fetch result for ${item.query.url}:`, error);
338
+ return {};
339
+ }
340
+ }
341
+ return {};
342
+ });
343
+ aggregatedResults.push(...scrapeResponses);
344
+ if (pageResults.results.length < pageSize || (pageResults.page + 1) * pageResults.limit >= pageResults.total) {
345
+ hasMore = false;
346
+ }
347
+ else {
348
+ currentPage += 1;
349
+ }
350
+ }
351
+ return aggregatedResults;
352
+ }
@@ -0,0 +1,152 @@
1
+ import { type AIOverview, type AIOParsed } from './helpers.js';
2
+ type SerpSearchType = 'all' | 'images' | 'videos' | 'news' | 'shopping' | 'local';
3
+ export interface SerpRequestOptions {
4
+ location: string;
5
+ country: string;
6
+ language: string;
7
+ contentLanguage?: string;
8
+ domain?: string;
9
+ filters?: string | Array<string>;
10
+ safeSearch?: 'active' | 'off' | boolean;
11
+ filterResults?: boolean;
12
+ preventAutoCorrect?: boolean;
13
+ offset?: number;
14
+ resultsPerPage?: number;
15
+ type?: SerpSearchType;
16
+ device?: 'desktop' | 'mobile' | 'tablet';
17
+ placeId?: string;
18
+ lsig?: string;
19
+ entityId?: string;
20
+ encodedLocation?: string;
21
+ searchId?: string;
22
+ }
23
+ interface SerpInlineSiteLink {
24
+ title?: string;
25
+ link?: string;
26
+ }
27
+ interface SerpListSiteLink {
28
+ title?: string;
29
+ link?: string;
30
+ snippet?: string;
31
+ }
32
+ interface SerpRichSnippetTop {
33
+ extensions?: Array<string>;
34
+ detectedExtensions?: Record<string, string | number>;
35
+ }
36
+ interface SerpRichSnippet {
37
+ top?: SerpRichSnippetTop;
38
+ }
39
+ interface SerpSiteLinks {
40
+ inline?: Array<SerpInlineSiteLink>;
41
+ list?: Array<SerpListSiteLink>;
42
+ }
43
+ export interface SerpOrganicResult {
44
+ position?: number;
45
+ title?: string;
46
+ link?: string;
47
+ url?: string;
48
+ displayedLink?: string;
49
+ source?: string;
50
+ snippet?: string;
51
+ snippetHighlitedWords?: Array<string>;
52
+ images?: Array<string>;
53
+ richSnippet?: SerpRichSnippet;
54
+ sitelinks?: SerpSiteLinks;
55
+ }
56
+ export interface SerpRequestMetadata {
57
+ id?: string;
58
+ status?: string;
59
+ html?: string;
60
+ url?: string;
61
+ }
62
+ export interface SerpSearchInformation {
63
+ totalResults?: string;
64
+ formattedTotalResults?: string;
65
+ timeTaken?: number;
66
+ searchTime?: number;
67
+ }
68
+ export interface SerpLocalPlace {
69
+ position?: number;
70
+ title?: string;
71
+ rating?: number;
72
+ reviews?: number;
73
+ reviewsOriginal?: string;
74
+ address?: string;
75
+ hours?: string;
76
+ placeId?: string;
77
+ description?: string;
78
+ }
79
+ export interface SerpLocalResults {
80
+ places?: Array<SerpLocalPlace>;
81
+ moreLocationsLink?: string;
82
+ }
83
+ export interface SerpRelatedSearch {
84
+ query?: string;
85
+ link?: string;
86
+ }
87
+ export interface SerpRelatedQuestion {
88
+ question?: string;
89
+ snippet?: string;
90
+ link?: string;
91
+ title?: string;
92
+ displayedLink?: string;
93
+ date?: string;
94
+ list?: Array<string>;
95
+ table?: Array<Array<string>>;
96
+ aiOverview?: AIOverview;
97
+ }
98
+ export interface SerpPerspective {
99
+ index?: number;
100
+ author?: string;
101
+ source?: string;
102
+ duration?: string;
103
+ extensions?: Array<string>;
104
+ thumbnail?: string;
105
+ title?: string;
106
+ link?: string;
107
+ date?: string;
108
+ snippet?: string;
109
+ }
110
+ export interface SerpImmersiveProduct {
111
+ position?: number;
112
+ category?: string;
113
+ title?: string;
114
+ productId?: string;
115
+ productLink?: string;
116
+ price?: string;
117
+ extractedPrice?: number;
118
+ source?: string;
119
+ reviews?: number;
120
+ rating?: number;
121
+ delivery?: string;
122
+ extensions?: Array<string>;
123
+ thumbnail?: string;
124
+ }
125
+ export interface SerpPagination {
126
+ next?: string;
127
+ pages?: Array<Record<string, string>>;
128
+ }
129
+ export interface SerpResponse {
130
+ requestMetadata?: SerpRequestMetadata;
131
+ searchMetadata?: Record<string, unknown>;
132
+ searchParameters?: Record<string, unknown>;
133
+ searchInformation?: SerpSearchInformation;
134
+ organicResults?: Array<SerpOrganicResult>;
135
+ adsResults?: Array<Record<string, unknown>>;
136
+ localResults?: SerpLocalResults;
137
+ knowledgeGraph?: Record<string, unknown>;
138
+ relatedSearches?: Array<SerpRelatedSearch>;
139
+ topStories?: Array<Record<string, unknown>>;
140
+ peopleAlsoAsk?: Array<Record<string, unknown>>;
141
+ relatedQuestions?: Array<SerpRelatedQuestion>;
142
+ imagesResults?: Array<Record<string, unknown>>;
143
+ videosResults?: Array<Record<string, unknown>>;
144
+ perspectives?: Array<SerpPerspective>;
145
+ immersiveProducts?: Array<SerpImmersiveProduct>;
146
+ pagination?: SerpPagination;
147
+ aiOverview?: AIOParsed;
148
+ }
149
+ export declare function fetchSerp(query: string, options: SerpRequestOptions): Promise<SerpResponse>;
150
+ export declare function fetchSerpBatch(queries: Array<string>, options: SerpRequestOptions, maxConcurrency?: number): Promise<Array<SerpResponse>>;
151
+ export {};
152
+ //# sourceMappingURL=serp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serp.d.ts","sourceRoot":"","sources":["../../../../src/src/apis/hasdata/serp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fetchSerp = fetchSerp;
4
+ exports.fetchSerpBatch = fetchSerpBatch;
5
+ /* eslint no-console: ["warn", { allow: ["log", "warn", "error"] }] */
6
+ const async_js_1 = require("../../helpers/async.js");
7
+ const helpers_js_1 = require("./helpers.js");
8
+ const SEARCH_TYPE_TO_TBM = {
9
+ images: 'isch',
10
+ videos: 'vid',
11
+ news: 'nws',
12
+ shopping: 'shop',
13
+ local: 'lcl'
14
+ };
15
+ const SERP_ENDPOINT = 'https://api.hasdata.com/scrape/google/serp';
16
+ function appendParam(url, key, value) {
17
+ url.searchParams.set(key, String(value));
18
+ }
19
+ function appendOptionalParam(url, key, value) {
20
+ if (value === undefined || value === null) {
21
+ return;
22
+ }
23
+ appendParam(url, key, value);
24
+ }
25
+ function formatBooleanParam(value, trueToken, falseToken) {
26
+ if (typeof value === 'boolean') {
27
+ return value ? trueToken : falseToken;
28
+ }
29
+ return String(value);
30
+ }
31
+ function normalizeLocale(value) {
32
+ return value ? value.toLowerCase() : undefined;
33
+ }
34
+ function normalizeDevice(device) {
35
+ if (!device) {
36
+ return undefined;
37
+ }
38
+ const normalized = device.toLowerCase();
39
+ if (normalized === 'desktop' || normalized === 'mobile' || normalized === 'tablet') {
40
+ return normalized;
41
+ }
42
+ return undefined;
43
+ }
44
+ function normalizeTbs(value) {
45
+ if (!value) {
46
+ return undefined;
47
+ }
48
+ if (Array.isArray(value)) {
49
+ return value.map(entry => entry.trim()).filter(Boolean).join(',');
50
+ }
51
+ return value;
52
+ }
53
+ function normalizeTbm(searchType) {
54
+ if (!searchType || searchType === 'all') {
55
+ return undefined;
56
+ }
57
+ const key = searchType.toLowerCase();
58
+ return SEARCH_TYPE_TO_TBM[key] || searchType;
59
+ }
60
+ function applySerpParams(url, options) {
61
+ appendOptionalParam(url, 'location', options.location);
62
+ appendOptionalParam(url, 'gl', normalizeLocale(options.country));
63
+ appendOptionalParam(url, 'hl', normalizeLocale(options.language));
64
+ appendOptionalParam(url, 'lr', options.contentLanguage);
65
+ appendOptionalParam(url, 'domain', options.domain);
66
+ appendOptionalParam(url, 'uule', options.encodedLocation);
67
+ const tbs = normalizeTbs(options.filters);
68
+ if (tbs) {
69
+ appendParam(url, 'tbs', tbs);
70
+ }
71
+ if (options.safeSearch !== undefined) {
72
+ const safeValue = typeof options.safeSearch === 'boolean'
73
+ ? options.safeSearch
74
+ ? 'active'
75
+ : 'off'
76
+ : options.safeSearch;
77
+ appendParam(url, 'safe', safeValue);
78
+ }
79
+ if (options.filterResults !== undefined) {
80
+ const filterValue = formatBooleanParam(options.filterResults, '1', '0');
81
+ appendParam(url, 'filter', filterValue);
82
+ }
83
+ if (options.preventAutoCorrect !== undefined) {
84
+ const nfprValue = formatBooleanParam(options.preventAutoCorrect, '1', '0');
85
+ appendParam(url, 'nfpr', nfprValue);
86
+ }
87
+ const tbm = normalizeTbm(options.type);
88
+ if (typeof options.offset === 'number' && options.offset >= 0) {
89
+ let start = Math.floor(options.offset);
90
+ if (tbm === 'lcl' && start % 20 !== 0) {
91
+ start = Math.floor(start / 20) * 20;
92
+ }
93
+ appendParam(url, 'start', start);
94
+ }
95
+ if (typeof options.resultsPerPage === 'number' && options.resultsPerPage > 0) {
96
+ const num = Math.min(Math.max(Math.floor(options.resultsPerPage), 10), 100);
97
+ appendParam(url, 'num', num);
98
+ }
99
+ if (tbm) {
100
+ appendParam(url, 'tbm', tbm);
101
+ }
102
+ const device = normalizeDevice(options.device);
103
+ if (device) {
104
+ appendParam(url, 'deviceType', device);
105
+ }
106
+ appendOptionalParam(url, 'ludocid', options.placeId);
107
+ appendOptionalParam(url, 'lsig', options.lsig);
108
+ appendOptionalParam(url, 'kgmid', options.entityId);
109
+ appendOptionalParam(url, 'si', options.searchId);
110
+ }
111
+ async function fetchSerpInternal(url) {
112
+ const response = await (0, helpers_js_1.fetchHasDataWithRetry)(url);
113
+ const content = (await response.json());
114
+ let aio = content.aiOverview;
115
+ if (aio && aio.pageToken && aio.hasdataLink) {
116
+ const aioResponse = await (0, helpers_js_1.fetchHasDataWithRetry)(aio.hasdataLink);
117
+ aio = await aioResponse.json();
118
+ }
119
+ if (aio) {
120
+ content.aiOverview = (0, helpers_js_1.parseAIO)(aio);
121
+ }
122
+ return content;
123
+ }
124
+ async function fetchSerp(query, options) {
125
+ const url = new URL(SERP_ENDPOINT);
126
+ url.searchParams.set('q', query);
127
+ applySerpParams(url, options);
128
+ return fetchSerpInternal(url.toString());
129
+ }
130
+ async function fetchSerpBatch(queries, options, maxConcurrency = helpers_js_1.HASDATA_CONCURRENCY) {
131
+ const url = new URL(SERP_ENDPOINT);
132
+ applySerpParams(url, options);
133
+ return (0, async_js_1.mapParallel)(queries, maxConcurrency, async (query) => {
134
+ url.searchParams.set('q', query);
135
+ return await fetchSerpInternal(url.toString());
136
+ });
137
+ }
@@ -12,11 +12,15 @@
12
12
  */
13
13
  export type * from './persona.schema.js';
14
14
  export type * from './brand.schema.js';
15
+ export type * from './entity.schema.js';
15
16
  export type * from './funnel.schema.js';
16
17
  export type * from './keyword.schema.js';
17
18
  export type * from './models.schema.js';
19
+ export type * from './prompt.schema.js';
20
+ export type * from './search.schema.js';
18
21
  export type * from './seedKeyword.schema.js';
19
- export type * from './topics.schema.js';
22
+ export type * from './sentiment.schema.js';
23
+ export type * from './sources.schema.js';
20
24
  export type * from './summary.schema.js';
21
- export type * from './prompt.schema.js';
25
+ export type * from './topics.schema.js';
22
26
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/schemas/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,mBAAmB,qBAAqB,CAAC;AACzC,mBAAmB,mBAAmB,CAAC;AACvC,mBAAmB,oBAAoB,CAAC;AACxC,mBAAmB,qBAAqB,CAAC;AACzC,mBAAmB,oBAAoB,CAAC;AACxC,mBAAmB,yBAAyB,CAAC;AAC7C,mBAAmB,oBAAoB,CAAC;AACxC,mBAAmB,qBAAqB,CAAC;AACzC,mBAAmB,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/schemas/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,mBAAmB,qBAAqB,CAAC;AACzC,mBAAmB,mBAAmB,CAAC;AACvC,mBAAmB,oBAAoB,CAAC;AACxC,mBAAmB,oBAAoB,CAAC;AACxC,mBAAmB,qBAAqB,CAAC;AACzC,mBAAmB,oBAAoB,CAAC;AACxC,mBAAmB,oBAAoB,CAAC;AACxC,mBAAmB,oBAAoB,CAAC;AACxC,mBAAmB,yBAAyB,CAAC;AAC7C,mBAAmB,uBAAuB,CAAC;AAC3C,mBAAmB,qBAAqB,CAAC;AACzC,mBAAmB,qBAAqB,CAAC;AACzC,mBAAmB,oBAAoB,CAAC"}