@endday/search-mcp 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/dist/index.js +4724 -0
  2. package/{mcp → dist}/search-mcp.js +1 -2
  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/src/content/extract.impl.js +0 -228
  8. package/src/content/extract.js +0 -1
  9. package/src/content/fetch.impl.js +0 -400
  10. package/src/content/fetch.js +0 -1
  11. package/src/core/crypto.js +0 -7
  12. package/src/core/errors.impl.js +0 -52
  13. package/src/core/errors.js +0 -1
  14. package/src/core/html.impl.js +0 -69
  15. package/src/core/html.js +0 -1
  16. package/src/mcp/config.js +0 -75
  17. package/src/mcp/format.js +0 -44
  18. package/src/mcp/index.js +0 -10
  19. package/src/mcp/local/content.js +0 -26
  20. package/src/mcp/local/search.js +0 -233
  21. package/src/mcp/schemas.js +0 -132
  22. package/src/mcp/server.js +0 -97
  23. package/src/mcp/tools/content.js +0 -31
  24. package/src/mcp/tools/jinaContent.js +0 -38
  25. package/src/mcp/tools/newsSearch.js +0 -22
  26. package/src/mcp/tools/webSearch.js +0 -57
  27. package/src/platform/auth.impl.js +0 -166
  28. package/src/platform/auth.js +0 -1
  29. package/src/platform/cache.impl.js +0 -166
  30. package/src/platform/cache.js +0 -1
  31. package/src/platform/health.impl.js +0 -133
  32. package/src/platform/health.js +0 -1
  33. package/src/platform/http.impl.js +0 -108
  34. package/src/platform/http.js +0 -1
  35. package/src/platform/logger.impl.js +0 -51
  36. package/src/platform/logger.js +0 -1
  37. package/src/platform/metrics.impl.js +0 -43
  38. package/src/platform/metrics.js +0 -1
  39. package/src/platform/nodeHttpClient.js +0 -104
  40. package/src/platform/rateLimit.impl.js +0 -141
  41. package/src/platform/rateLimit.js +0 -1
  42. package/src/platform/requestContext.impl.js +0 -10
  43. package/src/platform/requestContext.js +0 -1
  44. package/src/platform/session.impl.js +0 -198
  45. package/src/platform/session.js +0 -1
  46. package/src/platform/stateKv.impl.js +0 -18
  47. package/src/platform/stateKv.js +0 -1
  48. package/src/platform/tasks.impl.js +0 -17
  49. package/src/platform/tasks.js +0 -1
  50. package/src/routes/requestParams.impl.js +0 -12
  51. package/src/routes/requestParams.js +0 -1
  52. package/src/search/engineRegistry.impl.js +0 -117
  53. package/src/search/engineRegistry.js +0 -1
  54. package/src/search/engineRequest.impl.js +0 -377
  55. package/src/search/engineRequest.js +0 -1
  56. package/src/search/engineUtils.impl.js +0 -227
  57. package/src/search/engineUtils.js +0 -1
  58. package/src/search/engines/baidu.impl.js +0 -145
  59. package/src/search/engines/baidu.js +0 -2
  60. package/src/search/engines/bing.impl.js +0 -509
  61. package/src/search/engines/bing.js +0 -2
  62. package/src/search/engines/brave.impl.js +0 -223
  63. package/src/search/engines/brave.js +0 -2
  64. package/src/search/engines/duckduckgo.impl.js +0 -164
  65. package/src/search/engines/duckduckgo.js +0 -2
  66. package/src/search/engines/mojeek.impl.js +0 -115
  67. package/src/search/engines/mojeek.js +0 -2
  68. package/src/search/engines/qwant.impl.js +0 -188
  69. package/src/search/engines/qwant.js +0 -2
  70. package/src/search/engines/startpage.impl.js +0 -237
  71. package/src/search/engines/startpage.js +0 -2
  72. package/src/search/engines/toutiao.impl.js +0 -265
  73. package/src/search/engines/toutiao.js +0 -2
  74. package/src/search/engines/yahoo.impl.js +0 -379
  75. package/src/search/engines/yahoo.js +0 -2
  76. package/src/search/gateway.impl.js +0 -423
  77. package/src/search/gateway.js +0 -1
  78. package/src/search/ranking.impl.js +0 -381
  79. package/src/search/ranking.js +0 -1
  80. package/src/search/requestPolicy.impl.js +0 -137
  81. package/src/search/requestPolicy.js +0 -1
  82. package/src/search/upstreamSession.impl.js +0 -148
  83. package/src/search/upstreamSession.js +0 -1
  84. /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";