nosible 0.1.5

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 (44) hide show
  1. package/README.md +438 -0
  2. package/dist/index.cjs +1841 -0
  3. package/dist/index.cjs.map +29 -0
  4. package/dist/index.js +1815 -0
  5. package/dist/index.js.map +29 -0
  6. package/package.json +63 -0
  7. package/src/api/api.test.ts +366 -0
  8. package/src/api/index.ts +179 -0
  9. package/src/api/schemas.ts +152 -0
  10. package/src/client.test.ts +685 -0
  11. package/src/client.ts +762 -0
  12. package/src/index.ts +4 -0
  13. package/src/scrape/types.ts +119 -0
  14. package/src/scrape/webPageData.test.ts +302 -0
  15. package/src/scrape/webPageData.ts +103 -0
  16. package/src/search/analyze.test.ts +396 -0
  17. package/src/search/analyze.ts +151 -0
  18. package/src/search/bulkSearch.ts +62 -0
  19. package/src/search/result.test.ts +423 -0
  20. package/src/search/result.ts +391 -0
  21. package/src/search/result.types.ts +32 -0
  22. package/src/search/resultFactory.ts +21 -0
  23. package/src/search/resultSet.io.test.ts +320 -0
  24. package/src/search/resultSet.test.ts +368 -0
  25. package/src/search/resultSet.ts +387 -0
  26. package/src/search/resultSet.types.ts +3 -0
  27. package/src/search/search.test.ts +299 -0
  28. package/src/search/search.ts +187 -0
  29. package/src/search/searchSet.io.test.ts +321 -0
  30. package/src/search/searchSet.ts +122 -0
  31. package/src/search/sqlFilter.test.ts +129 -0
  32. package/src/search/sqlFilter.ts +147 -0
  33. package/src/test-utils/mocks.ts +159 -0
  34. package/src/topicTrend/topicTrend.ts +53 -0
  35. package/src/utils/browser.test.ts +209 -0
  36. package/src/utils/browser.ts +21 -0
  37. package/src/utils/fernet.ts +47 -0
  38. package/src/utils/file.test.ts +81 -0
  39. package/src/utils/file.ts +195 -0
  40. package/src/utils/index.ts +7 -0
  41. package/src/utils/llm.test.ts +279 -0
  42. package/src/utils/llm.ts +244 -0
  43. package/src/utils/userPlan.test.ts +332 -0
  44. package/src/utils/userPlan.ts +211 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,1841 @@
