One fetch against a DDG endpoint with its own timeout/abort wiring.
(url: string, query: string, timeoutMs: number, outer?: AbortSignal)
| 82 | |
| 83 | /** One fetch against a DDG endpoint with its own timeout/abort wiring. */ |
| 84 | private async fetchOnce(url: string, query: string, timeoutMs: number, outer?: AbortSignal): Promise<string> { |
| 85 | const internalAbort = new AbortController(); |
| 86 | const timer = setTimeout(() => internalAbort.abort(), timeoutMs); |
| 87 | const onOuterAbort = (): void => internalAbort.abort(); |
| 88 | outer?.addEventListener('abort', onOuterAbort); |
| 89 | try { |
| 90 | const params = new URLSearchParams({ q: query, kl: 'wt-wt' }); // kl=wt-wt = world, no region bias |
| 91 | const res = await proxyFetch(url, { |
| 92 | method: 'POST', |
| 93 | headers: { |
| 94 | 'Content-Type': 'application/x-www-form-urlencoded', |
| 95 | 'User-Agent': UA, |
| 96 | 'Accept': 'text/html,application/xhtml+xml', |
| 97 | 'Accept-Language': 'en-US,en;q=0.9', |
| 98 | }, |
| 99 | body: params.toString(), |
| 100 | signal: internalAbort.signal, |
| 101 | }); |
| 102 | if (!res.ok) throw new WebSearchError(`DuckDuckGo returned HTTP ${res.status}`, this.name); |
| 103 | return await res.text(); |
| 104 | } finally { |
| 105 | clearTimeout(timer); |
| 106 | outer?.removeEventListener('abort', onOuterAbort); |
| 107 | } |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | function looksLikeBlockPage(html: string): boolean { |
no test coverage detected