@endday/search-mcp 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/index.js +4724 -0
  2. package/dist/search-mcp.js +4715 -0
  3. package/package.json +14 -14
  4. package/data/blocklist.generated.js +0 -2
  5. package/envs.js +0 -129
  6. package/index.js +0 -6
  7. package/mcp/search-mcp.js +0 -8
  8. package/src/content/extract.impl.js +0 -228
  9. package/src/content/extract.js +0 -1
  10. package/src/content/fetch.impl.js +0 -400
  11. package/src/content/fetch.js +0 -1
  12. package/src/core/crypto.js +0 -7
  13. package/src/core/errors.impl.js +0 -52
  14. package/src/core/errors.js +0 -1
  15. package/src/core/html.impl.js +0 -69
  16. package/src/core/html.js +0 -1
  17. package/src/mcp/config.js +0 -75
  18. package/src/mcp/format.js +0 -44
  19. package/src/mcp/index.js +0 -10
  20. package/src/mcp/local/content.js +0 -26
  21. package/src/mcp/local/search.js +0 -233
  22. package/src/mcp/schemas.js +0 -132
  23. package/src/mcp/server.js +0 -97
  24. package/src/mcp/tools/content.js +0 -31
  25. package/src/mcp/tools/jinaContent.js +0 -38
  26. package/src/mcp/tools/newsSearch.js +0 -22
  27. package/src/mcp/tools/webSearch.js +0 -57
  28. package/src/platform/auth.impl.js +0 -166
  29. package/src/platform/auth.js +0 -1
  30. package/src/platform/cache.impl.js +0 -166
  31. package/src/platform/cache.js +0 -1
  32. package/src/platform/health.impl.js +0 -133
  33. package/src/platform/health.js +0 -1
  34. package/src/platform/http.impl.js +0 -108
  35. package/src/platform/http.js +0 -1
  36. package/src/platform/logger.impl.js +0 -51
  37. package/src/platform/logger.js +0 -1
  38. package/src/platform/metrics.impl.js +0 -43
  39. package/src/platform/metrics.js +0 -1
  40. package/src/platform/nodeHttpClient.js +0 -104
  41. package/src/platform/rateLimit.impl.js +0 -141
  42. package/src/platform/rateLimit.js +0 -1
  43. package/src/platform/requestContext.impl.js +0 -10
  44. package/src/platform/requestContext.js +0 -1
  45. package/src/platform/session.impl.js +0 -198
  46. package/src/platform/session.js +0 -1
  47. package/src/platform/stateKv.impl.js +0 -18
  48. package/src/platform/stateKv.js +0 -1
  49. package/src/platform/tasks.impl.js +0 -17
  50. package/src/platform/tasks.js +0 -1
  51. package/src/routes/requestParams.impl.js +0 -12
  52. package/src/routes/requestParams.js +0 -1
  53. package/src/search/engineRegistry.impl.js +0 -117
  54. package/src/search/engineRegistry.js +0 -1
  55. package/src/search/engineRequest.impl.js +0 -377
  56. package/src/search/engineRequest.js +0 -1
  57. package/src/search/engineUtils.impl.js +0 -227
  58. package/src/search/engineUtils.js +0 -1
  59. package/src/search/engines/baidu.impl.js +0 -145
  60. package/src/search/engines/baidu.js +0 -2
  61. package/src/search/engines/bing.impl.js +0 -509
  62. package/src/search/engines/bing.js +0 -2
  63. package/src/search/engines/brave.impl.js +0 -223
  64. package/src/search/engines/brave.js +0 -2
  65. package/src/search/engines/duckduckgo.impl.js +0 -164
  66. package/src/search/engines/duckduckgo.js +0 -2
  67. package/src/search/engines/mojeek.impl.js +0 -115
  68. package/src/search/engines/mojeek.js +0 -2
  69. package/src/search/engines/qwant.impl.js +0 -188
  70. package/src/search/engines/qwant.js +0 -2
  71. package/src/search/engines/startpage.impl.js +0 -237
  72. package/src/search/engines/startpage.js +0 -2
  73. package/src/search/engines/toutiao.impl.js +0 -265
  74. package/src/search/engines/toutiao.js +0 -2
  75. package/src/search/engines/yahoo.impl.js +0 -379
  76. package/src/search/engines/yahoo.js +0 -2
  77. package/src/search/gateway.impl.js +0 -423
  78. package/src/search/gateway.js +0 -1
  79. package/src/search/ranking.impl.js +0 -381
  80. package/src/search/ranking.js +0 -1
  81. package/src/search/requestPolicy.impl.js +0 -137
  82. package/src/search/requestPolicy.js +0 -1
  83. package/src/search/upstreamSession.impl.js +0 -148
  84. package/src/search/upstreamSession.js +0 -1
  85. /package/{index.d.ts → dist/index.d.ts} +0 -0
