nosible 0.2.13 → 0.2.16

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.
package/README.md CHANGED
@@ -30,7 +30,7 @@ bun add nosible
30
30
 
31
31
  **Requirements**:
32
32
 
33
- - Node.js 18+
33
+ - Node.js 20+
34
34
  - TypeScript 5+ (for TypeScript projects)
35
35
 
36
36
  **Dependencies**:
package/dist/index.cjs CHANGED
@@ -42,6 +42,10 @@ var __export = (target, all) => {
42
42
  // src/index.ts
43
43
  var exports_src = {};
44
44
  __export(exports_src, {
45
+ userSearchParamsSchema: () => userSearchParamsSchema,
46
+ snippetSchema: () => snippetSchema,
47
+ scrapeResponseSchema: () => scrapeResponseSchema,
48
+ scrapeFullResSchema: () => scrapeFullResSchema,
45
49
  WebPageData: () => WebPageData,
46
50
  TopicTrend: () => TopicTrend,
47
51
  SearchSet: () => SearchSet,
@@ -176,16 +180,16 @@ var snippetStatisticsSchema = import_zod2.z.object({
176
180
  images: import_zod2.z.number().optional()
177
181
  });
178
182
  var snippetSchema = import_zod2.z.object({
179
- url_hash: import_zod2.z.string(),
180
- snippet_hash: import_zod2.z.string(),
181
- prev_snippet_hash: import_zod2.z.string().nullable(),
182
- next_snippet_hash: import_zod2.z.string().nullable(),
183
- content: import_zod2.z.string(),
184
- words: import_zod2.z.string().optional(),
185
- language: import_zod2.z.string(),
186
- statistics: snippetStatisticsSchema.optional(),
187
- links: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.string()).optional(),
188
- images: import_zod2.z.array(import_zod2.z.string()).optional()
183
+ url_hash: import_zod2.z.string().describe("Hash of the URL from which the snippet was extracted"),
184
+ snippet_hash: import_zod2.z.string().describe("A unique hash for the snippet"),
185
+ prev_snippet_hash: import_zod2.z.string().nullable().describe("Hash of the previous snippet in sequence"),
186
+ next_snippet_hash: import_zod2.z.string().nullable().describe("Hash of the next snippet in sequence"),
187
+ content: import_zod2.z.string().describe("The text content of the snippet"),
188
+ words: import_zod2.z.string().optional().describe("The words in the snippet"),
189
+ language: import_zod2.z.string().describe("The language of the snippet"),
190
+ statistics: snippetStatisticsSchema.optional().describe("Statistical information about the snippet"),
191
+ links: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.string()).optional().describe("List of links associated with the snippet"),
192
+ images: import_zod2.z.array(import_zod2.z.string()).optional().describe("List of image URLs associated with the snippet")
189
193
  });
190
194
  var scrapeStatisticsSchema = import_zod2.z.object({
191
195
  snippets: import_zod2.z.number(),
@@ -252,20 +256,20 @@ var structuredSchema = import_zod2.z.object({
252
256
  });
253
257
  var urlTreeSchema = import_zod2.z.record(import_zod2.z.string(), import_zod2.z.any());
254
258
  var scrapeResponseSchema = import_zod2.z.object({
255
- request: scrapeRequestSchema,
256
- page: scrapePageSchema,
257
- statistics: scrapeStatisticsSchema,
258
- languages: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.number()),
259
- snippets: import_zod2.z.record(import_zod2.z.string(), snippetSchema),
260
- full_text: import_zod2.z.string(),
261
- metadata: metadataSchema,
262
- structured: import_zod2.z.array(structuredSchema),
263
- url_tree: urlTreeSchema
259
+ request: scrapeRequestSchema.describe("Details of the original scrape request including URL components and proxy settings"),
260
+ page: scrapePageSchema.describe("Basic page metadata like title, description, author, and dates"),
261
+ statistics: scrapeStatisticsSchema.describe("Content statistics including counts of snippets, words, characters, images, and other media"),
262
+ languages: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.number()).describe("Language detection results with language codes and confidence scores"),
263
+ snippets: import_zod2.z.record(import_zod2.z.string(), snippetSchema).describe("Page content broken into manageable snippets with metadata"),
264
+ full_text: import_zod2.z.string().describe("Complete extracted text content from the page"),
265
+ metadata: metadataSchema.describe("Additional metadata extracted from the page as key-value pairs"),
266
+ structured: import_zod2.z.array(structuredSchema).describe("Structured data extracted from the page (JSON-LD, microdata, etc.)"),
267
+ url_tree: urlTreeSchema.describe("Hierarchical structure of URLs found on the page")
264
268
  });
265
269
  var scrapeFullResSchema = import_zod2.z.object({
266
- message: import_zod2.z.string(),
267
- added_to_batch: import_zod2.z.boolean(),
268
- response: scrapeResponseSchema
270
+ message: import_zod2.z.string().describe("Status message describing the scrape operation result"),
271
+ added_to_batch: import_zod2.z.boolean().describe("Indicates if this scrape was added to a batch for processing"),
272
+ response: scrapeResponseSchema.describe("The complete scrape response containing all extracted data")
269
273
  });
270
274
 
271
275
  // src/api/schemas.ts
@@ -382,6 +386,22 @@ var bulkResSchema = import_zod3.default.object({
382
386
  decrypt_using: import_zod3.default.string(),
383
387
  download_from: import_zod3.default.string()
384
388
  });
389
+ var limitItemSchema = import_zod3.default.object({
390
+ name: import_zod3.default.string(),
391
+ query_type: import_zod3.default.string(),
392
+ duration_seconds: import_zod3.default.number(),
393
+ duration_string: import_zod3.default.string(),
394
+ limit: import_zod3.default.number(),
395
+ limited: import_zod3.default.boolean(),
396
+ remaining: import_zod3.default.number(),
397
+ period_start: import_zod3.default.string().nullable(),
398
+ period_end: import_zod3.default.string().nullable()
399
+ });
400
+ var limitsResponseSchema = import_zod3.default.object({
401
+ api_key_id: import_zod3.default.string(),
402
+ subscription_id: import_zod3.default.string(),
403
+ limits: import_zod3.default.array(limitItemSchema)
404
+ });
385
405
 
386
406
  // src/utils/llm.ts
387
407
  var defaultModel = "google/gemini-2.0-flash-001";
@@ -572,21 +592,28 @@ var callNosibleApi = async ({
572
592
  baseUrl = "https://www.nosible.ai/search/v2",
573
593
  endpoint,
574
594
  body,
575
- apiKey
595
+ apiKey,
596
+ method = "POST"
576
597
  }) => {
577
598
  const now = Date.now();
578
- console.debug("Body: ", JSON.stringify(body, null, 2));
579
- console.time(`Request-${endpoint}(${now})`);
599
+ if (method === "POST" && body && process.env.NOSIBLE_DEBUG) {
600
+ console.debug("Body: ", JSON.stringify(body, null, 2));
601
+ }
602
+ if (process.env.NOSIBLE_DEBUG) {
603
+ console.time(`Request-${endpoint}(${now})`);
604
+ }
580
605
  const response = await fetch(`${baseUrl}/${endpoint}`, {
581
- method: "POST",
606
+ method,
582
607
  headers: {
583
608
  Accept: "application/json",
584
- "Content-Type": "application/json",
609
+ ...method === "POST" ? { "Content-Type": "application/json" } : {},
585
610
  "Api-Key": `${apiKey}`
586
611
  },
587
- body: JSON.stringify(body)
612
+ ...method === "POST" && body ? { body: JSON.stringify(body) } : {}
588
613
  });
589
- console.timeEnd(`Request-${endpoint}(${now})`);
614
+ if (process.env.NOSIBLE_DEBUG) {
615
+ console.timeEnd(`Request-${endpoint}(${now})`);
616
+ }
590
617
  if (!response.ok) {
591
618
  console.error("Status: " + response.status);
592
619
  if (response.status === 401) {
@@ -911,8 +938,11 @@ class WebPageData {
911
938
  }
912
939
  static async fromJson(client, inputPath) {
913
940
  const data = await importJson({ filePath: inputPath });
914
- const validData = scrapeResponseSchema.parse(data);
915
- return new WebPageData(client, validData);
941
+ const validData = scrapeResponseSchema.safeParse(data);
942
+ if (!validData.success) {
943
+ throw new Error("Provided JSON is not a valid scrape response");
944
+ }
945
+ return new WebPageData(client, validData.data);
916
946
  }
917
947
  async writeJson(outputPath) {
918
948
  return await exportJson(this.data, outputPath);
@@ -967,175 +997,35 @@ class TopicTrend {
967
997
  }
968
998
  }
969
999
 
970
- // src/utils/userPlan.ts
1000
+ // src/utils/rateLimiters.ts
971
1001
  var import_bottleneck = __toESM(require("bottleneck"));
972
- var planLimits = [
973
- {
974
- key: "basic",
975
- name: "Legacy",
976
- rateLimits: {
977
- scrapeUrl: { minute: 60, month: 1400 },
978
- bulk: { minute: 60, month: 1400 },
979
- fast: { minute: 60, month: 14000 }
980
- }
981
- },
982
- {
983
- key: "pro",
984
- name: "Legacy",
985
- rateLimits: {
986
- scrapeUrl: { minute: 60, month: 6700 },
987
- bulk: { minute: 60, month: 6700 },
988
- fast: { minute: 60, month: 67000 }
989
- }
990
- },
991
- {
992
- key: "pro+",
993
- name: "Legacy",
994
- rateLimits: {
995
- scrapeUrl: { minute: 60, month: 32000 },
996
- bulk: { minute: 60, month: 32000 },
997
- fast: { minute: 60, month: 320000 }
998
- }
999
- },
1000
- {
1001
- key: "bus",
1002
- name: "Legacy",
1003
- rateLimits: {
1004
- scrapeUrl: { minute: 60, month: 200000 },
1005
- bulk: { minute: 60, month: 200000 },
1006
- fast: { minute: 60, month: 2000000 }
1007
- }
1008
- },
1009
- {
1010
- key: "bus+",
1011
- name: "Legacy",
1012
- rateLimits: {
1013
- scrapeUrl: { minute: 60, month: 500000 },
1014
- bulk: { minute: 60, month: 500000 },
1015
- fast: { minute: 120, month: 5000000 }
1016
- }
1017
- },
1018
- {
1019
- key: "prod",
1020
- name: "Legacy",
1021
- rateLimits: {
1022
- scrapeUrl: { minute: 60, month: 1500000 },
1023
- bulk: { minute: 60, month: 1500000 },
1024
- fast: { minute: 360, month: 15000000 }
1025
- }
1026
- },
1027
- {
1028
- key: "chat",
1029
- name: "Legacy",
1030
- rateLimits: {
1031
- scrapeUrl: { minute: 60, month: 1500000 },
1032
- bulk: { minute: 60, month: 1500000 },
1033
- fast: { minute: 360, month: 15000000 }
1034
- }
1035
- },
1036
- {
1037
- key: "self",
1038
- name: "Legacy",
1039
- rateLimits: {
1040
- scrapeUrl: { minute: 6000, month: 1500000 },
1041
- bulk: { minute: 6000, month: 1500000 },
1042
- fast: { minute: 36000, month: 15000000 }
1043
- }
1044
- },
1045
- {
1046
- key: "test",
1047
- name: "Free",
1048
- rateLimits: {
1049
- scrapeUrl: { minute: 60, month: 300 },
1050
- bulk: { minute: 60, month: 300 },
1051
- fast: { minute: 60, month: 3000 }
1052
- }
1053
- },
1054
- {
1055
- key: "cons",
1056
- name: "Consumer",
1057
- rateLimits: {
1058
- scrapeUrl: { minute: 60, month: 3000 },
1059
- bulk: { minute: 60, month: 3000 },
1060
- fast: { minute: 120, month: 30000 }
1061
- }
1062
- },
1063
- {
1064
- key: "stup",
1065
- name: "Startup",
1066
- rateLimits: {
1067
- scrapeUrl: { minute: 60, month: 30000 },
1068
- bulk: { minute: 60, month: 30000 },
1069
- fast: { minute: 360, month: 300000 }
1070
- }
1071
- },
1072
- {
1073
- key: "busn",
1074
- name: "Business",
1075
- rateLimits: {
1076
- scrapeUrl: { minute: 60, month: 300000 },
1077
- bulk: { minute: 60, month: 300000 },
1078
- fast: { minute: 360, month: 3000000 }
1079
- }
1080
- },
1081
- {
1082
- key: "ent",
1083
- name: "Enterprise",
1084
- rateLimits: {
1085
- scrapeUrl: { minute: 60, month: 1500000 },
1086
- bulk: { minute: 60, month: 1500000 },
1087
- fast: { minute: 360, month: 15000000 }
1088
- }
1089
- }
1090
- ];
1091
- var getUserPlan = (apiKey) => {
1092
- if (apiKey.split("|").length > 2) {
1093
- throw new Error("Invalid API key");
1002
+ var createChainedLimiter = (limitItems) => {
1003
+ if (limitItems.length === 0) {
1004
+ return new import_bottleneck.default;
1094
1005
  }
1095
- const planKey = apiKey.split("|")[0];
1096
- const plan = planLimits.find((p) => p.key === planKey);
1097
- if (!plan) {
1098
- throw new Error("Invalid API key");
1006
+ const sortedLimits = [...limitItems].sort((a, b) => a.duration_seconds - b.duration_seconds);
1007
+ const limiters = sortedLimits.map((limitItem) => {
1008
+ const intervalMs = limitItem.duration_seconds * 1000;
1009
+ return new import_bottleneck.default({
1010
+ reservoir: limitItem.remaining ?? limitItem.limit,
1011
+ reservoirRefreshAmount: limitItem.limit,
1012
+ reservoirRefreshInterval: intervalMs
1013
+ });
1014
+ });
1015
+ let chainedLimiter = limiters[0];
1016
+ for (let i = 1;i < limiters.length; i++) {
1017
+ chainedLimiter = chainedLimiter.chain(limiters[i]);
1099
1018
  }
1100
- return plan;
1019
+ return chainedLimiter;
1101
1020
  };
1102
- var minMs = 60 * 1000;
1103
- var monthMs = 60 * 60 * 24 * 30 * 1000;
1104
- var getLimiters = (planKey) => {
1105
- const plan = getUserPlan(planKey);
1106
- const scrapeUrlMinLimiter = new import_bottleneck.default({
1107
- reservoir: plan.rateLimits.scrapeUrl.minute,
1108
- reservoirRefreshAmount: plan.rateLimits.scrapeUrl.minute,
1109
- reservoirRefreshInterval: minMs
1110
- });
1111
- const scrapeUrlMonthLimiter = new import_bottleneck.default({
1112
- reservoir: plan.rateLimits.scrapeUrl.month,
1113
- reservoirRefreshAmount: plan.rateLimits.scrapeUrl.month,
1114
- reservoirRefreshInterval: monthMs
1115
- });
1116
- const scrapeUrlLimiter = scrapeUrlMinLimiter.chain(scrapeUrlMonthLimiter);
1117
- const bulkMinLimiter = new import_bottleneck.default({
1118
- reservoir: plan.rateLimits.bulk.minute,
1119
- reservoirRefreshAmount: plan.rateLimits.bulk.minute,
1120
- reservoirRefreshInterval: minMs
1121
- });
1122
- const bulkMonthLimiter = new import_bottleneck.default({
1123
- reservoir: plan.rateLimits.bulk.month,
1124
- reservoirRefreshAmount: plan.rateLimits.bulk.month,
1125
- reservoirRefreshInterval: monthMs
1126
- });
1127
- const bulkLimiter = bulkMinLimiter.chain(bulkMonthLimiter);
1128
- const fastMinLimiter = new import_bottleneck.default({
1129
- reservoir: plan.rateLimits.fast.minute,
1130
- reservoirRefreshAmount: plan.rateLimits.fast.minute,
1131
- reservoirRefreshInterval: minMs
1132
- });
1133
- const fastMonthLimiter = new import_bottleneck.default({
1134
- reservoir: plan.rateLimits.fast.month,
1135
- reservoirRefreshAmount: plan.rateLimits.fast.month,
1136
- reservoirRefreshInterval: monthMs
1137
- });
1138
- const fastLimiter = fastMinLimiter.chain(fastMonthLimiter);
1021
+ var createLimiters = (limitsResponse) => {
1022
+ const { limits } = limitsResponse;
1023
+ const visitLimits = limits.filter((l) => l.query_type === "visit");
1024
+ const slowLimits = limits.filter((l) => l.query_type === "slow");
1025
+ const fastLimits = limits.filter((l) => l.query_type === "fast");
1026
+ const scrapeUrlLimiter = createChainedLimiter(visitLimits);
1027
+ const bulkLimiter = createChainedLimiter(slowLimits);
1028
+ const fastLimiter = createChainedLimiter(fastLimits);
1139
1029
  return {
1140
1030
  scrapeUrl: scrapeUrlLimiter,
1141
1031
  bulk: bulkLimiter,
@@ -1701,23 +1591,26 @@ var nosibleClientParams = import_zod7.default.union([
1701
1591
  openAiBaseURL: import_zod7.default.string().optional(),
1702
1592
  sentimentModel: import_zod7.default.string().optional(),
1703
1593
  expansionsModel: import_zod7.default.string().optional(),
1704
- searchDefaults: clientDefaultSearchParamsSchema.optional()
1594
+ searchDefaults: clientDefaultSearchParamsSchema.optional(),
1595
+ rateLimit: import_zod7.default.boolean().optional()
1705
1596
  })
1706
1597
  ]);
1707
1598
 
1708
1599
  class NosibleClient {
1709
1600
  baseUrl = "https://www.nosible.ai/search/v2";
1710
1601
  apiKey;
1602
+ api_key_version;
1711
1603
  llmClient;
1712
1604
  expansionsModel = "openai/gpt-4o";
1713
1605
  searchDefaults;
1714
- plan;
1606
+ rateLimit = true;
1715
1607
  limiters;
1716
1608
  constructor(params) {
1717
1609
  let apiKeyToUse;
1718
1610
  let llmApiKeyToUse;
1719
1611
  let openAiBaseURL;
1720
1612
  let searchDefaultsToUse;
1613
+ let rateLimitToUse = true;
1721
1614
  if (typeof params === "string") {
1722
1615
  apiKeyToUse = params;
1723
1616
  } else if (params) {
@@ -1725,6 +1618,7 @@ class NosibleClient {
1725
1618
  llmApiKeyToUse = params.llmApiKey || process.env.LLM_API_KEY;
1726
1619
  openAiBaseURL = params.openAiBaseURL;
1727
1620
  searchDefaultsToUse = params.searchDefaults;
1621
+ rateLimitToUse = params.rateLimit ?? false;
1728
1622
  } else {
1729
1623
  apiKeyToUse = process.env.NOSIBLE_API_KEY;
1730
1624
  llmApiKeyToUse = process.env.LLM_API_KEY;
@@ -1742,8 +1636,7 @@ class NosibleClient {
1742
1636
  }
1743
1637
  this.apiKey = apiKeyToUse;
1744
1638
  this.searchDefaults = searchDefaultsToUse;
1745
- this.plan = getUserPlan(this.apiKey);
1746
- this.limiters = getLimiters(this.apiKey);
1639
+ this.rateLimit = rateLimitToUse;
1747
1640
  }
1748
1641
  mergeWithDefaultSearch(params) {
1749
1642
  if (!this.searchDefaults) {
@@ -1758,43 +1651,70 @@ class NosibleClient {
1758
1651
  if (!apiKey) {
1759
1652
  throw new Error("API key is required");
1760
1653
  }
1654
+ if (apiKey.startsWith("nos_sk_")) {
1655
+ this.api_key_version = "v2";
1656
+ this.apiKey = apiKey;
1657
+ return;
1658
+ }
1761
1659
  const splits = apiKey.split("|");
1762
1660
  if (splits.length !== 2) {
1763
- throw new Error("API key is invalid - expected format 'key_id|secret_key'");
1661
+ throw new Error("API key is invalid - expected format 'plan_id|secret_key' (v1) or 'nos_sk_...' (v2)");
1764
1662
  }
1663
+ this.api_key_version = "v1";
1765
1664
  this.apiKey = apiKey;
1766
1665
  }
1767
- async _request(endpoint, body) {
1666
+ async _request(endpoint, body, method = "POST") {
1768
1667
  return callNosibleApi({
1769
1668
  endpoint,
1770
1669
  body,
1771
- apiKey: this.apiKey
1670
+ apiKey: this.apiKey,
1671
+ method
1772
1672
  });
1773
1673
  }
1674
+ async _initializeLimiters() {
1675
+ if (!this.rateLimit || this.limiters) {
1676
+ return;
1677
+ }
1678
+ const limitsResponse = await this.limits();
1679
+ this.limiters = createLimiters(limitsResponse);
1680
+ }
1681
+ async limits() {
1682
+ const response = await this._request("limits", undefined, "GET");
1683
+ return response;
1684
+ }
1774
1685
  async fastSearch(params) {
1775
- let search;
1776
- const hasSearchInstance = (params2) => {
1777
- return "search" in params2;
1778
- };
1779
- if (hasSearchInstance(params)) {
1780
- if (params.search instanceof Search) {
1781
- search = params.search;
1686
+ if (this.rateLimit && !this.limiters) {
1687
+ await this._initializeLimiters();
1688
+ }
1689
+ const executeSearch = async () => {
1690
+ let search;
1691
+ const hasSearchInstance = (params2) => {
1692
+ return "search" in params2;
1693
+ };
1694
+ if (hasSearchInstance(params)) {
1695
+ if (params.search instanceof Search) {
1696
+ search = params.search;
1697
+ } else {
1698
+ throw new Error("Invalid search parameter provided.");
1699
+ }
1782
1700
  } else {
1783
- throw new Error("Invalid search parameter provided.");
1701
+ const mergedParams = this.mergeWithDefaultSearch(params);
1702
+ search = new Search(mergedParams);
1784
1703
  }
1785
- } else {
1786
- const mergedParams = this.mergeWithDefaultSearch(params);
1787
- search = new Search(mergedParams);
1704
+ const body = await search.searchBody({ client: this });
1705
+ const validatedBody = validateFastSearchParams(body);
1706
+ const { message, query, response } = await this._request("fast-search", validatedBody);
1707
+ const results = response.map((result) => {
1708
+ const fullResult = { ...query, ...result };
1709
+ return fullResult;
1710
+ });
1711
+ const resultSet = createResultSet(this, results);
1712
+ return resultSet;
1713
+ };
1714
+ if (this.rateLimit && this.limiters) {
1715
+ return this.limiters.fast.schedule(executeSearch);
1788
1716
  }
1789
- const body = await search.searchBody({ client: this });
1790
- const validatedBody = validateFastSearchParams(body);
1791
- const { message, query, response } = await this._request("fast-search", validatedBody);
1792
- const results = response.map((result) => {
1793
- const fullResult = { ...query, ...result };
1794
- return fullResult;
1795
- });
1796
- const resultSet = createResultSet(this, results);
1797
- return resultSet;
1717
+ return executeSearch();
1798
1718
  }
1799
1719
  async fastSearches(params) {
1800
1720
  let searchSet;
@@ -1810,49 +1730,74 @@ class NosibleClient {
1810
1730
  return results;
1811
1731
  }
1812
1732
  async aiSearch(params) {
1813
- const json = await this._request("search", params);
1814
- const results = json.response.map((result) => {
1815
- const fullResult = { ...json.query, ...result };
1816
- return fullResult;
1817
- });
1818
- const resultSet = createResultSet(this, results);
1819
- return resultSet;
1733
+ if (this.rateLimit && !this.limiters) {
1734
+ await this._initializeLimiters();
1735
+ }
1736
+ const executeSearch = async () => {
1737
+ const json = await this._request("search", params);
1738
+ const results = json.response.map((result) => {
1739
+ const fullResult = { ...json.query, ...result };
1740
+ return fullResult;
1741
+ });
1742
+ const resultSet = createResultSet(this, results);
1743
+ return resultSet;
1744
+ };
1745
+ if (this.rateLimit && this.limiters) {
1746
+ return this.limiters.fast.schedule(executeSearch);
1747
+ }
1748
+ return executeSearch();
1820
1749
  }
1821
1750
  async bulkSearch(params) {
1822
- let search;
1823
- const hasSearchInstance = (params2) => {
1824
- return "search" in params2;
1825
- };
1826
- if (hasSearchInstance(params)) {
1827
- if (params.search instanceof Search) {
1828
- search = params.search;
1751
+ if (this.rateLimit && !this.limiters) {
1752
+ await this._initializeLimiters();
1753
+ }
1754
+ const executeSearch = async () => {
1755
+ let search;
1756
+ const hasSearchInstance = (params2) => {
1757
+ return "search" in params2;
1758
+ };
1759
+ if (hasSearchInstance(params)) {
1760
+ if (params.search instanceof Search) {
1761
+ search = params.search;
1762
+ } else {
1763
+ throw new Error("Invalid search parameter provided.");
1764
+ }
1829
1765
  } else {
1830
- throw new Error("Invalid search parameter provided.");
1766
+ const mergedParams = this.mergeWithDefaultSearch(params);
1767
+ search = new Search(mergedParams);
1831
1768
  }
1832
- } else {
1833
- const mergedParams = this.mergeWithDefaultSearch(params);
1834
- search = new Search(mergedParams);
1769
+ const body = await search.searchBody({ client: this });
1770
+ const validatedBody = validateBulkSearchParams(body);
1771
+ const fileLocation = await this._request("bulk-search", validatedBody);
1772
+ const json = await bulkSearchDownload({
1773
+ downloadFrom: fileLocation.download_from,
1774
+ decryptUsing: fileLocation.decrypt_using
1775
+ });
1776
+ const results = json.response.map((result) => {
1777
+ const fullResult = { ...json.query, ...result };
1778
+ return fullResult;
1779
+ });
1780
+ const resultSet = createResultSet(this, results);
1781
+ return resultSet;
1782
+ };
1783
+ if (this.rateLimit && this.limiters) {
1784
+ return this.limiters.bulk.schedule(executeSearch);
1835
1785
  }
1836
- const body = await search.searchBody({ client: this });
1837
- const validatedBody = validateBulkSearchParams(body);
1838
- const fileLocation = await this._request("bulk-search", validatedBody);
1839
- const json = await bulkSearchDownload({
1840
- downloadFrom: fileLocation.download_from,
1841
- decryptUsing: fileLocation.decrypt_using
1842
- });
1843
- const results = json.response.map((result) => {
1844
- const fullResult = { ...json.query, ...result };
1845
- return fullResult;
1846
- });
1847
- const resultSet = createResultSet(this, results);
1848
- return resultSet;
1786
+ return executeSearch();
1849
1787
  }
1850
1788
  async scrapeUrl(url) {
1851
- return this.limiters.scrapeUrl.schedule(async () => {
1789
+ if (this.rateLimit && !this.limiters) {
1790
+ await this._initializeLimiters();
1791
+ }
1792
+ const executeScrape = async () => {
1852
1793
  const json = await this._request("scrape-url", { url });
1853
1794
  const webPage = new WebPageData(this, json.response);
1854
1795
  return webPage;
1855
- });
1796
+ };
1797
+ if (this.rateLimit && this.limiters) {
1798
+ return this.limiters.scrapeUrl.schedule(executeScrape);
1799
+ }
1800
+ return executeScrape();
1856
1801
  }
1857
1802
  async topicTrend(query, sqlFilter) {
1858
1803
  const body = { query, sql_filter: sqlFilter };
@@ -1862,4 +1807,4 @@ class NosibleClient {
1862
1807
  }
1863
1808
  }
1864
1809
 
1865
- //# debugId=88064A0B7CBC67C664756E2164756E21
1810
+ //# debugId=71464A07E20B4B6E64756E2164756E21