1
+ var __create = Object.create;
2
+ var __getProtoOf = Object.getPrototypeOf;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __moduleCache = /* @__PURE__ */ new WeakMap;
19
+ var __toCommonJS = (from) => {
20
+ var entry = __moduleCache.get(from), desc;
21
+ if (entry)
22
+ return entry;
23
+ entry = __defProp({}, "__esModule", { value: true });
24
+ if (from && typeof from === "object" || typeof from === "function")
25
+ __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
26
+ get: () => from[key],
27
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
28
+ }));
29
+ __moduleCache.set(from, entry);
30
+ return entry;
31
+ };
32
+ var __export = (target, all) => {
33
+ for (var name in all)
34
+ __defProp(target, name, {
35
+ get: all[name],
36
+ enumerable: true,
37
+ configurable: true,
38
+ set: (newValue) => all[name] = () => newValue
39
+ });
40
+ };
41
+
42
+ // src/index.ts
43
+ var exports_src = {};
44
+ __export(exports_src, {
45
+ Search: () => Search,
46
+ NosibleClient: () => NosibleClient
47
+ });
48
+ module.exports = __toCommonJS(exports_src);
49
+
50
+ // src/search/sqlFilter.ts
51
+ var import_zod = __toESM(require("zod"));
52
+ var sqlFilterSchema = import_zod.default.object({
53
+ publishStart: import_zod.default.date().optional(),
54
+ publishEnd: import_zod.default.date().optional(),
55
+ visitedStart: import_zod.default.date().optional(),
56
+ visitedEnd: import_zod.default.date().optional(),
57
+ certain: import_zod.default.boolean().optional(),
58
+ includeNetlocs: import_zod.default.array(import_zod.default.string()).max(50).optional(),
59
+ excludeNetlocs: import_zod.default.array(import_zod.default.string()).max(50).optional(),
60
+ includeCompanies: import_zod.default.array(import_zod.default.string()).max(50).optional(),
61
+ excludeCompanies: import_zod.default.array(import_zod.default.string()).max(50).optional(),
62
+ includeDocs: import_zod.default.array(import_zod.default.string()).max(50).optional(),
63
+ excludeDocs: import_zod.default.array(import_zod.default.string()).max(50).optional()
64
+ });
65
+ function generateSqlFilter(input) {
66
+ const validatedInput = sqlFilterSchema.parse(input);
67
+ const {
68
+ publishStart,
69
+ publishEnd,
70
+ visitedStart,
71
+ visitedEnd,
72
+ certain,
73
+ includeNetlocs,
74
+ excludeNetlocs,
75
+ includeCompanies,
76
+ excludeCompanies,
77
+ includeDocs,
78
+ excludeDocs
79
+ } = validatedInput;
80
+ const sql = ["SELECT loc FROM engine"];
81
+ const clauses = [];
82
+ if (publishStart || publishEnd) {
83
+ if (publishStart && publishEnd) {
84
+ clauses.push(`published >= '${publishStart.toISOString()}' AND published <= '${publishEnd.toISOString()}'`);
85
+ } else if (publishStart) {
86
+ clauses.push(`published >= '${publishStart.toISOString()}'`);
87
+ } else if (publishEnd) {
88
+ clauses.push(`published <= '${publishEnd.toISOString()}'`);
89
+ }
90
+ }
91
+ if (visitedStart || visitedEnd) {
92
+ if (visitedStart && visitedEnd) {
93
+ clauses.push(`visited >= '${visitedStart.toISOString()}' AND visited <= '${visitedEnd.toISOString()}'`);
94
+ } else if (visitedStart) {
95
+ clauses.push(`visited >= '${visitedStart.toISOString()}'`);
96
+ } else if (visitedEnd) {
97
+ clauses.push(`visited <= '${visitedEnd.toISOString()}'`);
98
+ }
99
+ }
100
+ if (certain === true) {
101
+ clauses.push("certain = TRUE");
102
+ } else if (certain === false) {
103
+ clauses.push("certain = FALSE");
104
+ }
105
+ if (includeNetlocs) {
106
+ const variants = new Set;
107
+ for (const n of includeNetlocs) {
108
+ variants.add(n);
109
+ if (n.startsWith("www.")) {
110
+ variants.add(n.slice(4));
111
+ } else {
112
+ variants.add("www." + n);
113
+ }
114
+ }
115
+ const inList = Array.from(variants).sort().map((v) => `'${v}'`).join(", ");
116
+ clauses.push(`netloc IN (${inList})`);
117
+ }
118
+ if (excludeNetlocs) {
119
+ const variants = new Set;
120
+ for (const n of excludeNetlocs) {
121
+ variants.add(n);
122
+ if (n.startsWith("www.")) {
123
+ variants.add(n.slice(4));
124
+ } else {
125
+ variants.add("www." + n);
126
+ }
127
+ }
128
+ const exList = Array.from(variants).sort().map((v) => `'${v}'`).join(", ");
129
+ clauses.push(`netloc NOT IN (${exList})`);
130
+ }
131
+ if (includeCompanies) {
132
+ const companyList = includeCompanies.map((c) => `ARRAY_CONTAINS(companies, '${c}')`).join(" OR ");
133
+ clauses.push(`(companies IS NOT NULL AND (${companyList}))`);
134
+ }
135
+ if (excludeCompanies) {
136
+ const companyList = excludeCompanies.map((c) => `ARRAY_CONTAINS(companies, '${c}')`).join(" OR ");
137
+ clauses.push(`(companies IS NULL OR NOT (${companyList}))`);
138
+ }
139
+ if (includeDocs) {
140
+ const docHashes = includeDocs.map((doc) => `'${doc}'`).join(", ");
141
+ clauses.push(`doc_hash IN (${docHashes})`);
142
+ }
143
+ if (excludeDocs) {
144
+ const docHashes = excludeDocs.map((doc) => `'${doc}'`).join(", ");
145
+ clauses.push(`doc_hash NOT IN (${docHashes})`);
146
+ }
147
+ if (clauses.length > 0) {
148
+ sql.push("WHERE " + clauses.join(" AND "));
149
+ }
150
+ if (sql.length === 1) {
151
+ return null;
152
+ }
153
+ const sqlFilter = sql.join(" ");
154
+ return sqlFilter;
155
+ }
156
+
157
+ // src/search/search.ts
158
+ var import_zod5 = require("zod");
159
+
160
+ // src/api/schemas.ts
161
+ var import_zod3 = __toESM(require("zod"));
162
+
163
+ // src/scrape/types.ts
164
+ var import_zod2 = require("zod");
165
+ var snippetStatisticsSchema = import_zod2.z.object({
166
+ sentences: import_zod2.z.number(),
167
+ words: import_zod2.z.number(),
168
+ characters: import_zod2.z.number(),
169
+ links: import_zod2.z.number().optional(),
170
+ images: import_zod2.z.number().optional()
171
+ });
172
+ var snippetSchema = import_zod2.z.object({
173
+ url_hash: import_zod2.z.string(),
174
+ snippet_hash: import_zod2.z.string(),
175
+ prev_snippet_hash: import_zod2.z.string().nullable(),
176
+ next_snippet_hash: import_zod2.z.string().nullable(),
177
+ content: import_zod2.z.string(),
178
+ words: import_zod2.z.string().optional(),
179
+ language: import_zod2.z.string(),
180
+ statistics: snippetStatisticsSchema.optional(),
181
+ links: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.string()).optional(),
182
+ images: import_zod2.z.array(import_zod2.z.string()).optional()
183
+ });
184
+ var scrapeStatisticsSchema = import_zod2.z.object({
185
+ snippets: import_zod2.z.number(),
186
+ sentences: import_zod2.z.number(),
187
+ words: import_zod2.z.number(),
188
+ characters: import_zod2.z.number(),
189
+ images: import_zod2.z.number(),
190
+ videos: import_zod2.z.number(),
191
+ audio: import_zod2.z.number(),
192
+ tables: import_zod2.z.number(),
193
+ lists: import_zod2.z.number(),
194
+ blocks: import_zod2.z.number(),
195
+ links: import_zod2.z.number(),
196
+ files: import_zod2.z.number()
197
+ });
198
+ var scrapePageSchema = import_zod2.z.object({
199
+ title: import_zod2.z.string(),
200
+ description: import_zod2.z.string(),
201
+ author: import_zod2.z.string(),
202
+ published: import_zod2.z.coerce.date(),
203
+ visited: import_zod2.z.coerce.date(),
204
+ certain: import_zod2.z.boolean().optional()
205
+ });
206
+ var querySchema = import_zod2.z.object({});
207
+ var scrapeRequestSchema = import_zod2.z.object({
208
+ raw_url: import_zod2.z.string(),
209
+ url: import_zod2.z.string(),
210
+ hash: import_zod2.z.string(),
211
+ geo: import_zod2.z.string(),
212
+ proxy: import_zod2.z.string(),
213
+ scheme: import_zod2.z.string(),
214
+ netloc: import_zod2.z.string(),
215
+ prefix: import_zod2.z.string(),
216
+ domain: import_zod2.z.string(),
217
+ suffix: import_zod2.z.string(),
218
+ path: import_zod2.z.string(),
219
+ query: import_zod2.z.string(),
220
+ fragment: import_zod2.z.string(),
221
+ query_allowed: querySchema,
222
+ query_blocked: querySchema
223
+ });
224
+ var metadataSchema = import_zod2.z.record(import_zod2.z.string(), import_zod2.z.any());
225
+ var logoSchema = import_zod2.z.object({
226
+ "@type": import_zod2.z.string().optional(),
227
+ "@id": import_zod2.z.string().optional(),
228
+ caption: import_zod2.z.string().optional(),
229
+ inLanguage: import_zod2.z.string().optional(),
230
+ url: import_zod2.z.string(),
231
+ width: import_zod2.z.union([import_zod2.z.string(), import_zod2.z.number()]).optional(),
232
+ height: import_zod2.z.union([import_zod2.z.string(), import_zod2.z.number()]).optional()
233
+ });
234
+ var publisherSchema = import_zod2.z.object({
235
+ "@type": import_zod2.z.string(),
236
+ name: import_zod2.z.string().optional(),
237
+ url: import_zod2.z.string().optional(),
238
+ logo: import_zod2.z.union([logoSchema, import_zod2.z.string()]).optional(),
239
+ sameAs: import_zod2.z.union([import_zod2.z.array(import_zod2.z.string()), import_zod2.z.string()]).optional()
240
+ });
241
+ var structuredSchema = import_zod2.z.object({
242
+ "@context": import_zod2.z.string().optional(),
243
+ "@type": import_zod2.z.string().optional(),
244
+ headline: import_zod2.z.string().optional(),
245
+ publisher: publisherSchema.optional()
246
+ });
247
+ var urlTreeSchema = import_zod2.z.record(import_zod2.z.string(), import_zod2.z.any());
248
+ var scrapeResponseSchema = import_zod2.z.object({
249
+ request: scrapeRequestSchema,
250
+ page: scrapePageSchema,
251
+ statistics: scrapeStatisticsSchema,
252
+ languages: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.number()),
253
+ snippets: import_zod2.z.record(import_zod2.z.string(), snippetSchema),
254
+ full_text: import_zod2.z.string(),
255
+ metadata: metadataSchema,
256
+ structured: import_zod2.z.array(structuredSchema),
257
+ url_tree: urlTreeSchema
258
+ });
259
+ var scrapeFullResSchema = import_zod2.z.object({
260
+ message: import_zod2.z.string(),
261
+ added_to_batch: import_zod2.z.boolean(),
262
+ response: scrapeResponseSchema
263
+ });
264
+
265
+ // src/api/schemas.ts
266
+ var queryTypeEnum = import_zod3.default.enum(["fast-search", "search", "bulk-search"]);
267
+ var algorithmEnum = import_zod3.default.enum([
268
+ "string",
269
+ "lexical",
270
+ "baseline",
271
+ "hamming",
272
+ "hybrid-1",
273
+ "hybrid-2",
274
+ "hybrid-3",
275
+ "company"
276
+ ]);
277
+ var brandSafetyEnum = import_zod3.default.enum(["safe", "sensitive", "unsafe"]);
278
+ var continentEnum = import_zod3.default.enum([
279
+ "Africa",
280
+ "Asia",
281
+ "Europe",
282
+ "North America",
283
+ "Oceania",
284
+ "South America",
285
+ "Worldwide"
286
+ ]);
287
+ var regionEnum = import_zod3.default.enum([
288
+ "Caribbean",
289
+ "Central Africa",
290
+ "Central America",
291
+ "Central Asia",
292
+ "Central Europe",
293
+ "East Africa",
294
+ "East Asia",
295
+ "Eastern Europe",
296
+ "Middle East",
297
+ "North Africa",
298
+ "North America",
299
+ "Northern Europe",
300
+ "Oceania",
301
+ "South America",
302
+ "South Asia",
303
+ "Southeast Asia",
304
+ "Southern Africa",
305
+ "Southern Europe",
306
+ "Sub-Saharan Africa",
307
+ "The Amazon Basin",
308
+ "The Andes",
309
+ "The Arctic Region",
310
+ "The Balkans",
311
+ "The Caucasus",
312
+ "The Horn of Africa",
313
+ "The Levant",
314
+ "The Middle East",
315
+ "The Sahel",
316
+ "West Africa",
317
+ "Western Europe",
318
+ "Worldwide"
319
+ ]);
320
+ var searchQuerySchema = import_zod3.default.object({
321
+ instruction: import_zod3.default.string(),
322
+ question: import_zod3.default.string(),
323
+ expansions: import_zod3.default.array(import_zod3.default.string()),
324
+ brand_safety: import_zod3.default.null(),
325
+ language: import_zod3.default.string().nullable(),
326
+ continent: import_zod3.default.string().nullable(),
327
+ region: import_zod3.default.string().nullable(),
328
+ country: import_zod3.default.string().nullable(),
329
+ sector: import_zod3.default.string().nullable(),
330
+ industry_group: import_zod3.default.string().nullable(),
331
+ industry: import_zod3.default.string().nullable(),
332
+ sub_industry: import_zod3.default.string().nullable(),
333
+ iab_tier_1: import_zod3.default.string().nullable(),
334
+ iab_tier_2: import_zod3.default.string().nullable(),
335
+ iab_tier_3: import_zod3.default.string().nullable(),
336
+ iab_tier_4: import_zod3.default.string().nullable(),
337
+ algorithm: import_zod3.default.string(),
338
+ n_results: import_zod3.default.number(),
339
+ n_contextify: import_zod3.default.number(),
340
+ n_probes: import_zod3.default.number(),
341
+ min_similarity: import_zod3.default.number(),
342
+ pass_similarity: import_zod3.default.number(),
343
+ must_exclude: import_zod3.default.array(import_zod3.default.string()),
344
+ must_include: import_zod3.default.array(import_zod3.default.string()),
345
+ shard_selector: import_zod3.default.string(),
346
+ shard_reranker: import_zod3.default.string(),
347
+ search_lang: import_zod3.default.string(),
348
+ search_words: import_zod3.default.record(import_zod3.default.string(), import_zod3.default.number()),
349
+ search_intents: import_zod3.default.record(import_zod3.default.string(), import_zod3.default.any()),
350
+ companies: import_zod3.default.array(import_zod3.default.any())
351
+ });
352
+ var searchResultSemanticsSchema = import_zod3.default.object({
353
+ origin_shard: import_zod3.default.number(),
354
+ chunks_total: import_zod3.default.number(),
355
+ chunks_matched: import_zod3.default.number(),
356
+ chunks_kept: import_zod3.default.number(),
357
+ similarity: import_zod3.default.number(),
358
+ bitstring: import_zod3.default.string()
359
+ });
360
+ var searchResponseSchema = import_zod3.default.object({
361
+ url_hash: import_zod3.default.string(),
362
+ url: import_zod3.default.string(),
363
+ netloc: import_zod3.default.string(),
364
+ published: import_zod3.default.string(),
365
+ visited: import_zod3.default.string(),
366
+ language: import_zod3.default.string(),
367
+ author: import_zod3.default.string(),
368
+ title: import_zod3.default.string(),
369
+ description: import_zod3.default.string(),
370
+ content: import_zod3.default.string(),
371
+ best_chunk: import_zod3.default.string(),
372
+ semantics: searchResultSemanticsSchema
373
+ });
374
+ var bulkResSchema = import_zod3.default.object({
375
+ message: import_zod3.default.string(),
376
+ decrypt_using: import_zod3.default.string(),
377
+ download_from: import_zod3.default.string()
378
+ });
379
+
380
+ // src/utils/llm.ts
381
+ var defaultModel = "google/gemini-2.0-flash-001";
382
+ var getSentiment = async ({
383
+ text,
384
+ model = defaultModel,
385
+ llmClient
386
+ }) => {
387
+ if (!llmClient) {
388
+ throw new Error("A OpenAI client instance must be provided as 'llmClient'.");
389
+ }
390
+ if (!text || text.trim() === "") {
391
+ throw new Error("Text must not be empty or whitespace.");
392
+ }
393
+ const prompt = `
394
+ # TASK DESCRIPTION
395
+ On a scale from -1.0 (very negative) to 1.0 (very positive),
396
+ please rate the sentiment of the following text and return _only_ the numeric score:
397
+ ${text.trim()}
398
+
399
+ # RESPONSE FORMAT
400
+
401
+ The response must be a float in [-1.0, 1.0]. No other text must be returned.
402
+ `;
403
+ try {
404
+ const completion = await llmClient.chat.completions.create({
405
+ model,
406
+ messages: [{ role: "user", content: prompt.trim() }],
407
+ temperature: 0.7
408
+ });
409
+ const raw = completion.choices[0]?.message?.content;
410
+ const score = parseFloat(raw);
411
+ if (Number.isNaN(score)) {
412
+ throw new Error(`Sentiment response is not a float: ${JSON.stringify(raw)}`);
413
+ }
414
+ if (score < -1 || score > 1) {
415
+ throw new Error(`Sentiment ${score} outside valid range [-1.0, 1.0]`);
416
+ }
417
+ return score;
418
+ } catch (error) {
419
+ throw error;
420
+ }
421
+ };
422
+ var generateExpansions = async ({
423
+ question,
424
+ model = defaultModel,
425
+ llmClient
426
+ }) => {
427
+ if (!llmClient) {
428
+ throw new Error("A OpenAI client instance must be provided as 'llmClient'.");
429
+ }
430
+ if (!question || question.trim() === "") {
431
+ throw new Error("Question must not be empty or whitespace.");
432
+ }
433
+ const prompt = `
434
+ # TASK DESCRIPTION
435
+
436
+
437
+ Given a search question you must generate a list of 10 similar questions that have the same exact
438
+ semantic meaning but are contextually and lexically different to improve search recall.
439
+
440
+
441
+ ## Question
442
+
443
+ Here is the question you must generate expansions for:
444
+
445
+ Question: ${question.trim()}
446
+
447
+ # RESPONSE FORMAT
448
+
449
+ Your response must be a JSON object structured as follows: a list of ten strings. Each string must
450
+ be a grammatically correct question that expands on the original question to improve recall.
451
+
452
+ [
453
+ string,
454
+ string,
455
+ string,
456
+ string,
457
+ string,
458
+ string,
459
+ string,
460
+ string,
461
+ string,
462
+ string
463
+ ]
464
+
465
+ # EXPANSION GUIDELINES
466
+
467
+ 1. **Use specific named entities** - To improve the quality of your search results you must mention
468
+ specific named entities (people, locations, organizations, products, places) in expansions.
469
+ 2. **Expansions must be highly targeted** - To improve the quality of search results each expansion
470
+ must be semantically unambiguous. Questions must be use between ten and fifteen words.
471
+ 3. **Expansions must improve recall** - When expanding the question leverage semantic and contextual
472
+ expansion to maximize the ability of the search engine to find semantically relevant documents:
473
+ - Semantic Example: Swap "climate change" with "global warming" or "environmental change".
474
+ - Contextual Example: Swap "diabetes treatment" with "insulin therapy" or "blood sugar management".
475
+ `;
476
+ try {
477
+ const completion = await llmClient.chat.completions.create({
478
+ model,
479
+ messages: [{ role: "user", content: prompt.trim() }],
480
+ temperature: 0.7
481
+ });
482
+ let raw = completion.choices[0]?.message?.content ?? "";
483
+ let toParse = raw.trim();
484
+ if (toParse.startsWith("```")) {
485
+ toParse = toParse.replace(/^```+/, "").trim();
486
+ if (toParse.toLowerCase().startsWith("json")) {
487
+ toParse = toParse.slice(4).trim();
488
+ }
489
+ toParse = toParse.replace(/```+$/, "").trim();
490
+ }
491
+ let expansions;
492
+ try {
493
+ expansions = JSON.parse(toParse);
494
+ } catch (decodeErr) {
495
+ throw new Error(`OpenRouter response was not valid JSON: '${toParse}'`);
496
+ }
497
+ if (!Array.isArray(expansions) || expansions.length !== 10 || !expansions.every((q) => typeof q === "string")) {
498
+ throw new Error("Invalid response: 'choices' missing or empty");
499
+ }
500
+ console.debug("Expansions: ", expansions);
501
+ return expansions;
502
+ } catch (error) {
503
+ throw error;
504
+ }
505
+ };
506
+
507
+ // src/api/index.ts
508
+ var import_zod4 = require("zod");
509
+ var fastNResults = import_zod4.z.number().min(10).max(100).optional().default(100);
510
+ var searchNResults = import_zod4.z.number().min(100).max(1000).optional().default(100);
511
+ var bulkNResults = import_zod4.z.number().min(1000).max(1e4).optional().default(1000);
512
+ var aiSearchParamsSchema = import_zod4.z.object({
513
+ prompt: import_zod4.z.string().min(25).max(2500),
514
+ agent: import_zod4.z.string().optional()
515
+ });
516
+ var stdSearchParams = import_zod4.z.object({
517
+ question: import_zod4.z.string(),
518
+ expansions: import_zod4.z.array(import_zod4.z.string()).optional(),
519
+ sql_filter: import_zod4.z.string().optional(),
520
+ algorithm: algorithmEnum.optional(),
521
+ n_results: import_zod4.z.number(),
522
+ n_probes: import_zod4.z.number().min(1).max(10).optional(),
523
+ n_contextify: import_zod4.z.number().min(64).max(1024).optional(),
524
+ min_similarity: import_zod4.z.number().min(0).max(1).optional(),
525
+ must_include: import_zod4.z.array(import_zod4.z.string()).max(100).optional(),
526
+ must_exclude: import_zod4.z.array(import_zod4.z.string()).max(100).optional(),
527
+ brand_safety: brandSafetyEnum.optional(),
528
+ language: import_zod4.z.string().min(2).max(2).optional(),
529
+ continent: continentEnum.optional(),
530
+ region: regionEnum.optional(),
531
+ country: import_zod4.z.string().optional(),
532
+ sector: import_zod4.z.string().optional(),
533
+ industry_group: import_zod4.z.string().optional(),
534
+ industry: import_zod4.z.string().optional(),
535
+ sub_industry: import_zod4.z.string().optional(),
536
+ iab_tier_1: import_zod4.z.string().optional(),
537
+ iab_tier_2: import_zod4.z.string().optional(),
538
+ iab_tier_3: import_zod4.z.string().optional(),
539
+ iab_tier_4: import_zod4.z.string().optional(),
540
+ companies: import_zod4.z.array(import_zod4.z.string()).max(30).optional()
541
+ });
542
+ var fastSearchParamsSchema = import_zod4.z.object({
543
+ ...stdSearchParams.shape,
544
+ n_results: fastNResults
545
+ });
546
+ var bulkSearchParamsSchema = import_zod4.z.object({
547
+ ...stdSearchParams.shape,
548
+ n_results: bulkNResults
549
+ });
550
+ var validateFastSearchParams = (params) => {
551
+ const validatedParams = fastSearchParamsSchema.parse(params);
552
+ return validatedParams;
553
+ };
554
+ var validateBulkSearchParams = (params) => {
555
+ const validatedParams = bulkSearchParamsSchema.parse(params);
556
+ return validatedParams;
557
+ };
558
+ var scapeUrlBody = import_zod4.z.object({
559
+ url: import_zod4.z.string()
560
+ });
561
+ var topicTrendBody = import_zod4.z.object({
562
+ query: import_zod4.z.string(),
563
+ sql_filter: import_zod4.z.string().optional()
564
+ });
565
+ var callNosibleApi = async ({
566
+ baseUrl = "https://www.nosible.ai/search/v2",
567
+ endpoint,
568
+ body,
569
+ apiKey
570
+ }) => {
571
+ const response = await fetch(`${baseUrl}/${endpoint}`, {
572
+ method: "POST",
573
+ headers: {
574
+ Accept: "application/json",
575
+ "Content-Type": "application/json",
576
+ "Api-Key": `${apiKey}`
577
+ },
578
+ body: JSON.stringify(body)
579
+ });
580
+ if (!response.ok) {
581
+ console.error("Status: " + response.status);
582
+ if (response.status === 401) {
583
+ throw new Error("Your API key is not valid.");
584
+ }
585
+ if (response.status === 422) {
586
+ const contentType = response.headers.get("Content-Type") || "";
587
+ if (contentType.startsWith("application/json")) {
588
+ const body2 = await response.json();
589
+ const errorBody = Array.isArray(body2) ? body2[0] : body2;
590
+ console.error(errorBody);
591
+ if (errorBody?.type === "string_too_short") {
592
+ throw new Error("Your API key is not valid: Too Short.");
593
+ }
594
+ }
595
+ throw new Error("You made a bad request.");
596
+ }
597
+ if (response.status === 429) {
598
+ throw new Error("You have hit your rate limit.");
599
+ }
600
+ if (response.status === 409) {
601
+ throw new Error("Too many concurrent searches.");
602
+ }
603
+ if (response.status === 500) {
604
+ throw new Error("An unexpected error occurred.");
605
+ }
606
+ if (response.status === 502) {
607
+ throw new Error("NOSIBLE is currently restarting.");
608
+ }
609
+ if (response.status === 504) {
610
+ throw new Error("NOSIBLE is currently overloaded.");
611
+ }
612
+ console.error(await response.text());
613
+ throw new Error(`HTTP error! status: ${response.status}`);
614
+ } else {
615
+ const data = await response.json();
616
+ return data;
617
+ }
618
+ };
619
+
620
+ // src/search/search.ts
621
+ var userSearchParamsSchema = sqlFilterSchema.extend({
622
+ question: import_zod5.z.string().optional(),
623
+ autoGenerateExpansions: import_zod5.z.boolean().optional(),
624
+ expansions: import_zod5.z.array(import_zod5.z.string()).optional(),
625
+ sqlFilter: import_zod5.z.string().optional(),
626
+ algorithm: algorithmEnum.optional(),
627
+ nResults: import_zod5.z.number().optional(),
628
+ nProbes: import_zod5.z.number().min(1).max(10).optional(),
629
+ nContextify: import_zod5.z.number().min(64).max(1024).optional(),
630
+ minSimilarity: import_zod5.z.number().min(0).max(1).optional(),
631
+ mustInclude: import_zod5.z.array(import_zod5.z.string()).max(100).optional(),
632
+ mustExclude: import_zod5.z.array(import_zod5.z.string()).max(100).optional(),
633
+ brandSafety: brandSafetyEnum.optional(),
634
+ language: import_zod5.z.string().min(2).max(2).optional(),
635
+ continent: continentEnum.optional(),
636
+ region: regionEnum.optional(),
637
+ country: import_zod5.z.string().optional(),
638
+ sector: import_zod5.z.string().optional(),
639
+ industryGroup: import_zod5.z.string().optional(),
640
+ industry: import_zod5.z.string().optional(),
641
+ subIndustry: import_zod5.z.string().optional(),
642
+ iabTier1: import_zod5.z.string().optional(),
643
+ iabTier2: import_zod5.z.string().optional(),
644
+ iabTier3: import_zod5.z.string().optional(),
645
+ iabTier4: import_zod5.z.string().optional(),
646
+ companies: import_zod5.z.array(import_zod5.z.string()).max(30).optional()
647
+ });
648
+ var clientDefaultSearchParamsSchema = userSearchParamsSchema.omit({
649
+ question: true
650
+ });
651
+ var similarUserSearchParams = userSearchParamsSchema.omit({
652
+ question: true
653
+ });
654
+
655
+ class Search {
656
+ question;
657
+ nResults;
658
+ expansions;
659
+ autoGenerateExpansions;
660
+ nProbes;
661
+ nContextify;
662
+ algorithm;
663
+ sqlFilter;
664
+ minSimilarity;
665
+ mustInclude;
666
+ mustExclude;
667
+ brandSafety;
668
+ language;
669
+ continent;
670
+ region;
671
+ country;
672
+ sector;
673
+ industryGroup;
674
+ industry;
675
+ subIndustry;
676
+ iabTier1;
677
+ iabTier2;
678
+ iabTier3;
679
+ iabTier4;
680
+ companies;
681
+ publishStart;
682
+ publishEnd;
683
+ visitedStart;
684
+ visitedEnd;
685
+ certain;
686
+ includeNetlocs;
687
+ excludeNetlocs;
688
+ includeCompanies;
689
+ excludeCompanies;
690
+ includeDocs;
691
+ excludeDocs;
692
+ constructor(params) {
693
+ Object.assign(this, params);
694
+ }
695
+ searchBody = async ({
696
+ client
697
+ }) => {
698
+ let expansions = this.expansions;
699
+ if (this.autoGenerateExpansions) {
700
+ expansions = await generateExpansions({
701
+ question: this.question,
702
+ model: client.expansionsModel,
703
+ llmClient: client.llmClient
704
+ });
705
+ }
706
+ let sqlFilter = generateSqlFilter({
707
+ publishStart: this.publishStart || undefined,
708
+ publishEnd: this.publishEnd || undefined,
709
+ visitedStart: this.visitedStart || undefined,
710
+ visitedEnd: this.visitedEnd || undefined,
711
+ certain: this.certain || undefined,
712
+ includeNetlocs: this.includeNetlocs || undefined,
713
+ excludeNetlocs: this.excludeNetlocs || undefined,
714
+ includeCompanies: this.includeCompanies || undefined,
715
+ excludeCompanies: this.excludeCompanies || undefined,
716
+ includeDocs: this.includeDocs || undefined,
717
+ excludeDocs: this.excludeDocs || undefined
718
+ });
719
+ const output = {
720
+ question: this.question,
721
+ expansions,
722
+ sql_filter: sqlFilter || undefined,
723
+ algorithm: this.algorithm,
724
+ n_probes: this.nProbes,
725
+ n_results: this.nResults,
726
+ n_contextify: this.nContextify,
727
+ min_similarity: this.minSimilarity,
728
+ must_include: this.mustInclude,
729
+ must_exclude: this.mustExclude,
730
+ brand_safety: this.brandSafety,
731
+ language: this.language,
732
+ continent: this.continent,
733
+ region: this.region,
734
+ country: this.country,
735
+ sector: this.sector,
736
+ industry_group: this.industryGroup,
737
+ industry: this.industry,
738
+ sub_industry: this.subIndustry,
739
+ iab_tier_1: this.iabTier1,
740
+ iab_tier_2: this.iabTier2,
741
+ iab_tier_3: this.iabTier3,
742
+ iab_tier_4: this.iabTier4,
743
+ companies: this.companies
744
+ };
745
+ const outputWithoutUndefined = Object.fromEntries(Object.entries(output).filter(([, value]) => value !== undefined));
746
+ return outputWithoutUndefined;
747
+ };
748
+ }
749
+
750
+ // src/utils/index.ts
751
+ var isBrowser = () => {
752
+ return typeof window !== "undefined";
753
+ };
754
+
755
+ // src/utils/browser.ts
756
+ var downloadBlob = (data, mimeType, fileName) => {
757
+ const blob = new Blob([data], { type: mimeType });
758
+ const url = URL.createObjectURL(blob);
759
+ const a = document.createElement("a");
760
+ a.href = url;
761
+ a.download = fileName;
762
+ document.body.appendChild(a);
763
+ a.click();
764
+ document.body.removeChild(a);
765
+ URL.revokeObjectURL(url);
766
+ };
767
+
768
+ // src/utils/file.ts
769
+ var import_papaparse = __toESM(require("papaparse"));
770
+ var exportJson = async (data, outputPath) => {
771
+ try {
772
+ if (isBrowser()) {
773
+ const filename = outputPath.split("/").pop() || "export.json";
774
+ const jsonString = JSON.stringify(data);
775
+ const finalFilename = filename.endsWith(".json") ? filename : `${filename}.json`;
776
+ downloadBlob(jsonString, "application/json", finalFilename);
777
+ } else {
778
+ const { writeFile } = await import("node:fs/promises");
779
+ await writeFile(outputPath, JSON.stringify(data));
780
+ }
781
+ } catch (error) {
782
+ const errorMessage = error instanceof Error ? error.message : String(error);
783
+ throw new Error(`Failed to write JSON: ${errorMessage}`);
784
+ }
785
+ };
786
+ var importJson = async (options) => {
787
+ try {
788
+ if ("file" in options) {
789
+ const text = await options.file.text();
790
+ return JSON.parse(text);
791
+ } else {
792
+ if (isBrowser()) {
793
+ throw new Error("File path import is not supported in browser. Use {file: File} instead.");
794
+ }
795
+ const { readFile } = await import("node:fs/promises");
796
+ const data = await readFile(options.filePath, "utf-8");
797
+ return JSON.parse(data);
798
+ }
799
+ } catch (error) {
800
+ const errorMessage = error instanceof Error ? error.message : String(error);
801
+ throw new Error(`Failed to read JSON: ${errorMessage}`);
802
+ }
803
+ };
804
+ var importCsv = async (options) => {
805
+ try {
806
+ let csvText;
807
+ if ("file" in options) {
808
+ csvText = await options.file.text();
809
+ } else {
810
+ if (isBrowser()) {
811
+ throw new Error("File path import is not supported in browser. Use {file: File} instead.");
812
+ }
813
+ const { readFile } = await import("node:fs/promises");
814
+ csvText = await readFile(options.filePath, "utf-8");
815
+ }
816
+ if (!csvText.trim()) {
817
+ return [];
818
+ }
819
+ const result = import_papaparse.default.parse(csvText, {
820
+ header: true,
821
+ skipEmptyLines: true,
822
+ dynamicTyping: true
823
+ });
824
+ const significantErrors = result.errors.filter((error) => !error.message.includes("Unable to auto-detect delimiting character"));
825
+ if (significantErrors.length > 0) {
826
+ const errorMessages = significantErrors.map((err) => err.message).join(", ");
827
+ throw new Error(`CSV parsing errors: ${errorMessages}`);
828
+ }
829
+ return result.data;
830
+ } catch (error) {
831
+ const errorMessage = error instanceof Error ? error.message : String(error);
832
+ throw new Error(`Failed to read CSV: ${errorMessage}`);
833
+ }
834
+ };
835
+ var exportNdjson = async (data, outputPath) => {
836
+ try {
837
+ if (isBrowser()) {
838
+ const filename = outputPath.split("/").pop() || "export.ndjson";
839
+ const ndjsonString = data.map((item) => JSON.stringify(item)).join(`
840
+ `);
841
+ const finalFilename = filename.endsWith(".ndjson") ? filename : `${filename}.ndjson`;
842
+ downloadBlob(ndjsonString, "application/x-ndjson", finalFilename);
843
+ } else {
844
+ const pl = await import("nodejs-polars");
845
+ const df = pl.DataFrame(data);
846
+ await df.writeJSON(outputPath, { format: "lines" });
847
+ }
848
+ } catch (error) {
849
+ const errorMessage = error instanceof Error ? error.message : String(error);
850
+ throw new Error(`Failed to write NDJSON: ${errorMessage}`);
851
+ }
852
+ };
853
+ var exportCsv = async (data, outputPath) => {
854
+ try {
855
+ if (!Array.isArray(data) || data.length === 0) {
856
+ throw new Error("Data must be a non-empty array");
857
+ }
858
+ if (!outputPath || typeof outputPath !== "string") {
859
+ throw new Error("Output path must be a non-empty string");
860
+ }
861
+ const csvString = import_papaparse.default.unparse(data, {
862
+ header: true,
863
+ newline: `
864
+ `
865
+ });
866
+ if (isBrowser()) {
867
+ const filename = outputPath.split("/").pop() || "export.csv";
868
+ const finalFilename = filename.endsWith(".csv") ? filename : `${filename}.csv`;
869
+ downloadBlob(csvString, "text/csv", finalFilename);
870
+ } else {
871
+ const { writeFile } = await import("node:fs/promises");
872
+ await writeFile(outputPath, csvString);
873
+ }
874
+ } catch (error) {
875
+ const errorMessage = error instanceof Error ? error.message : String(error);
876
+ throw new Error(`Failed to write CSV: ${errorMessage}`);
877
+ }
878
+ };
879
+
880
+ // src/scrape/webPageData.ts
881
+ class WebPageData {
882
+ client;
883
+ data;
884
+ snippets;
885
+ page;
886
+ fullText;
887
+ metadata;
888
+ structured;
889
+ urlTree;
890
+ statistics;
891
+ constructor(client, res) {
892
+ this.client = client;
893
+ this.data = res;
894
+ this.snippets = mapSnippetToArray(res);
895
+ this.page = this.data.page;
896
+ this.fullText = this.data.full_text;
897
+ this.metadata = this.data.metadata;
898
+ this.structured = this.data.structured;
899
+ this.urlTree = this.data.url_tree;
900
+ this.statistics = this.data.statistics;
901
+ }
902
+ static async fromJson(client, inputPath) {
903
+ const data = await importJson({ filePath: inputPath });
904
+ const validData = scrapeResponseSchema.parse(data);
905
+ return new WebPageData(client, validData);
906
+ }
907
+ async writeJson(outputPath) {
908
+ return await exportJson(this.data, outputPath);
909
+ }
910
+ getSnippets() {
911
+ return this.snippets;
912
+ }
913
+ getSnippet(hashKey) {
914
+ return this.snippets.find((snippet) => snippet.url_hash === hashKey);
915
+ }
916
+ }
917
+ var mapSnippetToArray = (data) => {
918
+ const snippets = [];
919
+ const snippetKeys = Object.keys(data.snippets);
920
+ if (snippetKeys.length === 0) {
921
+ return snippets;
922
+ }
923
+ const unsortedSnippets = [];
924
+ snippetKeys.forEach((key) => {
925
+ unsortedSnippets.push(data.snippets[key]);
926
+ });
927
+ const first = unsortedSnippets.find((snippet) => snippet.prev_snippet_hash === null);
928
+ if (!first) {
929
+ throw new Error("No first snippet found");
930
+ }
931
+ snippets.push(first);
932
+ let current = first;
933
+ while (current.next_snippet_hash) {
934
+ const next = unsortedSnippets.find((snippet) => snippet.snippet_hash === current.next_snippet_hash);
935
+ if (!next) {
936
+ throw new Error("No next snippet found");
937
+ }
938
+ snippets.push(next);
939
+ current = next;
940
+ }
941
+ return snippets;
942
+ };
943
+
944
+ // src/topicTrend/topicTrend.ts
945
+ class TopicTrend {
946
+ data;
947
+ constructor(data) {
948
+ this.data = data;
949
+ }
950
+ peakDate() {
951
+ const maxValue = Math.max(...Object.values(this.data.response));
952
+ const date = Object.keys(this.data.response).find((key) => this.data.response[key] === maxValue || undefined);
953
+ if (!date) {
954
+ throw new Error("No peak date found");
955
+ }
956
+ return new Date(date);
957
+ }
958
+ }
959
+
960
+ // src/utils/userPlan.ts
961
+ var import_bottleneck = __toESM(require("bottleneck"));
962
+ var planLimits = [
963
+ {
964
+ key: "test",
965
+ name: "Test",
966
+ rateLimits: {
967
+ scrapeUrl: { minute: 60, month: 300 },
968
+ bulk: { minute: 60, month: 300 },
969
+ fast: { minute: 60, month: 3000 }
970
+ }
971
+ },
972
+ {
973
+ key: "basic",
974
+ name: "Basic",
975
+ rateLimits: {
976
+ scrapeUrl: { minute: 60, month: 1400 },
977
+ bulk: { minute: 60, month: 1400 },
978
+ fast: { minute: 60, month: 14000 }
979
+ }
980
+ },
981
+ {
982
+ key: "pro",
983
+ name: "Pro",
984
+ rateLimits: {
985
+ scrapeUrl: { minute: 60, month: 6700 },
986
+ bulk: { minute: 60, month: 6700 },
987
+ fast: { minute: 60, month: 67000 }
988
+ }
989
+ },
990
+ {
991
+ key: "pro+",
992
+ name: "Pro+",
993
+ rateLimits: {
994
+ scrapeUrl: { minute: 60, month: 32000 },
995
+ bulk: { minute: 60, month: 32000 },
996
+ fast: { minute: 60, month: 320000 }
997
+ }
998
+ },
999
+ {
1000
+ key: "bus",
1001
+ name: "Business",
1002
+ rateLimits: {
1003
+ scrapeUrl: { minute: 60, month: 200000 },
1004
+ bulk: { minute: 60, month: 200000 },
1005
+ fast: { minute: 60, month: 2000000 }
1006
+ }
1007
+ },
1008
+ {
1009
+ key: "bus+",
1010
+ name: "Business+",
1011
+ rateLimits: {
1012
+ scrapeUrl: { minute: 60, month: 500000 },
1013
+ bulk: { minute: 60, month: 500000 },
1014
+ fast: { minute: 120, month: 5000000 }
1015
+ }
1016
+ },
1017
+ {
1018
+ key: "ent",
1019
+ name: "Enterprise",
1020
+ rateLimits: {
1021
+ scrapeUrl: { minute: 60, month: 1500000 },
1022
+ bulk: { minute: 60, month: 1500000 },
1023
+ fast: { minute: 360, month: 15000000 }
1024
+ }
1025
+ },
1026
+ {
1027
+ key: "prod",
1028
+ name: "Production",
1029
+ rateLimits: {
1030
+ scrapeUrl: { minute: 60, month: 1500000 },
1031
+ bulk: { minute: 60, month: 1500000 },
1032
+ fast: { minute: 360, month: 15000000 }
1033
+ }
1034
+ },
1035
+ {
1036
+ key: "chat",
1037
+ name: "Chat",
1038
+ rateLimits: {
1039
+ scrapeUrl: { minute: 60, month: 1500000 },
1040
+ bulk: { minute: 60, month: 1500000 },
1041
+ fast: { minute: 360, month: 15000000 }
1042
+ }
1043
+ },
1044
+ {
1045
+ key: "self",
1046
+ name: "Self",
1047
+ rateLimits: {
1048
+ scrapeUrl: { minute: 6000, month: 1500000 },
1049
+ bulk: { minute: 6000, month: 1500000 },
1050
+ fast: { minute: 36000, month: 15000000 }
1051
+ }
1052
+ },
1053
+ {
1054
+ key: "cons",
1055
+ name: "Consumer",
1056
+ rateLimits: {
1057
+ scrapeUrl: { minute: 60, month: 3000 },
1058
+ bulk: { minute: 60, month: 3000 },
1059
+ fast: { minute: 120, month: 30000 }
1060
+ }
1061
+ },
1062
+ {
1063
+ key: "stup",
1064
+ name: "Startup",
1065
+ rateLimits: {
1066
+ scrapeUrl: { minute: 60, month: 30000 },
1067
+ bulk: { minute: 60, month: 30000 },
1068
+ fast: { minute: 360, month: 300000 }
1069
+ }
1070
+ },
1071
+ {
1072
+ key: "busn",
1073
+ name: "Business Network",
1074
+ rateLimits: {
1075
+ scrapeUrl: { minute: 60, month: 300000 },
1076
+ bulk: { minute: 60, month: 300000 },
1077
+ fast: { minute: 360, month: 3000000 }
1078
+ }
1079
+ }
1080
+ ];
1081
+ var getUserPlan = (apiKey) => {
1082
+ const planKey = apiKey.split("|")[0];
1083
+ const plan = planLimits.find((p) => p.key === planKey);
1084
+ if (!plan) {
1085
+ throw new Error("Invalid API key");
1086
+ }
1087
+ return plan;
1088
+ };
1089
+ var minMs = 60 * 1000;
1090
+ var monthMs = 60 * 60 * 24 * 30 * 1000;
1091
+ var getLimiters = (planKey) => {
1092
+ const plan = getUserPlan(planKey);
1093
+ const scrapeUrlMinLimiter = new import_bottleneck.default({
1094
+ reservoir: plan.rateLimits.scrapeUrl.minute,
1095
+ reservoirRefreshAmount: plan.rateLimits.scrapeUrl.minute,
1096
+ reservoirRefreshInterval: minMs
1097
+ });
1098
+ const scrapeUrlMonthLimiter = new import_bottleneck.default({
1099
+ reservoir: plan.rateLimits.scrapeUrl.month,
1100
+ reservoirRefreshAmount: plan.rateLimits.scrapeUrl.month,
1101
+ reservoirRefreshInterval: monthMs
1102
+ });
1103
+ const scrapeUrlLimiter = scrapeUrlMinLimiter.chain(scrapeUrlMonthLimiter);
1104
+ const bulkMinLimiter = new import_bottleneck.default({
1105
+ reservoir: plan.rateLimits.bulk.minute,
1106
+ reservoirRefreshAmount: plan.rateLimits.bulk.minute,
1107
+ reservoirRefreshInterval: minMs
1108
+ });
1109
+ const bulkMonthLimiter = new import_bottleneck.default({
1110
+ reservoir: plan.rateLimits.bulk.month,
1111
+ reservoirRefreshAmount: plan.rateLimits.bulk.month,
1112
+ reservoirRefreshInterval: monthMs
1113
+ });
1114
+ const bulkLimiter = bulkMinLimiter.chain(bulkMonthLimiter);
1115
+ const fastMinLimiter = new import_bottleneck.default({
1116
+ reservoir: plan.rateLimits.fast.minute,
1117
+ reservoirRefreshAmount: plan.rateLimits.fast.minute,
1118
+ reservoirRefreshInterval: minMs
1119
+ });
1120
+ const fastMonthLimiter = new import_bottleneck.default({
1121
+ reservoir: plan.rateLimits.fast.month,
1122
+ reservoirRefreshAmount: plan.rateLimits.fast.month,
1123
+ reservoirRefreshInterval: monthMs
1124
+ });
1125
+ const fastLimiter = fastMinLimiter.chain(fastMonthLimiter);
1126
+ return {
1127
+ scrapeUrl: scrapeUrlLimiter,
1128
+ bulk: bulkLimiter,
1129
+ fast: fastLimiter
1130
+ };
1131
+ };
1132
+
1133
+ // src/client.ts
1134
+ var import_openai = require("openai");
1135
+ var import_zod7 = __toESM(require("zod"));
1136
+
1137
+ // src/search/result.ts
1138
+ class Result {
1139
+ url_hash;
1140
+ url;
1141
+ netloc;
1142
+ published;
1143
+ visited;
1144
+ language;
1145
+ author;
1146
+ title;
1147
+ description;
1148
+ content;
1149
+ best_chunk;
1150
+ semantics;
1151
+ brand_safety;
1152
+ continent;
1153
+ region;
1154
+ country;
1155
+ sector;
1156
+ industry_group;
1157
+ industry;
1158
+ sub_industry;
1159
+ iab_tier_1;
1160
+ iab_tier_2;
1161
+ iab_tier_3;
1162
+ iab_tier_4;
1163
+ client;
1164
+ constructor(params) {
1165
+ this.client = params.client;
1166
+ Object.assign(this, params.result);
1167
+ }
1168
+ static fromFlatten = (client, flatten) => {
1169
+ const unflattened = {
1170
+ ...flatten,
1171
+ semantics: {
1172
+ origin_shard: flatten.origin_shard,
1173
+ chunks_total: flatten.chunks_total,
1174
+ chunks_matched: flatten.chunks_matched,
1175
+ chunks_kept: flatten.chunks_kept,
1176
+ similarity: flatten.similarity
1177
+ }
1178
+ };
1179
+ return new Result({
1180
+ client,
1181
+ result: unflattened
1182
+ });
1183
+ };
1184
+ getSentiment = async (model) => {
1185
+ if (!this.client.llmClient) {
1186
+ throw new Error("A Nosible client instance must be provided with a OpenRouter API key.");
1187
+ }
1188
+ return getSentiment({
1189
+ text: this.content,
1190
+ model,
1191
+ llmClient: this.client.llmClient
1192
+ });
1193
+ };
1194
+ getSimilar = async (params) => {
1195
+ return this.client.fastSearch({
1196
+ question: this.title,
1197
+ excludeDocs: [this.url_hash],
1198
+ ...params
1199
+ });
1200
+ };
1201
+ scrapeUrl = async () => {
1202
+ return this.client.scrapeUrl(this.url);
1203
+ };
1204
+ flatten = () => {
1205
+ return {
1206
+ url_hash: this.url_hash,
1207
+ url: this.url,
1208
+ netloc: this.netloc,
1209
+ published: this.published,
1210
+ visited: this.visited,
1211
+ language: this.language,
1212
+ author: this.author,
1213
+ title: this.title,
1214
+ description: this.description,
1215
+ content: this.content,
1216
+ best_chunk: this.best_chunk,
1217
+ origin_shard: this.semantics.origin_shard,
1218
+ chunks_total: this.semantics.chunks_total,
1219
+ chunks_matched: this.semantics.chunks_matched,
1220
+ chunks_kept: this.semantics.chunks_kept,
1221
+ similarity: this.semantics.similarity,
1222
+ brand_safety: this.brand_safety,
1223
+ continent: this.continent,
1224
+ region: this.region,
1225
+ country: this.country,
1226
+ sector: this.sector,
1227
+ industry_group: this.industry_group,
1228
+ industry: this.industry,
1229
+ sub_industry: this.sub_industry,
1230
+ iab_tier_1: this.iab_tier_1,
1231
+ iab_tier_2: this.iab_tier_2,
1232
+ iab_tier_3: this.iab_tier_3,
1233
+ iab_tier_4: this.iab_tier_4
1234
+ };
1235
+ };
1236
+ data = () => {
1237
+ return {
1238
+ url_hash: this.url_hash,
1239
+ url: this.url,
1240
+ netloc: this.netloc,
1241
+ published: this.published,
1242
+ visited: this.visited,
1243
+ language: this.language,
1244
+ author: this.author,
1245
+ title: this.title,
1246
+ description: this.description,
1247
+ content: this.content,
1248
+ best_chunk: this.best_chunk,
1249
+ brand_safety: this.brand_safety,
1250
+ continent: this.continent,
1251
+ region: this.region,
1252
+ country: this.country,
1253
+ sector: this.sector,
1254
+ industry_group: this.industry_group,
1255
+ industry: this.industry,
1256
+ sub_industry: this.sub_industry,
1257
+ iab_tier_1: this.iab_tier_1,
1258
+ iab_tier_2: this.iab_tier_2,
1259
+ iab_tier_3: this.iab_tier_3,
1260
+ iab_tier_4: this.iab_tier_4,
1261
+ semantics: this.semantics
1262
+ };
1263
+ };
1264
+ }
1265
+
1266
+ // src/search/resultSet.ts
1267
+ var import_lunr = __toESM(require("lunr"));
1268
+
1269
+ // src/search/analyze.ts
1270
+ var import_simple_statistics = require("simple-statistics");
1271
+ var analyzeResults = (results, by) => {
1272
+ switch (by) {
1273
+ case 0 /* netloc */:
1274
+ const netlocValues = results.map((r) => r.netloc);
1275
+ const netlocStats = analyzeCategorical(netlocValues);
1276
+ return netlocStats;
1277
+ case 1 /* published */:
1278
+ const publishedValues = results.map((r) => new Date(r.published));
1279
+ const publishedStats = analyzeDateByMonth(publishedValues);
1280
+ return publishedStats;
1281
+ case 2 /* visited */:
1282
+ const visitedValues = results.map((r) => new Date(r.visited));
1283
+ const visitedStats = analyzeDateByMonth(visitedValues);
1284
+ return visitedStats;
1285
+ case 3 /* author */:
1286
+ const authorValues = results.map((r) => {
1287
+ if (r.author) {
1288
+ return r.author;
1289
+ } else {
1290
+ return "Unknown Author";
1291
+ }
1292
+ });
1293
+ const authorStats = analyzeCategorical(authorValues);
1294
+ return authorStats;
1295
+ case 4 /* language */:
1296
+ const languageValues = results.map((r) => r.language);
1297
+ const languageStats = analyzeCategorical(languageValues);
1298
+ return languageStats;
1299
+ case 5 /* similarity */:
1300
+ const simValues = results.map((r) => r.semantics.similarity);
1301
+ const simStats = analyzeNumeric(simValues);
1302
+ return simStats;
1303
+ default:
1304
+ return {};
1305
+ }
1306
+ };
1307
+ var analyzeCategorical = (arr) => {
1308
+ const result = {};
1309
+ for (const v of arr) {
1310
+ if (result[v]) {
1311
+ result[v] += 1;
1312
+ } else {
1313
+ result[v] = 1;
1314
+ }
1315
+ }
1316
+ return result;
1317
+ };
1318
+ var analyzeNumeric = (arr) => {
1319
+ const meanValue = import_simple_statistics.mean(arr);
1320
+ const stdValue = import_simple_statistics.standardDeviation(arr);
1321
+ const minValue = import_simple_statistics.min(arr);
1322
+ const maxValue = import_simple_statistics.max(arr);
1323
+ const q25 = import_simple_statistics.quantile(arr, 0.25);
1324
+ const q50 = import_simple_statistics.quantile(arr, 0.5);
1325
+ const q75 = import_simple_statistics.quantile(arr, 0.75);
1326
+ return {
1327
+ count: arr.length,
1328
+ null_count: arr.filter((v) => v === null).length,
1329
+ mean: meanValue,
1330
+ std: stdValue,
1331
+ min: minValue,
1332
+ q25,
1333
+ q50,
1334
+ q75,
1335
+ max: maxValue
1336
+ };
1337
+ };
1338
+ var analyzeDateByMonth = (arr) => {
1339
+ if (!arr || arr.length === 0)
1340
+ return {};
1341
+ let minDate = null;
1342
+ let maxDate = null;
1343
+ const counts = {};
1344
+ for (const d of arr) {
1345
+ if (!(d instanceof Date))
1346
+ continue;
1347
+ const time = d.getTime();
1348
+ if (Number.isNaN(time))
1349
+ continue;
1350
+ if (!minDate || d < minDate)
1351
+ minDate = d;
1352
+ if (!maxDate || d > maxDate)
1353
+ maxDate = d;
1354
+ const key = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`;
1355
+ counts[key] = (counts[key] ?? 0) + 1;
1356
+ }
1357
+ if (!minDate || !maxDate)
1358
+ return {};
1359
+ const result = {};
1360
+ let y = minDate.getFullYear();
1361
+ let m = minDate.getMonth() + 1;
1362
+ const endY = maxDate.getFullYear();
1363
+ const endM = maxDate.getMonth() + 1;
1364
+ while (y < endY || y === endY && m <= endM) {
1365
+ const key = `${y}-${String(m).padStart(2, "0")}`;
1366
+ result[key] = counts[key] ?? 0;
1367
+ m += 1;
1368
+ if (m > 12) {
1369
+ m = 1;
1370
+ y += 1;
1371
+ }
1372
+ }
1373
+ return result;
1374
+ };
1375
+
1376
+ // src/search/resultSet.ts
1377
+ class ResultSet {
1378
+ results;
1379
+ constructor(results) {
1380
+ this.results = results;
1381
+ }
1382
+ static async fromFilePath(filePath, client) {
1383
+ if (filePath.endsWith(".json")) {
1384
+ const json = await importJson({ filePath });
1385
+ const results = json.map((result) => {
1386
+ return new Result({ client, result });
1387
+ });
1388
+ return new ResultSet(results);
1389
+ } else if (filePath.endsWith(".csv")) {
1390
+ const csv = await importCsv({ filePath });
1391
+ const results = csv.map((result) => {
1392
+ return Result.fromFlatten(client, result);
1393
+ });
1394
+ return new ResultSet(results);
1395
+ } else {
1396
+ throw new Error("Unsupported file type");
1397
+ }
1398
+ }
1399
+ static async fromFile(file, client) {
1400
+ if (file.name.endsWith(".json")) {
1401
+ const json = await importJson({ file });
1402
+ const results = json.map((result) => {
1403
+ return new Result({ client, result });
1404
+ });
1405
+ return new ResultSet(results);
1406
+ } else if (file.name.endsWith(".csv")) {
1407
+ const csv = await importCsv({ file });
1408
+ const results = csv.map((result) => {
1409
+ return new Result({ client, result });
1410
+ });
1411
+ return new ResultSet(results);
1412
+ } else {
1413
+ throw new Error("Unsupported file type");
1414
+ }
1415
+ }
1416
+ static fromResults(results, searchQuery, client) {
1417
+ const processedResults = results.map((result) => {
1418
+ if (result instanceof Result) {
1419
+ return result;
1420
+ } else {
1421
+ const fullResult = { ...searchQuery, ...result };
1422
+ return new Result({ client, result: fullResult });
1423
+ }
1424
+ });
1425
+ return new ResultSet(processedResults);
1426
+ }
1427
+ static join(resultSets) {
1428
+ const newSet = [];
1429
+ resultSets.forEach((resultSet) => newSet.push(...resultSet.results));
1430
+ return new ResultSet(newSet);
1431
+ }
1432
+ getResults = () => {
1433
+ return this.results.map((result) => result.data());
1434
+ };
1435
+ getFlattenResults = () => {
1436
+ return this.results.map((result) => result.flatten());
1437
+ };
1438
+ findInResults = (query) => {
1439
+ const results = this.results;
1440
+ const index = import_lunr.default(function() {
1441
+ this.ref("index");
1442
+ this.field("content");
1443
+ results.forEach((result, i) => {
1444
+ this.add({
1445
+ index: i,
1446
+ content: result.content
1447
+ });
1448
+ });
1449
+ });
1450
+ const hits = index.search(query);
1451
+ console.log("Number of results: " + this.results.length);
1452
+ const matchedResults = [];
1453
+ hits.forEach((hit) => {
1454
+ let index2 = Number(hit.ref);
1455
+ const found = this.results[index2];
1456
+ if (found) {
1457
+ matchedResults.push(found);
1458
+ } else {
1459
+ console.warn(`findInSearchResults: Hit not found (index ${index2})`);
1460
+ }
1461
+ });
1462
+ console.log("Number of hits: " + hits.length);
1463
+ console.log("Number of matchedResults: " + matchedResults.length);
1464
+ console.log("matchedResults: ", typeof matchedResults);
1465
+ return matchedResults;
1466
+ };
1467
+ analyze = (by) => {
1468
+ return analyzeResults(this.results, by);
1469
+ };
1470
+ toPolars = async () => {
1471
+ if (isBrowser()) {
1472
+ throw new Error("toPolars is not supported in the browser");
1473
+ } else {
1474
+ const pl = await import("nodejs-polars");
1475
+ const flattenedData = this.getFlattenResults();
1476
+ const df = pl.DataFrame(flattenedData);
1477
+ return df;
1478
+ }
1479
+ };
1480
+ writeToCsv = async (fileName) => {
1481
+ const flattenedData = this.getFlattenResults();
1482
+ await exportCsv(flattenedData, fileName);
1483
+ };
1484
+ writeToParquet = async (fileName) => {
1485
+ if (isBrowser()) {
1486
+ throw new Error("writeToParquet is not supported in the browser");
1487
+ } else {
1488
+ const pl = await import("nodejs-polars");
1489
+ const flattenedData = this.getFlattenResults();
1490
+ const df = pl.DataFrame(flattenedData);
1491
+ await df.writeParquet(fileName);
1492
+ }
1493
+ };
1494
+ writeToIpc = async (fileName) => {
1495
+ if (isBrowser()) {
1496
+ throw new Error("writeToIpc is not supported in the browser");
1497
+ } else {
1498
+ const pl = await import("nodejs-polars");
1499
+ const flattenedData = this.getFlattenResults();
1500
+ const df = pl.DataFrame(flattenedData);
1501
+ await df.writeIPC(fileName);
1502
+ }
1503
+ };
1504
+ writeToJson = async (fileName) => {
1505
+ await exportJson(this.getResults(), fileName);
1506
+ };
1507
+ writeToNdjson = async (fileName) => {
1508
+ const flattenedData = this.getFlattenResults();
1509
+ await exportNdjson(flattenedData, fileName);
1510
+ };
1511
+ }
1512
+
1513
+ // src/search/resultFactory.ts
1514
+ function createResult(client, result) {
1515
+ return new Result({ client, result });
1516
+ }
1517
+ function createResultSet(client, rawResults) {
1518
+ const resultInstances = rawResults.map((result) => createResult(client, result));
1519
+ return new ResultSet(resultInstances);
1520
+ }
1521
+
1522
+ // src/search/bulkSearch.ts
1523
+ var import_zlib = require("zlib");
1524
+
1525
+ // src/utils/fernet.ts
1526
+ var import_crypto = require("crypto");
1527
+ var fernetDecrypt = (token, key) => {
1528
+ try {
1529
+ const keyBuffer = Buffer.from(key, "base64");
1530
+ const signingKey = keyBuffer.subarray(0, 16);
1531
+ const encryptionKey = keyBuffer.subarray(16, 32);
1532
+ const hmac = token.subarray(token.length - 32);
1533
+ const payload = token.subarray(0, token.length - 32);
1534
+ const expectedHmac = import_crypto.createHmac("sha256", signingKey).update(payload).digest();
1535
+ if (!import_crypto.timingSafeEqual(hmac, expectedHmac)) {
1536
+ throw new Error("HMAC verification failed");
1537
+ }
1538
+ const version = payload[0];
1539
+ if (version !== 128) {
1540
+ throw new Error(`Unsupported Fernet version: ${version}`);
1541
+ }
1542
+ const iv = payload.subarray(9, 25);
1543
+ const ciphertext = payload.subarray(25);
1544
+ const decipher = import_crypto.createDecipheriv("aes-128-cbc", encryptionKey, iv);
1545
+ const decrypted = Buffer.concat([
1546
+ decipher.update(ciphertext),
1547
+ decipher.final()
1548
+ ]);
1549
+ return decrypted;
1550
+ } catch (error) {
1551
+ console.error("Error decrypting data:", error);
1552
+ throw error;
1553
+ }
1554
+ };
1555
+
1556
+ // src/search/bulkSearch.ts
1557
+ async function bulkSearchDownload({
1558
+ downloadFrom,
1559
+ decryptUsing
1560
+ }) {
1561
+ if (downloadFrom.includes(".zstd.")) {
1562
+ downloadFrom = downloadFrom.replace(".zstd.", ".gzip.");
1563
+ } else {
1564
+ throw new Error("Results were not retrieved from Nosible");
1565
+ }
1566
+ try {
1567
+ for (let attempt = 0;attempt < 100; attempt++) {
1568
+ const response = await fetch(downloadFrom);
1569
+ if (response.status === 200) {
1570
+ try {
1571
+ const responseData = await response.arrayBuffer();
1572
+ const encryptedData = Buffer.from(responseData);
1573
+ const tokenBuffer = Buffer.from(encryptedData.toString("utf-8"), "base64");
1574
+ const decrypted = fernetDecrypt(tokenBuffer, decryptUsing);
1575
+ const decompressed = import_zlib.gunzipSync(decrypted);
1576
+ const apiResp = JSON.parse(decompressed.toString("utf-8"));
1577
+ return apiResp;
1578
+ } catch (error) {
1579
+ console.error("Error decrypting data:", error);
1580
+ break;
1581
+ }
1582
+ }
1583
+ await new Promise((resolve) => setTimeout(resolve, 1e4));
1584
+ }
1585
+ } catch (error) {
1586
+ console.error("Error downloading data:", error);
1587
+ throw error;
1588
+ }
1589
+ }
1590
+
1591
+ // src/search/searchSet.ts
1592
+ var import_zod6 = require("zod");
1593
+ var searchSetParams = import_zod6.z.union([
1594
+ import_zod6.z.object({
1595
+ searches: import_zod6.z.array(import_zod6.z.instanceof(Search))
1596
+ }),
1597
+ import_zod6.z.array(import_zod6.z.instanceof(Search))
1598
+ ]);
1599
+
1600
+ class SearchSet {
1601
+ searches = [];
1602
+ index;
1603
+ constructor(params) {
1604
+ if (Array.isArray(params)) {
1605
+ this.searches = params;
1606
+ } else {
1607
+ this.searches = params.searches;
1608
+ }
1609
+ this.index = 0;
1610
+ }
1611
+ static async fromFilePath(filePath) {
1612
+ if (filePath.endsWith(".json")) {
1613
+ const searches = await importJson({ filePath });
1614
+ return new SearchSet(searches.map((search) => new Search(search)));
1615
+ } else if (filePath.endsWith(".csv")) {
1616
+ const searches = await importCsv({ filePath });
1617
+ return new SearchSet(searches.map((search) => new Search(search)));
1618
+ } else
1619
+ throw new Error("Unsupported file type");
1620
+ }
1621
+ static async fromFile(file) {
1622
+ if (file.name.endsWith(".json")) {
1623
+ const searches = await importJson({ file });
1624
+ return new SearchSet(searches.map((search) => new Search(search)));
1625
+ } else if (file.name.endsWith(".csv")) {
1626
+ const searches = await importCsv({ file });
1627
+ return new SearchSet(searches.map((search) => new Search(search)));
1628
+ } else
1629
+ throw new Error("Unsupported file type");
1630
+ }
1631
+ next = () => {
1632
+ this.index++;
1633
+ const search = this.searches[this.index];
1634
+ if (!search) {
1635
+ return null;
1636
+ }
1637
+ return search;
1638
+ };
1639
+ add = (search) => {
1640
+ this.searches.push(search);
1641
+ };
1642
+ remove = (index) => {
1643
+ this.searches.splice(index, 1);
1644
+ };
1645
+ toPolars = async () => {
1646
+ if (isBrowser()) {
1647
+ throw new Error("toPolars is not supported in the browser");
1648
+ } else {
1649
+ const pl = await import("nodejs-polars");
1650
+ const df = pl.DataFrame(this.searches);
1651
+ return df;
1652
+ }
1653
+ };
1654
+ writeToCsv = async (fileName) => {
1655
+ await exportCsv(this.searches, fileName);
1656
+ };
1657
+ writeToJson = async (fileName) => {
1658
+ await exportJson(this.searches, fileName);
1659
+ };
1660
+ writeToNdjson = async (fileName) => {
1661
+ await exportNdjson(this.searches, fileName);
1662
+ };
1663
+ }
1664
+
1665
+ // src/client.ts
1666
+ var fastSearchesParamsSchema = import_zod7.default.union([
1667
+ userSearchParamsSchema.omit({ question: true }).extend({
1668
+ questions: import_zod7.default.array(import_zod7.default.string())
1669
+ }),
1670
+ import_zod7.default.instanceof(SearchSet)
1671
+ ]);
1672
+ var nosibleClientParams = import_zod7.default.union([
1673
+ import_zod7.default.string(),
1674
+ import_zod7.default.object({
1675
+ apiKey: import_zod7.default.string(),
1676
+ llmApiKey: import_zod7.default.string().optional(),
1677
+ openAiBaseURL: import_zod7.default.string().optional(),
1678
+ sentimentModel: import_zod7.default.string().optional(),
1679
+ expansionsModel: import_zod7.default.string().optional(),
1680
+ searchDefaults: clientDefaultSearchParamsSchema.optional()
1681
+ })
1682
+ ]);
1683
+
1684
+ class NosibleClient {
1685
+ baseUrl = "https://www.nosible.ai/search/v2";
1686
+ apiKey;
1687
+ llmClient;
1688
+ expansionsModel = "openai/gpt-4o";
1689
+ searchDefaults;
1690
+ plan;
1691
+ limiters;
1692
+ constructor(params) {
1693
+ let apiKeyToUse;
1694
+ let llmApiKeyToUse;
1695
+ let openAiBaseURL;
1696
+ let searchDefaultsToUse;
1697
+ if (typeof params === "string") {
1698
+ apiKeyToUse = params;
1699
+ } else if (params) {
1700
+ apiKeyToUse = params.apiKey;
1701
+ llmApiKeyToUse = params.llmApiKey;
1702
+ openAiBaseURL = params.openAiBaseURL;
1703
+ searchDefaultsToUse = params.searchDefaults;
1704
+ } else {
1705
+ apiKeyToUse = process.env.NOSIBLE_API_KEY;
1706
+ llmApiKeyToUse = process.env.LLM_API_KEY;
1707
+ }
1708
+ if (!apiKeyToUse) {
1709
+ throw new Error("API key is required");
1710
+ } else {
1711
+ this.verifyAndSetApiKey(apiKeyToUse);
1712
+ }
1713
+ if (llmApiKeyToUse) {
1714
+ this.llmClient = new import_openai.OpenAI({
1715
+ apiKey: llmApiKeyToUse,
1716
+ baseURL: openAiBaseURL
1717
+ });
1718
+ }
1719
+ this.apiKey = apiKeyToUse;
1720
+ this.searchDefaults = searchDefaultsToUse;
1721
+ this.plan = getUserPlan(this.apiKey);
1722
+ this.limiters = getLimiters(this.apiKey);
1723
+ }
1724
+ mergeWithDefaultSearch(params) {
1725
+ if (!this.searchDefaults) {
1726
+ return params;
1727
+ }
1728
+ return {
1729
+ ...this.searchDefaults,
1730
+ ...params
1731
+ };
1732
+ }
1733
+ verifyAndSetApiKey(apiKey) {
1734
+ if (!apiKey) {
1735
+ throw new Error("API key is required");
1736
+ }
1737
+ const splits = apiKey.split("|");
1738
+ if (splits.length !== 2) {
1739
+ throw new Error("API key is invalid - expected format 'key_id|secret_key'");
1740
+ }
1741
+ this.apiKey = apiKey;
1742
+ }
1743
+ async _request(endpoint, body) {
1744
+ return callNosibleApi({
1745
+ endpoint,
1746
+ body,
1747
+ apiKey: this.apiKey
1748
+ });
1749
+ }
1750
+ async fastSearch(params) {
1751
+ let search;
1752
+ const hasSearchInstance = (params2) => {
1753
+ return "search" in params2;
1754
+ };
1755
+ if (hasSearchInstance(params)) {
1756
+ if (params.search instanceof Search) {
1757
+ search = params.search;
1758
+ } else {
1759
+ throw new Error("Invalid search parameter provided.");
1760
+ }
1761
+ } else {
1762
+ const mergedParams = this.mergeWithDefaultSearch(params);
1763
+ search = new Search(mergedParams);
1764
+ }
1765
+ const body = await search.searchBody({ client: this });
1766
+ const validatedBody = validateFastSearchParams(body);
1767
+ const { message, query, response } = await this._request("fast-search", validatedBody);
1768
+ const results = response.map((result) => {
1769
+ const fullResult = { ...query, ...result };
1770
+ return fullResult;
1771
+ });
1772
+ const resultSet = createResultSet(this, results);
1773
+ return resultSet;
1774
+ }
1775
+ async fastSearches(params) {
1776
+ let searchSet;
1777
+ if (params instanceof SearchSet) {
1778
+ searchSet = params;
1779
+ } else {
1780
+ const { questions, ...sharedParams } = params;
1781
+ const mergedSharedParams = this.mergeWithDefaultSearch(sharedParams);
1782
+ const searches = questions.map((question) => new Search({ question, ...mergedSharedParams }));
1783
+ searchSet = new SearchSet(searches);
1784
+ }
1785
+ const results = await Promise.all(searchSet.searches.map((search) => this.fastSearch({ search })));
1786
+ return results;
1787
+ }
1788
+ async aiSearch(params) {
1789
+ const json = await this._request("search", params);
1790
+ const results = json.response.map((result) => {
1791
+ const fullResult = { ...json.query, ...result };
1792
+ return fullResult;
1793
+ });
1794
+ const resultSet = createResultSet(this, results);
1795
+ return resultSet;
1796
+ }
1797
+ async bulkSearch(params) {
1798
+ let search;
1799
+ const hasSearchInstance = (params2) => {
1800
+ return "search" in params2;
1801
+ };
1802
+ if (hasSearchInstance(params)) {
1803
+ if (params.search instanceof Search) {
1804
+ search = params.search;
1805
+ } else {
1806
+ throw new Error("Invalid search parameter provided.");
1807
+ }
1808
+ } else {
1809
+ const mergedParams = this.mergeWithDefaultSearch(params);
1810
+ search = new Search(mergedParams);
1811
+ }
1812
+ const body = await search.searchBody({ client: this });
1813
+ const validatedBody = validateBulkSearchParams(body);
1814
+ const fileLocation = await this._request("bulk-search", validatedBody);
1815
+ const json = await bulkSearchDownload({
1816
+ downloadFrom: fileLocation.download_from,
1817
+ decryptUsing: fileLocation.decrypt_using
1818
+ });
1819
+ const results = json.response.map((result) => {
1820
+ const fullResult = { ...json.query, ...result };
1821
+ return fullResult;
1822
+ });
1823
+ const resultSet = createResultSet(this, results);
1824
+ return resultSet;
1825
+ }
1826
+ async scrapeUrl(url) {
1827
+ return this.limiters.scrapeUrl.schedule(async () => {
1828
+ const json = await this._request("scrape-url", { url });
1829
+ const webPage = new WebPageData(this, json.response);
1830
+ return webPage;
1831
+ });
1832
+ }
1833
+ async topicTrend(query, sqlFilter) {
1834
+ const body = { query, sql_filter: sqlFilter };
1835
+ const json = await this._request("topic-trend", body);
1836
+ const topicTrend = new TopicTrend(json);
1837
+ return topicTrend;
1838
+ }
1839
+ }
1840
+
1841
+ //# debugId=E7A50C56345E2B0F64756E2164756E21