@@ -1,145 +0,0 @@
1
- import { ApiError } from "../../core/errors.js";
2
- import { fetchSearchText } from "../engineRequest.js";
3
- import { ensureAbsoluteUrl, mapTimeRange, resolvePageNumber } from "../engineUtils.js";
4
- import { cleanText, parseHtml } from "../../core/html.js";
5
- import { normalizeResults } from "../ranking.js";
6
-
7
- const BAIDU_TIME_RANGE = {
8
- day: "1",
9
- week: "2",
10
- month: "3",
11
- year: "4",
12
- };
13
-
14
- function extractBaiduResultUrl(node, linkNode) {
15
- const mu = node.getAttribute("mu");
16
- if (mu) {
17
- return ensureAbsoluteUrl(mu, "https://www.baidu.com");
18
- }
19
-
20
- return ensureAbsoluteUrl(
21
- linkNode?.getAttribute("href"),
22
- "https://www.baidu.com"
23
- );
24
- }
25
-
26
- function extractBaiduTitle(node, linkNode) {
27
- const titleNode =
28
- node.querySelector("h3 a") ||
29
- node.querySelector("h3") ||
30
- linkNode;
31
-
32
- return cleanText(titleNode?.innerHTML || titleNode?.text || "");
33
- }
34
-
35
- export function parseBaiduResults(html) {
36
- const root = parseHtml(html);
37
- const resultNodes = root.querySelectorAll(
38
- "#content_left .result, #content_left .result-op"
39
- );
40
- const results = [];
41
-
42
- for (const node of resultNodes) {
43
- const linkNode = node.querySelector("h3 a[href]");
44
- if (!linkNode) {
45
- continue;
46
- }
47
-
48
- const url = extractBaiduResultUrl(node, linkNode);
49
- if (!url || /^https?:\/\/(?:www\.)?baidu\.com\//i.test(url)) {
50
- continue;
51
- }
52
-
53
- const descriptionNode =
54
- node.querySelector('[data-sanssr-cmpt="card/www-summary"]') ||
55
- node.querySelector(".c-span-last p") ||
56
- node.querySelector(".content-right_8Zs40") ||
57
- node.querySelector(".c-color-text") ||
58
- node.querySelector(".c-line-clamp3") ||
59
- node.querySelector("p");
60
-
61
- results.push({
62
- title: extractBaiduTitle(node, linkNode),
63
- url,
64
- description: cleanText(
65
- descriptionNode?.innerHTML || descriptionNode?.text || ""
66
- ),
67
- });
68
- }
69
-
70
- const normalized = normalizeResults(results);
71
- if (normalized.length === 0) {
72
- throw new ApiError({
73
- status: 502,
74
- code: "UPSTREAM_PARSE_ERROR",
75
- category: "upstream",
76
- message: "Baidu parser could not find organic results",
77
- });
78
- }
79
-
80
- return normalized;
81
- }
82
-
83
- function buildBaiduSearchUrl({ query, time_range, pageno }) {
84
- const page = resolvePageNumber(pageno);
85
- const searchUrl = new URL("https://www.baidu.com/s");
86
- searchUrl.searchParams.set("wd", query);
87
- searchUrl.searchParams.set("ie", "utf-8");
88
- searchUrl.searchParams.set("rn", "10");
89
-
90
- if (page > 0) {
91
- searchUrl.searchParams.set("pn", String(page * 10));
92
- }
93
-
94
- const timeFilter = mapTimeRange(time_range, BAIDU_TIME_RANGE);
95
- if (timeFilter) {
96
- searchUrl.searchParams.set("gpc", `stf=${timeFilter}`);
97
- }
98
-
99
- return searchUrl;
100
- }
101
-
102
- async function searchBaidu(params) {
103
- const { query, language, time_range, pageno, signal, runtimeContext } = params;
104
- const searchUrl = buildBaiduSearchUrl({
105
- query,
106
- time_range,
107
- pageno,
108
- });
109
-
110
- const html = await fetchSearchText(searchUrl.toString(), {
111
- engine: "baidu",
112
- engineLabel: "Baidu",
113
- signal,
114
- language,
115
- cookies: {
116
- BAIDUID_BFESS: "search-mcp",
117
- PSTM: "0",
118
- },
119
- referrer: "https://www.baidu.com/",
120
- runtimeContext,
121
- blockedStatuses: [403, 429],
122
- });
123
-
124
- return parseBaiduResults(html);
125
- }
126
-
127
- export const baiduAdapter = {
128
- name: "baidu",
129
- label: "Baidu",
130
- priority: 60,
131
- tier: "primary",
132
- requestPolicy: {
133
- retryAttempts: 1,
134
- minRequestIntervalMs: 150,
135
- },
136
- supports: {
137
- language: false,
138
- time_range: true,
139
- pageno: true,
140
- },
141
- isAvailable: () => true,
142
- search: searchBaidu,
143
- };
144
-
145
- export default searchBaidu;
@@ -1,2 +0,0 @@
1
- export * from "./baidu.impl.js";
2
- export { default } from "./baidu.impl.js";
@@ -1,509 +0,0 @@
1
- import { ApiError } from "../../core/errors.js";
2
- import {
3
- fetchSearchText,
4
- isChallengeResponse,
5
- throwBlockedUpstreamError,
6
- } from "../engineRequest.js";
7
- import {
8
- ensureAbsoluteUrl,
9
- getAcceptLanguageHeader,
10
- mapLanguage,
11
- mapTimeRange,
12
- resolvePageNumber,
13
- } from "../engineUtils.js";
14
- import { cleanText, parseHtml } from "../../core/html.js";
15
- import { normalizeResults } from "../ranking.js";
16
-
17
- const BING_TIME_RANGE = {
18
- day: '+filterui:age-lt1440',
19
- week: '+filterui:age-lt10080',
20
- month: '+filterui:age-lt43200',
21
- year: '+filterui:age-lt525600',
22
- };
23
-
24
- const BING_LANGUAGE = {
25
- en: { setlang: "en-US", cc: "us", mkt: "en-US" },
26
- "en-us": { setlang: "en-US", cc: "us", mkt: "en-US" },
27
- "en-gb": { setlang: "en-GB", cc: "gb", mkt: "en-GB" },
28
- zh: { setlang: "zh-Hans", cc: "cn", mkt: "zh-CN" },
29
- "zh-cn": { setlang: "zh-Hans", cc: "cn", mkt: "zh-CN" },
30
- "zh-tw": { setlang: "zh-Hant", cc: "tw", mkt: "zh-TW" },
31
- };
32
-
33
- const XML_ENTITIES = {
34
- amp: "&",
35
- lt: "<",
36
- gt: ">",
37
- quot: '"',
38
- apos: "'",
39
- };
40
-
41
- const BING_CHALLENGE_PATTERNS = [
42
- /\bid=["']b_captcha["']\b/i,
43
- /\bb_captcha\b/i,
44
- /\/turing\//i,
45
- /\/challenge\.aspx/i,
46
- ];
47
-
48
- function decodeBase64(value) {
49
- const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
50
- const padding = "=".repeat((4 - (normalized.length % 4)) % 4);
51
- const binary = atob(normalized + padding);
52
- const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
53
- return new TextDecoder().decode(bytes);
54
- }
55
-
56
- function decodeXmlEntities(value) {
57
- return String(value || "").replace(
58
- /&(#x[0-9a-f]+|#\d+|amp|lt|gt|quot|apos);/gi,
59
- (match, entity) => {
60
- const normalized = entity.toLowerCase();
61
-
62
- if (normalized.startsWith("#")) {
63
- const isHex = normalized[1] === "x";
64
- const codePoint = Number.parseInt(
65
- normalized.slice(isHex ? 2 : 1),
66
- isHex ? 16 : 10
67
- );
68
-
69
- if (Number.isNaN(codePoint)) {
70
- return match;
71
- }
72
-
73
- try {
74
- return String.fromCodePoint(codePoint);
75
- } catch (_) {
76
- return match;
77
- }
78
- }
79
-
80
- return XML_ENTITIES[normalized] || match;
81
- }
82
- );
83
- }
84
-
85
- function isBingChallengeResponse(source) {
86
- const text = String(source || "");
87
- const hasChallengeMessage =
88
- /\bverify\s+you\s+are\s+(?:a\s+)?human\b/i.test(text) ||
89
- /\bunusual\s+traffic\b/i.test(text);
90
- const hasOrganicMarkers =
91
- /\bid=["']b_results["']/i.test(text) ||
92
- /\bb_algo\b/i.test(text) ||
93
- /<main\b/i.test(text);
94
-
95
- return (
96
- isChallengeResponse(text, BING_CHALLENGE_PATTERNS) ||
97
- (hasChallengeMessage && !hasOrganicMarkers)
98
- );
99
- }
100
-
101
- function throwBingChallengeError(surface) {
102
- throwBlockedUpstreamError({
103
- engine: "Bing",
104
- surface,
105
- });
106
- }
107
-
108
- export function extractBingRedirectUrl(bingUrl) {
109
- if (!bingUrl || !bingUrl.includes("bing.com/ck/a?")) {
110
- return bingUrl;
111
- }
112
-
113
- try {
114
- const decodedUrl = bingUrl.replace(/&amp;/g, "&");
115
- const url = new URL(decodedUrl);
116
- const uParam = url.searchParams.get("u");
117
-
118
- if (!uParam?.startsWith("a1")) {
119
- return bingUrl;
120
- }
121
-
122
- return decodeBase64(uParam.slice(2));
123
- } catch (_) {
124
- return bingUrl;
125
- }
126
- }
127
-
128
- export function extractBingNewsRedirectUrl(bingUrl) {
129
- if (!bingUrl || !bingUrl.includes("bing.com/news/apiclick.aspx?")) {
130
- return extractBingRedirectUrl(bingUrl);
131
- }
132
-
133
- try {
134
- const decodedUrl = bingUrl.replace(/&amp;/g, "&");
135
- const url = new URL(decodedUrl);
136
- const target = url.searchParams.get("url");
137
- return target ? decodeURIComponent(target) : bingUrl;
138
- } catch (_) {
139
- return bingUrl;
140
- }
141
- }
142
-
143
- export function parseBingResults(html) {
144
- if (isBingChallengeResponse(html)) {
145
- throwBingChallengeError("html");
146
- }
147
-
148
- const root = parseHtml(html);
149
- const candidateNodes = collectBingResultNodes(root);
150
- const results = [];
151
-
152
- for (const node of candidateNodes) {
153
- const linkNode = node.querySelector("h2 a[href]");
154
- if (!linkNode) {
155
- continue;
156
- }
157
-
158
- const title = cleanText(linkNode.innerHTML || linkNode.text);
159
- const rawUrl = ensureAbsoluteUrl(
160
- linkNode.getAttribute("href"),
161
- "https://www.bing.com"
162
- );
163
- const url = extractBingRedirectUrl(rawUrl);
164
- const descriptionNode =
165
- node.querySelector(".b_caption p") ||
166
- node.querySelector(".b_snippet") ||
167
- node.querySelector("p");
168
- const description = cleanText(
169
- descriptionNode?.innerHTML || descriptionNode?.text || ""
170
- );
171
-
172
- results.push({
173
- title,
174
- url,
175
- description,
176
- });
177
- }
178
-
179
- if (results.length === 0) {
180
- const fallbackLinkCount = root.querySelectorAll("main h2 a[href]").length;
181
- throw new ApiError({
182
- status: 502,
183
- code: "UPSTREAM_PARSE_ERROR",
184
- category: "upstream",
185
- message: `Bing parser could not find organic results (h2_links=${fallbackLinkCount})`,
186
- });
187
- }
188
-
189
- return normalizeResults(results);
190
- }
191
-
192
- function extractXmlTagContent(source, tagName) {
193
- const match = source.match(new RegExp(`<${tagName}[^>]*>([\\s\\S]*?)</${tagName}>`, "i"));
194
- if (!match) {
195
- return "";
196
- }
197
-
198
- return match[1]
199
- .replace(/<!\[CDATA\[([\s\S]*?)\]\]>/gi, "$1")
200
- .trim();
201
- }
202
-
203
- export function parseBingRssResults(xml) {
204
- if (isBingChallengeResponse(xml)) {
205
- throwBingChallengeError("rss");
206
- }
207
-
208
- const items = [...xml.matchAll(/<item\b[^>]*>([\s\S]*?)<\/item>/gi)];
209
- const results = normalizeResults(
210
- items.map((item) => {
211
- const source = item[1];
212
-
213
- return {
214
- title: cleanText(extractXmlTagContent(source, "title")),
215
- url: extractBingRedirectUrl(
216
- decodeXmlEntities(extractXmlTagContent(source, "link"))
217
- ),
218
- description: cleanText(extractXmlTagContent(source, "description")),
219
- };
220
- })
221
- );
222
-
223
- if (items.length === 0 || results.length === 0) {
224
- throw new ApiError({
225
- status: 502,
226
- code: "UPSTREAM_PARSE_ERROR",
227
- category: "upstream",
228
- message: `Bing RSS parser could not find valid results (items=${items.length}, normalized=${results.length})`,
229
- });
230
- }
231
-
232
- return results;
233
- }
234
-
235
- export function parseBingNewsRssResults(xml) {
236
- if (isBingChallengeResponse(xml)) {
237
- throwBingChallengeError("rss");
238
- }
239
-
240
- const items = [...xml.matchAll(/<item\b[^>]*>([\s\S]*?)<\/item>/gi)];
241
- const results = normalizeResults(
242
- items.map((item) => {
243
- const source = item[1];
244
-
245
- return {
246
- title: cleanText(extractXmlTagContent(source, "title")),
247
- url: extractBingNewsRedirectUrl(
248
- decodeXmlEntities(extractXmlTagContent(source, "link"))
249
- ),
250
- description: cleanText(extractXmlTagContent(source, "description")),
251
- published_text: cleanText(extractXmlTagContent(source, "pubDate")),
252
- source_name: cleanText(extractXmlTagContent(source, "News:Source")),
253
- };
254
- })
255
- );
256
-
257
- if (items.length === 0 || results.length === 0) {
258
- throw new ApiError({
259
- status: 502,
260
- code: "UPSTREAM_PARSE_ERROR",
261
- category: "upstream",
262
- message: `Bing News RSS parser could not find valid results (items=${items.length}, normalized=${results.length})`,
263
- });
264
- }
265
-
266
- return results;
267
- }
268
-
269
- function isBingNoiseNode(node) {
270
- let current = node;
271
-
272
- while (current) {
273
- const id = current.getAttribute?.("id") || "";
274
- const className = current.getAttribute?.("class") || "";
275
- const classList = className.split(/\s+/).filter(Boolean);
276
-
277
- if (
278
- id === "b_context" ||
279
- id === "b_pole" ||
280
- classList.includes("b_pag") ||
281
- classList.includes("b_ad")
282
- ) {
283
- return true;
284
- }
285
-
286
- current = current.parentNode;
287
- }
288
-
289
- return false;
290
- }
291
-
292
- function findBingResultContainer(node) {
293
- let current = node;
294
- let nearestContainer = node.parentNode || node;
295
-
296
- while (current) {
297
- if (["li", "div", "article", "section"].includes(current.rawTagName)) {
298
- nearestContainer = current;
299
- }
300
-
301
- const id = current.getAttribute?.("id") || "";
302
- if (id === "b_results" || current.rawTagName === "main") {
303
- return nearestContainer;
304
- }
305
-
306
- current = current.parentNode;
307
- }
308
-
309
- return nearestContainer;
310
- }
311
-
312
- function collectBingResultNodes(root) {
313
- const selectors = ["li.b_algo", "div.b_algo", "#b_results h2 a[href]", "main h2 a[href]"];
314
- const seenNodes = new Set();
315
- const resultNodes = [];
316
-
317
- for (const selector of selectors) {
318
- for (const node of root.querySelectorAll(selector)) {
319
- const linkNode = node.rawTagName === "a" ? node : node.querySelector("h2 a[href]");
320
- if (!linkNode || isBingNoiseNode(linkNode)) {
321
- continue;
322
- }
323
-
324
- const href = ensureAbsoluteUrl(linkNode.getAttribute("href"), "https://www.bing.com");
325
- if (!href || href.startsWith("https://www.bing.com/search?")) {
326
- continue;
327
- }
328
-
329
- const container = node.rawTagName === "a" ? findBingResultContainer(node) : node;
330
- if (!container || seenNodes.has(container)) {
331
- continue;
332
- }
333
-
334
- seenNodes.add(container);
335
- resultNodes.push(container);
336
- }
337
- }
338
-
339
- return resultNodes;
340
- }
341
-
342
- function buildBingSearchUrl({ query, language, time_range }) {
343
- const searchUrl = new URL("https://www.bing.com/search");
344
- searchUrl.searchParams.set("q", query);
345
- searchUrl.searchParams.set("pq", query);
346
- searchUrl.searchParams.set("form", "QBLH");
347
-
348
- const timeFilter = mapTimeRange(time_range, BING_TIME_RANGE);
349
- if (timeFilter) {
350
- searchUrl.searchParams.set("qft", timeFilter);
351
- }
352
-
353
- const languageConfig = mapLanguage(language, BING_LANGUAGE, null);
354
- if (languageConfig) {
355
- searchUrl.searchParams.set("setlang", languageConfig.setlang);
356
- searchUrl.searchParams.set("cc", languageConfig.cc);
357
- searchUrl.searchParams.set("mkt", languageConfig.mkt);
358
- }
359
-
360
- return searchUrl;
361
- }
362
-
363
- function buildBingRssUrl({ query, language, time_range }) {
364
- const searchUrl = buildBingSearchUrl({ query, language, time_range });
365
- searchUrl.searchParams.set("format", "rss");
366
- return searchUrl;
367
- }
368
-
369
- function buildBingNewsRssUrl({ query, language }) {
370
- const searchUrl = new URL("https://www.bing.com/news/search");
371
- searchUrl.searchParams.set("q", query);
372
- searchUrl.searchParams.set("format", "rss");
373
-
374
- const languageConfig = mapLanguage(language, BING_LANGUAGE, null);
375
- if (languageConfig) {
376
- searchUrl.searchParams.set("setlang", languageConfig.setlang);
377
- searchUrl.searchParams.set("cc", languageConfig.cc);
378
- searchUrl.searchParams.set("mkt", languageConfig.mkt);
379
- }
380
-
381
- return searchUrl;
382
- }
383
-
384
- async function fetchBingHtml(searchUrl, { signal, language, runtimeContext }) {
385
- const locale = mapLanguage(language, BING_LANGUAGE, BING_LANGUAGE.en);
386
- return fetchSearchText(searchUrl.toString(), {
387
- engine: "bing",
388
- engineLabel: "Bing",
389
- signal,
390
- language,
391
- acceptLanguage: locale
392
- ? `${locale.mkt},${locale.mkt.split("-")[0]};q=0.9,en;q=0.8`
393
- : getAcceptLanguageHeader(language),
394
- cookies: locale
395
- ? {
396
- _EDGE_CD: `m=${locale.mkt}&u=${locale.mkt}`,
397
- _EDGE_S: `mkt=${locale.mkt}&ui=${locale.setlang}`,
398
- }
399
- : undefined,
400
- runtimeContext,
401
- blockedStatuses: [403, 429],
402
- isBlocked: isBingChallengeResponse,
403
- blockedSurface: "html",
404
- });
405
- }
406
-
407
- async function fetchBingRss(searchUrl, { signal, language, runtimeContext }) {
408
- const locale = mapLanguage(language, BING_LANGUAGE, BING_LANGUAGE.en);
409
- return fetchSearchText(searchUrl.toString(), {
410
- engine: "bing",
411
- engineLabel: "Bing",
412
- signal,
413
- language,
414
- acceptLanguage: locale
415
- ? `${locale.mkt},${locale.mkt.split("-")[0]};q=0.9,en;q=0.8`
416
- : getAcceptLanguageHeader(language),
417
- cookies: locale
418
- ? {
419
- _EDGE_CD: `m=${locale.mkt}&u=${locale.mkt}`,
420
- _EDGE_S: `mkt=${locale.mkt}&ui=${locale.setlang}`,
421
- }
422
- : undefined,
423
- headers: {
424
- accept: "application/rss+xml,application/xml;q=0.9,text/xml;q=0.8,*/*;q=0.7",
425
- },
426
- runtimeContext,
427
- blockedStatuses: [403, 429],
428
- isBlocked: isBingChallengeResponse,
429
- blockedSurface: "rss",
430
- });
431
- }
432
-
433
- async function searchBing(params) {
434
- const {
435
- vertical = "web",
436
- query,
437
- language,
438
- time_range,
439
- pageno,
440
- signal,
441
- runtimeContext,
442
- } = params;
443
- const page = resolvePageNumber(pageno);
444
-
445
- if (vertical === "news") {
446
- const rssUrl = buildBingNewsRssUrl({
447
- query,
448
- language,
449
- });
450
- const rss = await fetchBingRss(rssUrl, { signal, language, runtimeContext });
451
- return parseBingNewsRssResults(rss);
452
- }
453
-
454
- if (page > 0) {
455
- throw new ApiError({
456
- status: 400,
457
- code: "UNSUPPORTED_PARAMETER",
458
- category: "validation",
459
- message: "Bing pagination is not supported",
460
- });
461
- }
462
-
463
- const searchUrl = buildBingSearchUrl({
464
- query,
465
- language,
466
- time_range,
467
- });
468
- const html = await fetchBingHtml(searchUrl, { signal, language, runtimeContext });
469
- try {
470
- return parseBingResults(html);
471
- } catch (error) {
472
- if (!(error instanceof ApiError) || error.code !== "UPSTREAM_PARSE_ERROR") {
473
- throw error;
474
- }
475
-
476
- const rssUrl = buildBingRssUrl({
477
- query,
478
- language,
479
- time_range,
480
- });
481
- const rss = await fetchBingRss(rssUrl, { signal, language, runtimeContext });
482
- return parseBingRssResults(rss);
483
- }
484
- }
485
-
486
- export const bingAdapter = {
487
- name: "bing",
488
- label: "Bing",
489
- priority: 50,
490
- tier: "primary",
491
- requestPolicy: {
492
- retryAttempts: 1,
493
- minRequestIntervalMs: 100,
494
- },
495
- supports: {
496
- verticals: ["web", "news"],
497
- language: true,
498
- time_range: true,
499
- pageno: false,
500
- news: {
501
- time_range: false,
502
- pageno: false,
503
- },
504
- },
505
- isAvailable: () => true,
506
- search: searchBing,
507
- };
508
-
509
- export default searchBing;
@@ -1,2 +0,0 @@
1
- export * from "./bing.impl.js";
2
- export { default } from "./bing.impl.js";