@debriefer/sources 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.
- package/README.md +59 -0
- package/dist/__tests__/archives/chronicling-america.test.d.ts +8 -0
- package/dist/__tests__/archives/chronicling-america.test.d.ts.map +1 -0
- package/dist/__tests__/archives/chronicling-america.test.js +151 -0
- package/dist/__tests__/archives/chronicling-america.test.js.map +1 -0
- package/dist/__tests__/archives/europeana.test.d.ts +8 -0
- package/dist/__tests__/archives/europeana.test.d.ts.map +1 -0
- package/dist/__tests__/archives/europeana.test.js +200 -0
- package/dist/__tests__/archives/europeana.test.js.map +1 -0
- package/dist/__tests__/archives/internet-archive.test.d.ts +8 -0
- package/dist/__tests__/archives/internet-archive.test.d.ts.map +1 -0
- package/dist/__tests__/archives/internet-archive.test.js +189 -0
- package/dist/__tests__/archives/internet-archive.test.js.map +1 -0
- package/dist/__tests__/archives/trove.test.d.ts +8 -0
- package/dist/__tests__/archives/trove.test.d.ts.map +1 -0
- package/dist/__tests__/archives/trove.test.js +202 -0
- package/dist/__tests__/archives/trove.test.js.map +1 -0
- package/dist/__tests__/books/google-books.test.d.ts +8 -0
- package/dist/__tests__/books/google-books.test.d.ts.map +1 -0
- package/dist/__tests__/books/google-books.test.js +221 -0
- package/dist/__tests__/books/google-books.test.js.map +1 -0
- package/dist/__tests__/books/open-library.test.d.ts +8 -0
- package/dist/__tests__/books/open-library.test.d.ts.map +1 -0
- package/dist/__tests__/books/open-library.test.js +159 -0
- package/dist/__tests__/books/open-library.test.js.map +1 -0
- package/dist/__tests__/news/guardian.test.d.ts +9 -0
- package/dist/__tests__/news/guardian.test.d.ts.map +1 -0
- package/dist/__tests__/news/guardian.test.js +224 -0
- package/dist/__tests__/news/guardian.test.js.map +1 -0
- package/dist/__tests__/news/nytimes.test.d.ts +9 -0
- package/dist/__tests__/news/nytimes.test.d.ts.map +1 -0
- package/dist/__tests__/news/nytimes.test.js +271 -0
- package/dist/__tests__/news/nytimes.test.js.map +1 -0
- package/dist/__tests__/news/site-search-source.test.d.ts +9 -0
- package/dist/__tests__/news/site-search-source.test.d.ts.map +1 -0
- package/dist/__tests__/news/site-search-source.test.js +342 -0
- package/dist/__tests__/news/site-search-source.test.js.map +1 -0
- package/dist/__tests__/obituary/find-a-grave.test.d.ts +8 -0
- package/dist/__tests__/obituary/find-a-grave.test.d.ts.map +1 -0
- package/dist/__tests__/obituary/find-a-grave.test.js +238 -0
- package/dist/__tests__/obituary/find-a-grave.test.js.map +1 -0
- package/dist/__tests__/shared/duckduckgo-search.test.d.ts +9 -0
- package/dist/__tests__/shared/duckduckgo-search.test.d.ts.map +1 -0
- package/dist/__tests__/shared/duckduckgo-search.test.js +218 -0
- package/dist/__tests__/shared/duckduckgo-search.test.js.map +1 -0
- package/dist/__tests__/shared/fetch-page.test.d.ts +9 -0
- package/dist/__tests__/shared/fetch-page.test.d.ts.map +1 -0
- package/dist/__tests__/shared/fetch-page.test.js +281 -0
- package/dist/__tests__/shared/fetch-page.test.js.map +1 -0
- package/dist/__tests__/shared/html-utils.test.d.ts +2 -0
- package/dist/__tests__/shared/html-utils.test.d.ts.map +1 -0
- package/dist/__tests__/shared/html-utils.test.js +169 -0
- package/dist/__tests__/shared/html-utils.test.js.map +1 -0
- package/dist/__tests__/shared/readability-extract.test.d.ts +2 -0
- package/dist/__tests__/shared/readability-extract.test.d.ts.map +1 -0
- package/dist/__tests__/shared/readability-extract.test.js +107 -0
- package/dist/__tests__/shared/readability-extract.test.js.map +1 -0
- package/dist/__tests__/shared/sanitize-text.test.d.ts +2 -0
- package/dist/__tests__/shared/sanitize-text.test.d.ts.map +1 -0
- package/dist/__tests__/shared/sanitize-text.test.js +77 -0
- package/dist/__tests__/shared/sanitize-text.test.js.map +1 -0
- package/dist/__tests__/shared/search-utils.test.d.ts +2 -0
- package/dist/__tests__/shared/search-utils.test.d.ts.map +1 -0
- package/dist/__tests__/shared/search-utils.test.js +26 -0
- package/dist/__tests__/shared/search-utils.test.js.map +1 -0
- package/dist/__tests__/structured/wikidata.test.d.ts +9 -0
- package/dist/__tests__/structured/wikidata.test.d.ts.map +1 -0
- package/dist/__tests__/structured/wikidata.test.js +509 -0
- package/dist/__tests__/structured/wikidata.test.js.map +1 -0
- package/dist/__tests__/structured/wikipedia.test.d.ts +9 -0
- package/dist/__tests__/structured/wikipedia.test.d.ts.map +1 -0
- package/dist/__tests__/structured/wikipedia.test.js +643 -0
- package/dist/__tests__/structured/wikipedia.test.js.map +1 -0
- package/dist/__tests__/web-search/base.test.d.ts +9 -0
- package/dist/__tests__/web-search/base.test.d.ts.map +1 -0
- package/dist/__tests__/web-search/base.test.js +622 -0
- package/dist/__tests__/web-search/base.test.js.map +1 -0
- package/dist/__tests__/web-search/bing.test.d.ts +10 -0
- package/dist/__tests__/web-search/bing.test.d.ts.map +1 -0
- package/dist/__tests__/web-search/bing.test.js +277 -0
- package/dist/__tests__/web-search/bing.test.js.map +1 -0
- package/dist/__tests__/web-search/brave.test.d.ts +10 -0
- package/dist/__tests__/web-search/brave.test.d.ts.map +1 -0
- package/dist/__tests__/web-search/brave.test.js +264 -0
- package/dist/__tests__/web-search/brave.test.js.map +1 -0
- package/dist/__tests__/web-search/duckduckgo.test.d.ts +10 -0
- package/dist/__tests__/web-search/duckduckgo.test.d.ts.map +1 -0
- package/dist/__tests__/web-search/duckduckgo.test.js +107 -0
- package/dist/__tests__/web-search/duckduckgo.test.js.map +1 -0
- package/dist/__tests__/web-search/google.test.d.ts +9 -0
- package/dist/__tests__/web-search/google.test.d.ts.map +1 -0
- package/dist/__tests__/web-search/google.test.js +189 -0
- package/dist/__tests__/web-search/google.test.js.map +1 -0
- package/dist/archives/chronicling-america.d.ts +33 -0
- package/dist/archives/chronicling-america.d.ts.map +1 -0
- package/dist/archives/chronicling-america.js +85 -0
- package/dist/archives/chronicling-america.js.map +1 -0
- package/dist/archives/europeana.d.ts +37 -0
- package/dist/archives/europeana.d.ts.map +1 -0
- package/dist/archives/europeana.js +92 -0
- package/dist/archives/europeana.js.map +1 -0
- package/dist/archives/internet-archive.d.ts +32 -0
- package/dist/archives/internet-archive.d.ts.map +1 -0
- package/dist/archives/internet-archive.js +90 -0
- package/dist/archives/internet-archive.js.map +1 -0
- package/dist/archives/trove.d.ts +37 -0
- package/dist/archives/trove.d.ts.map +1 -0
- package/dist/archives/trove.js +97 -0
- package/dist/archives/trove.js.map +1 -0
- package/dist/books/google-books.d.ts +48 -0
- package/dist/books/google-books.d.ts.map +1 -0
- package/dist/books/google-books.js +111 -0
- package/dist/books/google-books.js.map +1 -0
- package/dist/books/open-library.d.ts +44 -0
- package/dist/books/open-library.d.ts.map +1 -0
- package/dist/books/open-library.js +103 -0
- package/dist/books/open-library.js.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/news/guardian.d.ts +51 -0
- package/dist/news/guardian.d.ts.map +1 -0
- package/dist/news/guardian.js +131 -0
- package/dist/news/guardian.js.map +1 -0
- package/dist/news/nytimes.d.ts +27 -0
- package/dist/news/nytimes.d.ts.map +1 -0
- package/dist/news/nytimes.js +104 -0
- package/dist/news/nytimes.js.map +1 -0
- package/dist/news/site-search-source.d.ts +89 -0
- package/dist/news/site-search-source.d.ts.map +1 -0
- package/dist/news/site-search-source.js +182 -0
- package/dist/news/site-search-source.js.map +1 -0
- package/dist/news/sources.d.ts +52 -0
- package/dist/news/sources.d.ts.map +1 -0
- package/dist/news/sources.js +276 -0
- package/dist/news/sources.js.map +1 -0
- package/dist/obituary/find-a-grave.d.ts +43 -0
- package/dist/obituary/find-a-grave.d.ts.map +1 -0
- package/dist/obituary/find-a-grave.js +173 -0
- package/dist/obituary/find-a-grave.js.map +1 -0
- package/dist/shared/duckduckgo-search.d.ts +86 -0
- package/dist/shared/duckduckgo-search.d.ts.map +1 -0
- package/dist/shared/duckduckgo-search.js +218 -0
- package/dist/shared/duckduckgo-search.js.map +1 -0
- package/dist/shared/fetch-page.d.ts +50 -0
- package/dist/shared/fetch-page.d.ts.map +1 -0
- package/dist/shared/fetch-page.js +212 -0
- package/dist/shared/fetch-page.js.map +1 -0
- package/dist/shared/html-utils.d.ts +99 -0
- package/dist/shared/html-utils.d.ts.map +1 -0
- package/dist/shared/html-utils.js +246 -0
- package/dist/shared/html-utils.js.map +1 -0
- package/dist/shared/readability-extract.d.ts +33 -0
- package/dist/shared/readability-extract.d.ts.map +1 -0
- package/dist/shared/readability-extract.js +45 -0
- package/dist/shared/readability-extract.js.map +1 -0
- package/dist/shared/sanitize-text.d.ts +24 -0
- package/dist/shared/sanitize-text.d.ts.map +1 -0
- package/dist/shared/sanitize-text.js +49 -0
- package/dist/shared/sanitize-text.js.map +1 -0
- package/dist/shared/search-utils.d.ts +18 -0
- package/dist/shared/search-utils.d.ts.map +1 -0
- package/dist/shared/search-utils.js +20 -0
- package/dist/shared/search-utils.js.map +1 -0
- package/dist/structured/wikidata.d.ts +128 -0
- package/dist/structured/wikidata.d.ts.map +1 -0
- package/dist/structured/wikidata.js +361 -0
- package/dist/structured/wikidata.js.map +1 -0
- package/dist/structured/wikipedia.d.ts +184 -0
- package/dist/structured/wikipedia.d.ts.map +1 -0
- package/dist/structured/wikipedia.js +275 -0
- package/dist/structured/wikipedia.js.map +1 -0
- package/dist/web-search/base.d.ts +128 -0
- package/dist/web-search/base.d.ts.map +1 -0
- package/dist/web-search/base.js +251 -0
- package/dist/web-search/base.js.map +1 -0
- package/dist/web-search/bing.d.ts +21 -0
- package/dist/web-search/bing.d.ts.map +1 -0
- package/dist/web-search/bing.js +53 -0
- package/dist/web-search/bing.js.map +1 -0
- package/dist/web-search/brave.d.ts +21 -0
- package/dist/web-search/brave.d.ts.map +1 -0
- package/dist/web-search/brave.js +56 -0
- package/dist/web-search/brave.js.map +1 -0
- package/dist/web-search/duckduckgo.d.ts +15 -0
- package/dist/web-search/duckduckgo.d.ts.map +1 -0
- package/dist/web-search/duckduckgo.js +21 -0
- package/dist/web-search/duckduckgo.js.map +1 -0
- package/dist/web-search/google.d.ts +24 -0
- package/dist/web-search/google.d.ts.map +1 -0
- package/dist/web-search/google.js +48 -0
- package/dist/web-search/google.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Abstract base class for web search sources using the template method pattern.
|
|
3
|
+
*
|
|
4
|
+
* Subclasses only implement `performSearch()` — the base class handles the
|
|
5
|
+
* full pipeline: search → score/rank links → fetch pages → extract content →
|
|
6
|
+
* sanitize → combine with attribution.
|
|
7
|
+
*
|
|
8
|
+
* Used by Google, Bing, Brave, and DuckDuckGo search sources.
|
|
9
|
+
*/
|
|
10
|
+
import { BaseResearchSource, } from "@debriefer/core";
|
|
11
|
+
import { fetchPage } from "../shared/fetch-page.js";
|
|
12
|
+
import { extractArticleContent } from "../shared/readability-extract.js";
|
|
13
|
+
import { sanitizeSourceText } from "../shared/sanitize-text.js";
|
|
14
|
+
// ============================================================================
|
|
15
|
+
// WebSearchBase
|
|
16
|
+
// ============================================================================
|
|
17
|
+
/**
|
|
18
|
+
* Abstract base class for web search sources.
|
|
19
|
+
*
|
|
20
|
+
* Implements the template method pattern: subclasses provide `performSearch()`
|
|
21
|
+
* and this class handles the rest of the pipeline (scoring, fetching,
|
|
22
|
+
* extracting, sanitizing, combining).
|
|
23
|
+
*/
|
|
24
|
+
export class WebSearchBase extends BaseResearchSource {
|
|
25
|
+
maxLinksToFollow;
|
|
26
|
+
minContentLength;
|
|
27
|
+
domainScores;
|
|
28
|
+
boostKeywords;
|
|
29
|
+
penaltyKeywords;
|
|
30
|
+
blockedDomains;
|
|
31
|
+
maxLinkCost;
|
|
32
|
+
linkSelector;
|
|
33
|
+
customFetchPage;
|
|
34
|
+
constructor(options = {}) {
|
|
35
|
+
super(options);
|
|
36
|
+
this.maxLinksToFollow = options.maxLinksToFollow ?? 3;
|
|
37
|
+
this.minContentLength = options.minContentLength ?? 200;
|
|
38
|
+
this.domainScores = options.domainScores ?? {};
|
|
39
|
+
this.boostKeywords = options.boostKeywords ?? [];
|
|
40
|
+
this.penaltyKeywords = options.penaltyKeywords ?? [];
|
|
41
|
+
this.blockedDomains = options.blockedDomains ?? [];
|
|
42
|
+
this.maxLinkCost = options.maxLinkCost;
|
|
43
|
+
this.linkSelector = options.linkSelector;
|
|
44
|
+
this.customFetchPage = options.fetchPage;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Full search pipeline: search → score → fetch → extract → combine.
|
|
48
|
+
*
|
|
49
|
+
* @param subject - The research subject
|
|
50
|
+
* @param signal - Abort signal for cancellation
|
|
51
|
+
* @returns RawFinding with combined text, or null if no content extracted
|
|
52
|
+
*/
|
|
53
|
+
async fetchResult(subject, signal) {
|
|
54
|
+
// 1. Build query and perform search
|
|
55
|
+
const query = this.buildQuery(subject);
|
|
56
|
+
const searchResults = await this.performSearch(query, signal);
|
|
57
|
+
if (searchResults.length === 0) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
// 2. Filter blocked domains
|
|
61
|
+
const filtered = searchResults.filter((r) => !this.isDomainBlocked(r.url));
|
|
62
|
+
if (filtered.length === 0) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
// 3. Score & rank links
|
|
66
|
+
const ranked = this.scoreAndRank(filtered);
|
|
67
|
+
// 4. Apply custom link selector if provided, then take top N
|
|
68
|
+
let selectedResults = ranked.map((r) => r.result);
|
|
69
|
+
if (this.linkSelector) {
|
|
70
|
+
selectedResults = await this.linkSelector(selectedResults, subject);
|
|
71
|
+
}
|
|
72
|
+
const linksToFollow = selectedResults.slice(0, this.maxLinksToFollow);
|
|
73
|
+
// 5. Fetch and extract content from each page
|
|
74
|
+
const extractedPages = [];
|
|
75
|
+
let linksAttempted = 0;
|
|
76
|
+
let linkCostUsd = 0;
|
|
77
|
+
for (const result of linksToFollow) {
|
|
78
|
+
if (signal.aborted)
|
|
79
|
+
break;
|
|
80
|
+
if (this.maxLinkCost !== undefined && linkCostUsd >= this.maxLinkCost)
|
|
81
|
+
break;
|
|
82
|
+
linksAttempted++;
|
|
83
|
+
// Use custom fetch if provided, otherwise default pipeline
|
|
84
|
+
if (this.customFetchPage) {
|
|
85
|
+
const text = await this.customFetchPage(result.url, signal);
|
|
86
|
+
if (text && text.length >= this.minContentLength) {
|
|
87
|
+
extractedPages.push({
|
|
88
|
+
url: result.url,
|
|
89
|
+
title: result.title ?? result.url,
|
|
90
|
+
text,
|
|
91
|
+
});
|
|
92
|
+
linkCostUsd += this.estimatedCostPerQuery;
|
|
93
|
+
}
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const pageResult = await fetchPage({ url: result.url, signal });
|
|
97
|
+
if (pageResult.fetchMethod === "none" || !pageResult.content) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
// Use the actual fetched URL (may be archive.org URL if fallback was used)
|
|
101
|
+
const actualUrl = pageResult.url || result.url;
|
|
102
|
+
const extracted = extractArticleContent(pageResult.content, actualUrl);
|
|
103
|
+
if (!extracted) {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
// 6. Filter by minimum content length
|
|
107
|
+
if (extracted.text.length < this.minContentLength) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
extractedPages.push({
|
|
111
|
+
url: actualUrl,
|
|
112
|
+
title: extracted.title ?? result.title ?? result.url,
|
|
113
|
+
text: extracted.text,
|
|
114
|
+
});
|
|
115
|
+
linkCostUsd += this.estimatedCostPerQuery;
|
|
116
|
+
}
|
|
117
|
+
if (extractedPages.length === 0) {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
// 7. Sanitize each page's text
|
|
121
|
+
const sanitizedPages = extractedPages.map((page) => ({
|
|
122
|
+
...page,
|
|
123
|
+
text: sanitizeSourceText(page.text),
|
|
124
|
+
}));
|
|
125
|
+
// 8. Combine texts with source attribution
|
|
126
|
+
const combinedText = sanitizedPages
|
|
127
|
+
.map((page) => `${page.title}\n${page.text}`)
|
|
128
|
+
.join("\n\n---\n\n");
|
|
129
|
+
// 9. Return RawFinding
|
|
130
|
+
return {
|
|
131
|
+
text: combinedText,
|
|
132
|
+
confidence: -1,
|
|
133
|
+
costUsd: this.estimatedCostPerQuery + linkCostUsd,
|
|
134
|
+
url: extractedPages[0].url,
|
|
135
|
+
metadata: {
|
|
136
|
+
searchEngine: this.name,
|
|
137
|
+
linksFollowed: linksAttempted,
|
|
138
|
+
pagesExtracted: extractedPages.length,
|
|
139
|
+
urls: extractedPages.map((p) => p.url),
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Score and rank search results by relevance.
|
|
145
|
+
*
|
|
146
|
+
* Scoring:
|
|
147
|
+
* - Base: 50 - index (preserves search engine ordering)
|
|
148
|
+
* - + domainScores[domain] if hostname matches
|
|
149
|
+
* - + boost for each boostKeyword found in title+snippet
|
|
150
|
+
* - - penalty for each penaltyKeyword found in title+snippet
|
|
151
|
+
*/
|
|
152
|
+
scoreAndRank(results) {
|
|
153
|
+
const scored = results.map((result, index) => {
|
|
154
|
+
let score = 50 - index;
|
|
155
|
+
// Domain score bonus
|
|
156
|
+
let hostname = null;
|
|
157
|
+
try {
|
|
158
|
+
hostname = new URL(result.url).hostname;
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
// Invalid URL — skip domain scoring
|
|
162
|
+
}
|
|
163
|
+
for (const [domain, domainScore] of Object.entries(this.domainScores)) {
|
|
164
|
+
if (!hostname)
|
|
165
|
+
break;
|
|
166
|
+
if (this.hostnameMatchesDomain(hostname, domain)) {
|
|
167
|
+
score += domainScore;
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// Boost keywords
|
|
172
|
+
const combined = `${result.title} ${result.snippet}`.toLowerCase();
|
|
173
|
+
for (const { keyword, boost } of this.boostKeywords) {
|
|
174
|
+
if (combined.includes(keyword.toLowerCase())) {
|
|
175
|
+
score += boost;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// Penalty keywords
|
|
179
|
+
for (const { keyword, penalty } of this.penaltyKeywords) {
|
|
180
|
+
if (combined.includes(keyword.toLowerCase())) {
|
|
181
|
+
score -= penalty;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return { result, score };
|
|
185
|
+
});
|
|
186
|
+
// Sort by score descending
|
|
187
|
+
scored.sort((a, b) => b.score - a.score);
|
|
188
|
+
return scored;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Check whether a URL should be excluded (blocked domain or unsafe URL).
|
|
192
|
+
* Blocks: non-http(s) schemes, localhost, private IP ranges, and user-specified domains.
|
|
193
|
+
*/
|
|
194
|
+
isDomainBlocked(url) {
|
|
195
|
+
let parsed;
|
|
196
|
+
try {
|
|
197
|
+
parsed = new URL(url);
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
return true; // Unparseable URLs are blocked
|
|
201
|
+
}
|
|
202
|
+
// Only allow http and https
|
|
203
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
// Block localhost, private IPs, and link-local addresses (SSRF prevention)
|
|
207
|
+
// Normalize IPv4-mapped IPv6 (e.g., ::ffff:127.0.0.1) to plain IPv4
|
|
208
|
+
let hostname = parsed.hostname;
|
|
209
|
+
const mappedMatch = /^::ffff:(\d+\.\d+\.\d+\.\d+)$/i.exec(hostname);
|
|
210
|
+
if (mappedMatch) {
|
|
211
|
+
hostname = mappedMatch[1];
|
|
212
|
+
}
|
|
213
|
+
if (hostname === "localhost" ||
|
|
214
|
+
hostname.startsWith("127.") || // 127.0.0.0/8 loopback
|
|
215
|
+
hostname === "::1" || // IPv6 loopback
|
|
216
|
+
hostname === "[::1]" || // IPv6 loopback (bracketed form)
|
|
217
|
+
hostname.startsWith("10.") || // RFC 1918
|
|
218
|
+
hostname.startsWith("192.168.") || // RFC 1918
|
|
219
|
+
hostname.startsWith("169.254.") || // Link-local / cloud metadata (169.254.169.254)
|
|
220
|
+
hostname === "0.0.0.0" ||
|
|
221
|
+
hostname.endsWith(".local") ||
|
|
222
|
+
(hostname.includes(":") && hostname.startsWith("fc")) || // IPv6 unique local (fc00::/7)
|
|
223
|
+
(hostname.includes(":") && hostname.startsWith("fd")) || // IPv6 unique local (fc00::/7)
|
|
224
|
+
(hostname.includes(":") && hostname.startsWith("fe80")) || // IPv6 link-local (fe80::/10)
|
|
225
|
+
this.isPrivate172(hostname)) {
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
return this.blockedDomains.some((domain) => this.hostnameMatchesDomain(hostname, domain));
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Check if a hostname matches a domain (exact or subdomain match).
|
|
232
|
+
* Normalizes domain to lowercase since URL.hostname is always lowercase.
|
|
233
|
+
*
|
|
234
|
+
* "www.example.com" matches "example.com"
|
|
235
|
+
* "sub.example.com" matches "example.com"
|
|
236
|
+
* "example.com" matches "example.com"
|
|
237
|
+
* "notexample.com" does NOT match "example.com"
|
|
238
|
+
*/
|
|
239
|
+
hostnameMatchesDomain(hostname, domain) {
|
|
240
|
+
const d = domain.toLowerCase();
|
|
241
|
+
return hostname === d || hostname.endsWith("." + d);
|
|
242
|
+
}
|
|
243
|
+
/** Check if hostname is in the 172.16.0.0–172.31.255.255 private range (RFC 1918). */
|
|
244
|
+
isPrivate172(hostname) {
|
|
245
|
+
if (!hostname.startsWith("172."))
|
|
246
|
+
return false;
|
|
247
|
+
const secondOctet = parseInt(hostname.split(".")[1], 10);
|
|
248
|
+
return secondOctet >= 16 && secondOctet <= 31;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/web-search/base.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ReliabilityTier } from "@debriefer/core";
|
|
2
|
+
import { WebSearchBase, type WebSearchOptions, type WebSearchResult } from "./base.js";
|
|
3
|
+
export interface BingSearchOptions extends WebSearchOptions {
|
|
4
|
+
apiKey?: string;
|
|
5
|
+
maxResults?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class BingSearchSource extends WebSearchBase {
|
|
8
|
+
readonly name = "Bing Search";
|
|
9
|
+
readonly type = "bing-search";
|
|
10
|
+
readonly reliabilityTier = ReliabilityTier.SEARCH_AGGREGATOR;
|
|
11
|
+
readonly domain = "api.bing.microsoft.com";
|
|
12
|
+
readonly isFree = false;
|
|
13
|
+
readonly estimatedCostPerQuery = 0.003;
|
|
14
|
+
private apiKey;
|
|
15
|
+
private maxResults;
|
|
16
|
+
constructor(options?: BingSearchOptions);
|
|
17
|
+
isAvailable(): boolean;
|
|
18
|
+
protected performSearch(query: string, signal: AbortSignal): Promise<WebSearchResult[]>;
|
|
19
|
+
}
|
|
20
|
+
export declare function bingSearch(options?: BingSearchOptions): BingSearchSource;
|
|
21
|
+
//# sourceMappingURL=bing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bing.d.ts","sourceRoot":"","sources":["../../src/web-search/bing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,WAAW,CAAA;AAItF,MAAM,WAAW,iBAAkB,SAAQ,gBAAgB;IACzD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,qBAAa,gBAAiB,SAAQ,aAAa;IACjD,QAAQ,CAAC,IAAI,iBAAgB;IAC7B,QAAQ,CAAC,IAAI,iBAAgB;IAC7B,QAAQ,CAAC,eAAe,qCAAoC;IAC5D,QAAQ,CAAC,MAAM,4BAA2B;IAC1C,QAAQ,CAAC,MAAM,SAAQ;IACvB,QAAQ,CAAC,qBAAqB,SAAQ;IAEtC,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,UAAU,CAAQ;gBAEd,OAAO,GAAE,iBAAsB;IAMlC,WAAW,IAAI,OAAO;cAIf,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;CAoC9F;AAED,wBAAgB,UAAU,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,gBAAgB,CAExE"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ReliabilityTier } from "@debriefer/core";
|
|
2
|
+
import { WebSearchBase } from "./base.js";
|
|
3
|
+
const BING_SEARCH_URL = "https://api.bing.microsoft.com/v7.0/search";
|
|
4
|
+
export class BingSearchSource extends WebSearchBase {
|
|
5
|
+
name = "Bing Search";
|
|
6
|
+
type = "bing-search";
|
|
7
|
+
reliabilityTier = ReliabilityTier.SEARCH_AGGREGATOR;
|
|
8
|
+
domain = "api.bing.microsoft.com";
|
|
9
|
+
isFree = false;
|
|
10
|
+
estimatedCostPerQuery = 0.003;
|
|
11
|
+
apiKey;
|
|
12
|
+
maxResults;
|
|
13
|
+
constructor(options = {}) {
|
|
14
|
+
super({ rateLimitMs: 500, ...options });
|
|
15
|
+
this.apiKey = options.apiKey ?? process.env.BING_SEARCH_API_KEY;
|
|
16
|
+
this.maxResults = options.maxResults ?? 20;
|
|
17
|
+
}
|
|
18
|
+
isAvailable() {
|
|
19
|
+
return Boolean(this.apiKey);
|
|
20
|
+
}
|
|
21
|
+
async performSearch(query, signal) {
|
|
22
|
+
if (!this.apiKey)
|
|
23
|
+
return [];
|
|
24
|
+
const url = `${BING_SEARCH_URL}?q=${encodeURIComponent(query)}&count=${this.maxResults}&mkt=en-US&responseFilter=Webpages,News`;
|
|
25
|
+
const response = await fetch(url, {
|
|
26
|
+
headers: { "Ocp-Apim-Subscription-Key": this.apiKey },
|
|
27
|
+
signal,
|
|
28
|
+
});
|
|
29
|
+
if (!response.ok) {
|
|
30
|
+
throw new Error(`Bing Search error: HTTP ${response.status} ${response.statusText}`);
|
|
31
|
+
}
|
|
32
|
+
const data = (await response.json());
|
|
33
|
+
const results = [];
|
|
34
|
+
const seenUrls = new Set();
|
|
35
|
+
for (const item of data.webPages?.value ?? []) {
|
|
36
|
+
if (seenUrls.has(item.url))
|
|
37
|
+
continue;
|
|
38
|
+
seenUrls.add(item.url);
|
|
39
|
+
results.push({ url: item.url, title: item.name, snippet: item.snippet });
|
|
40
|
+
}
|
|
41
|
+
for (const item of data.news?.value ?? []) {
|
|
42
|
+
if (seenUrls.has(item.url))
|
|
43
|
+
continue;
|
|
44
|
+
seenUrls.add(item.url);
|
|
45
|
+
results.push({ url: item.url, title: item.name, snippet: item.description });
|
|
46
|
+
}
|
|
47
|
+
return results;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export function bingSearch(options) {
|
|
51
|
+
return new BingSearchSource(options);
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=bing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bing.js","sourceRoot":"","sources":["../../src/web-search/bing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,aAAa,EAA+C,MAAM,WAAW,CAAA;AAEtF,MAAM,eAAe,GAAG,4CAA4C,CAAA;AAOpE,MAAM,OAAO,gBAAiB,SAAQ,aAAa;IACxC,IAAI,GAAG,aAAa,CAAA;IACpB,IAAI,GAAG,aAAa,CAAA;IACpB,eAAe,GAAG,eAAe,CAAC,iBAAiB,CAAA;IACnD,MAAM,GAAG,wBAAwB,CAAA;IACjC,MAAM,GAAG,KAAK,CAAA;IACd,qBAAqB,GAAG,KAAK,CAAA;IAE9B,MAAM,CAAoB;IAC1B,UAAU,CAAQ;IAE1B,YAAY,UAA6B,EAAE;QACzC,KAAK,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC,CAAA;QACvC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAA;QAC/D,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,EAAE,CAAA;IAC5C,CAAC;IAEQ,WAAW;QAClB,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAC7B,CAAC;IAES,KAAK,CAAC,aAAa,CAAC,KAAa,EAAE,MAAmB;QAC9D,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,CAAA;QAE3B,MAAM,GAAG,GAAG,GAAG,eAAe,MAAM,kBAAkB,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,UAAU,yCAAyC,CAAA;QAE/H,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,OAAO,EAAE,EAAE,2BAA2B,EAAE,IAAI,CAAC,MAAM,EAAE;YACrD,MAAM;SACP,CAAC,CAAA;QAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,2BAA2B,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAA;QACtF,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAGlC,CAAA;QAED,MAAM,OAAO,GAAsB,EAAE,CAAA;QACrC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAA;QAElC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE,EAAE,CAAC;YAC9C,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;gBAAE,SAAQ;YACpC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACtB,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAA;QAC1E,CAAC;QAED,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,EAAE,CAAC;YAC1C,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;gBAAE,SAAQ;YACpC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACtB,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;QAC9E,CAAC;QAED,OAAO,OAAO,CAAA;IAChB,CAAC;CACF;AAED,MAAM,UAAU,UAAU,CAAC,OAA2B;IACpD,OAAO,IAAI,gBAAgB,CAAC,OAAO,CAAC,CAAA;AACtC,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ReliabilityTier } from "@debriefer/core";
|
|
2
|
+
import { WebSearchBase, type WebSearchOptions, type WebSearchResult } from "./base.js";
|
|
3
|
+
export interface BraveSearchOptions extends WebSearchOptions {
|
|
4
|
+
apiKey?: string;
|
|
5
|
+
maxResults?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class BraveSearchSource extends WebSearchBase {
|
|
8
|
+
readonly name = "Brave Search";
|
|
9
|
+
readonly type = "brave-search";
|
|
10
|
+
readonly reliabilityTier = ReliabilityTier.SEARCH_AGGREGATOR;
|
|
11
|
+
readonly domain = "api.search.brave.com";
|
|
12
|
+
readonly isFree = false;
|
|
13
|
+
readonly estimatedCostPerQuery = 0.005;
|
|
14
|
+
private apiKey;
|
|
15
|
+
private maxResults;
|
|
16
|
+
constructor(options?: BraveSearchOptions);
|
|
17
|
+
isAvailable(): boolean;
|
|
18
|
+
protected performSearch(query: string, signal: AbortSignal): Promise<WebSearchResult[]>;
|
|
19
|
+
}
|
|
20
|
+
export declare function braveSearch(options?: BraveSearchOptions): BraveSearchSource;
|
|
21
|
+
//# sourceMappingURL=brave.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brave.d.ts","sourceRoot":"","sources":["../../src/web-search/brave.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,WAAW,CAAA;AAItF,MAAM,WAAW,kBAAmB,SAAQ,gBAAgB;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,qBAAa,iBAAkB,SAAQ,aAAa;IAClD,QAAQ,CAAC,IAAI,kBAAiB;IAC9B,QAAQ,CAAC,IAAI,kBAAiB;IAC9B,QAAQ,CAAC,eAAe,qCAAoC;IAC5D,QAAQ,CAAC,MAAM,0BAAyB;IACxC,QAAQ,CAAC,MAAM,SAAQ;IACvB,QAAQ,CAAC,qBAAqB,SAAQ;IAEtC,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,UAAU,CAAQ;gBAEd,OAAO,GAAE,kBAAuB;IAMnC,WAAW,IAAI,OAAO;cAIf,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;CAuC9F;AAED,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,iBAAiB,CAE3E"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ReliabilityTier } from "@debriefer/core";
|
|
2
|
+
import { WebSearchBase } from "./base.js";
|
|
3
|
+
const BRAVE_SEARCH_URL = "https://api.search.brave.com/res/v1/web/search";
|
|
4
|
+
export class BraveSearchSource extends WebSearchBase {
|
|
5
|
+
name = "Brave Search";
|
|
6
|
+
type = "brave-search";
|
|
7
|
+
reliabilityTier = ReliabilityTier.SEARCH_AGGREGATOR;
|
|
8
|
+
domain = "api.search.brave.com";
|
|
9
|
+
isFree = false;
|
|
10
|
+
estimatedCostPerQuery = 0.005;
|
|
11
|
+
apiKey;
|
|
12
|
+
maxResults;
|
|
13
|
+
constructor(options = {}) {
|
|
14
|
+
super({ rateLimitMs: 500, ...options });
|
|
15
|
+
this.apiKey = options.apiKey ?? process.env.BRAVE_SEARCH_API_KEY;
|
|
16
|
+
this.maxResults = options.maxResults ?? 20;
|
|
17
|
+
}
|
|
18
|
+
isAvailable() {
|
|
19
|
+
return Boolean(this.apiKey);
|
|
20
|
+
}
|
|
21
|
+
async performSearch(query, signal) {
|
|
22
|
+
if (!this.apiKey)
|
|
23
|
+
return [];
|
|
24
|
+
const url = `${BRAVE_SEARCH_URL}?q=${encodeURIComponent(query)}&count=${this.maxResults}&search_lang=en`;
|
|
25
|
+
const response = await fetch(url, {
|
|
26
|
+
headers: {
|
|
27
|
+
"X-Subscription-Token": this.apiKey,
|
|
28
|
+
Accept: "application/json",
|
|
29
|
+
},
|
|
30
|
+
signal,
|
|
31
|
+
});
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
throw new Error(`Brave Search error: HTTP ${response.status} ${response.statusText}`);
|
|
34
|
+
}
|
|
35
|
+
const data = (await response.json());
|
|
36
|
+
const results = [];
|
|
37
|
+
const seenUrls = new Set();
|
|
38
|
+
for (const item of data.web?.results ?? []) {
|
|
39
|
+
if (seenUrls.has(item.url))
|
|
40
|
+
continue;
|
|
41
|
+
seenUrls.add(item.url);
|
|
42
|
+
results.push({ url: item.url, title: item.title, snippet: item.description });
|
|
43
|
+
}
|
|
44
|
+
for (const item of data.news?.results ?? []) {
|
|
45
|
+
if (seenUrls.has(item.url))
|
|
46
|
+
continue;
|
|
47
|
+
seenUrls.add(item.url);
|
|
48
|
+
results.push({ url: item.url, title: item.title, snippet: item.description });
|
|
49
|
+
}
|
|
50
|
+
return results;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export function braveSearch(options) {
|
|
54
|
+
return new BraveSearchSource(options);
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=brave.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brave.js","sourceRoot":"","sources":["../../src/web-search/brave.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ReliabilityTier } from "@debriefer/core";
|
|
2
|
+
import { WebSearchBase, type WebSearchOptions, type WebSearchResult } from "./base.js";
|
|
3
|
+
export type DuckDuckGoSourceOptions = WebSearchOptions;
|
|
4
|
+
export declare class DuckDuckGoSearchSource extends WebSearchBase {
|
|
5
|
+
readonly name = "DuckDuckGo";
|
|
6
|
+
readonly type = "duckduckgo-search";
|
|
7
|
+
readonly reliabilityTier = ReliabilityTier.SEARCH_AGGREGATOR;
|
|
8
|
+
readonly domain = "html.duckduckgo.com";
|
|
9
|
+
readonly isFree = true;
|
|
10
|
+
readonly estimatedCostPerQuery = 0;
|
|
11
|
+
constructor(options?: DuckDuckGoSourceOptions);
|
|
12
|
+
protected performSearch(query: string, signal: AbortSignal): Promise<WebSearchResult[]>;
|
|
13
|
+
}
|
|
14
|
+
export declare function duckduckgoSearch(options?: DuckDuckGoSourceOptions): DuckDuckGoSearchSource;
|
|
15
|
+
//# sourceMappingURL=duckduckgo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duckduckgo.d.ts","sourceRoot":"","sources":["../../src/web-search/duckduckgo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,WAAW,CAAA;AAGtF,MAAM,MAAM,uBAAuB,GAAG,gBAAgB,CAAA;AAEtD,qBAAa,sBAAuB,SAAQ,aAAa;IACvD,QAAQ,CAAC,IAAI,gBAAe;IAC5B,QAAQ,CAAC,IAAI,uBAAsB;IACnC,QAAQ,CAAC,eAAe,qCAAoC;IAC5D,QAAQ,CAAC,MAAM,yBAAwB;IACvC,QAAQ,CAAC,MAAM,QAAO;IACtB,QAAQ,CAAC,qBAAqB,KAAI;gBAEtB,OAAO,GAAE,uBAA4B;cAIjC,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;CAG9F;AAED,wBAAgB,gBAAgB,CAAC,OAAO,CAAC,EAAE,uBAAuB,GAAG,sBAAsB,CAE1F"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ReliabilityTier } from "@debriefer/core";
|
|
2
|
+
import { WebSearchBase } from "./base.js";
|
|
3
|
+
import { searchDuckDuckGo } from "../shared/duckduckgo-search.js";
|
|
4
|
+
export class DuckDuckGoSearchSource extends WebSearchBase {
|
|
5
|
+
name = "DuckDuckGo";
|
|
6
|
+
type = "duckduckgo-search";
|
|
7
|
+
reliabilityTier = ReliabilityTier.SEARCH_AGGREGATOR;
|
|
8
|
+
domain = "html.duckduckgo.com";
|
|
9
|
+
isFree = true;
|
|
10
|
+
estimatedCostPerQuery = 0;
|
|
11
|
+
constructor(options = {}) {
|
|
12
|
+
super({ rateLimitMs: 1000, ...options });
|
|
13
|
+
}
|
|
14
|
+
async performSearch(query, signal) {
|
|
15
|
+
return searchDuckDuckGo({ query, signal });
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function duckduckgoSearch(options) {
|
|
19
|
+
return new DuckDuckGoSearchSource(options);
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=duckduckgo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duckduckgo.js","sourceRoot":"","sources":["../../src/web-search/duckduckgo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,aAAa,EAA+C,MAAM,WAAW,CAAA;AACtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAIjE,MAAM,OAAO,sBAAuB,SAAQ,aAAa;IAC9C,IAAI,GAAG,YAAY,CAAA;IACnB,IAAI,GAAG,mBAAmB,CAAA;IAC1B,eAAe,GAAG,eAAe,CAAC,iBAAiB,CAAA;IACnD,MAAM,GAAG,qBAAqB,CAAA;IAC9B,MAAM,GAAG,IAAI,CAAA;IACb,qBAAqB,GAAG,CAAC,CAAA;IAElC,YAAY,UAAmC,EAAE;QAC/C,KAAK,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,OAAO,EAAE,CAAC,CAAA;IAC1C,CAAC;IAES,KAAK,CAAC,aAAa,CAAC,KAAa,EAAE,MAAmB;QAC9D,OAAO,gBAAgB,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;IAC5C,CAAC;CACF;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAiC;IAChE,OAAO,IAAI,sBAAsB,CAAC,OAAO,CAAC,CAAA;AAC5C,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ReliabilityTier } from "@debriefer/core";
|
|
2
|
+
import { WebSearchBase, type WebSearchOptions, type WebSearchResult } from "./base.js";
|
|
3
|
+
export interface GoogleSearchOptions extends WebSearchOptions {
|
|
4
|
+
apiKey?: string;
|
|
5
|
+
cx?: string;
|
|
6
|
+
/** Number of results (1–10, Google CSE limit). Default: 10. */
|
|
7
|
+
maxResults?: number;
|
|
8
|
+
}
|
|
9
|
+
export declare class GoogleSearchSource extends WebSearchBase {
|
|
10
|
+
readonly name = "Google Search";
|
|
11
|
+
readonly type = "google-search";
|
|
12
|
+
readonly reliabilityTier = ReliabilityTier.SEARCH_AGGREGATOR;
|
|
13
|
+
readonly domain = "www.googleapis.com";
|
|
14
|
+
readonly isFree = false;
|
|
15
|
+
readonly estimatedCostPerQuery = 0.005;
|
|
16
|
+
private apiKey;
|
|
17
|
+
private cx;
|
|
18
|
+
private maxResults;
|
|
19
|
+
constructor(options?: GoogleSearchOptions);
|
|
20
|
+
isAvailable(): boolean;
|
|
21
|
+
protected performSearch(query: string, signal: AbortSignal): Promise<WebSearchResult[]>;
|
|
22
|
+
}
|
|
23
|
+
export declare function googleSearch(options?: GoogleSearchOptions): GoogleSearchSource;
|
|
24
|
+
//# sourceMappingURL=google.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../src/web-search/google.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,WAAW,CAAA;AAItF,MAAM,WAAW,mBAAoB,SAAQ,gBAAgB;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,qBAAa,kBAAmB,SAAQ,aAAa;IACnD,QAAQ,CAAC,IAAI,mBAAkB;IAC/B,QAAQ,CAAC,IAAI,mBAAkB;IAC/B,QAAQ,CAAC,eAAe,qCAAoC;IAC5D,QAAQ,CAAC,MAAM,wBAAuB;IACtC,QAAQ,CAAC,MAAM,SAAQ;IACvB,QAAQ,CAAC,qBAAqB,SAAQ;IAEtC,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,UAAU,CAAQ;gBAEd,OAAO,GAAE,mBAAwB;IAOpC,WAAW,IAAI,OAAO;cAIf,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;CA2B9F;AAED,wBAAgB,YAAY,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,kBAAkB,CAE9E"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ReliabilityTier } from "@debriefer/core";
|
|
2
|
+
import { WebSearchBase } from "./base.js";
|
|
3
|
+
const GOOGLE_CSE_URL = "https://www.googleapis.com/customsearch/v1";
|
|
4
|
+
export class GoogleSearchSource extends WebSearchBase {
|
|
5
|
+
name = "Google Search";
|
|
6
|
+
type = "google-search";
|
|
7
|
+
reliabilityTier = ReliabilityTier.SEARCH_AGGREGATOR;
|
|
8
|
+
domain = "www.googleapis.com";
|
|
9
|
+
isFree = false;
|
|
10
|
+
estimatedCostPerQuery = 0.005;
|
|
11
|
+
apiKey;
|
|
12
|
+
cx;
|
|
13
|
+
maxResults;
|
|
14
|
+
constructor(options = {}) {
|
|
15
|
+
super({ rateLimitMs: 500, ...options });
|
|
16
|
+
this.apiKey = options.apiKey ?? process.env.GOOGLE_SEARCH_API_KEY;
|
|
17
|
+
this.cx = options.cx ?? process.env.GOOGLE_SEARCH_CX;
|
|
18
|
+
this.maxResults = Math.min(Math.max(options.maxResults ?? 10, 1), 10);
|
|
19
|
+
}
|
|
20
|
+
isAvailable() {
|
|
21
|
+
return Boolean(this.apiKey && this.cx);
|
|
22
|
+
}
|
|
23
|
+
async performSearch(query, signal) {
|
|
24
|
+
if (!this.apiKey || !this.cx)
|
|
25
|
+
return [];
|
|
26
|
+
const url = new URL(GOOGLE_CSE_URL);
|
|
27
|
+
url.searchParams.set("key", this.apiKey);
|
|
28
|
+
url.searchParams.set("cx", this.cx);
|
|
29
|
+
url.searchParams.set("q", query);
|
|
30
|
+
url.searchParams.set("num", String(this.maxResults));
|
|
31
|
+
const response = await fetch(url.toString(), { signal });
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
throw new Error(`Google CSE error: HTTP ${response.status} ${response.statusText}`);
|
|
34
|
+
}
|
|
35
|
+
const data = (await response.json());
|
|
36
|
+
if (!data.items || data.items.length === 0)
|
|
37
|
+
return [];
|
|
38
|
+
return data.items.map((item) => ({
|
|
39
|
+
url: item.link,
|
|
40
|
+
title: item.title,
|
|
41
|
+
snippet: item.snippet,
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export function googleSearch(options) {
|
|
46
|
+
return new GoogleSearchSource(options);
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=google.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google.js","sourceRoot":"","sources":["../../src/web-search/google.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,aAAa,EAA+C,MAAM,WAAW,CAAA;AAEtF,MAAM,cAAc,GAAG,4CAA4C,CAAA;AASnE,MAAM,OAAO,kBAAmB,SAAQ,aAAa;IAC1C,IAAI,GAAG,eAAe,CAAA;IACtB,IAAI,GAAG,eAAe,CAAA;IACtB,eAAe,GAAG,eAAe,CAAC,iBAAiB,CAAA;IACnD,MAAM,GAAG,oBAAoB,CAAA;IAC7B,MAAM,GAAG,KAAK,CAAA;IACd,qBAAqB,GAAG,KAAK,CAAA;IAE9B,MAAM,CAAoB;IAC1B,EAAE,CAAoB;IACtB,UAAU,CAAQ;IAE1B,YAAY,UAA+B,EAAE;QAC3C,KAAK,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC,CAAA;QACvC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAA;QACjE,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAA;QACpD,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IACvE,CAAC;IAEQ,WAAW;QAClB,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,EAAE,CAAC,CAAA;IACxC,CAAC;IAES,KAAK,CAAC,aAAa,CAAC,KAAa,EAAE,MAAmB;QAC9D,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE;YAAE,OAAO,EAAE,CAAA;QAEvC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,CAAA;QACnC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;QACxC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAA;QACnC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QAChC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAA;QAEpD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;QAExD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,0BAA0B,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAA;QACrF,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAElC,CAAA;QAED,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAA;QAErD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC/B,GAAG,EAAE,IAAI,CAAC,IAAI;YACd,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC,CAAC,CAAA;IACL,CAAC;CACF;AAED,MAAM,UAAU,YAAY,CAAC,OAA6B;IACxD,OAAO,IAAI,kBAAkB,CAAC,OAAO,CAAC,CAAA;AACxC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@debriefer/sources",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Built-in research sources for debriefer: Wikipedia, Wikidata, web search, news, archives, and more",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"test": "vitest run --passWithNoTests",
|
|
20
|
+
"lint": "eslint src/",
|
|
21
|
+
"type-check": "tsc --noEmit"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"research",
|
|
25
|
+
"wikipedia",
|
|
26
|
+
"wikidata",
|
|
27
|
+
"web-scraping",
|
|
28
|
+
"news",
|
|
29
|
+
"archives",
|
|
30
|
+
"debriefer"
|
|
31
|
+
],
|
|
32
|
+
"author": "Chris Henderson",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/chenders/debriefer.git",
|
|
37
|
+
"directory": "packages/sources"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://github.com/chenders/debriefer#readme",
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/chenders/debriefer/issues"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@mozilla/readability": "^0.6",
|
|
45
|
+
"@debriefer/core": ">=1.0.0",
|
|
46
|
+
"he": "^1",
|
|
47
|
+
"jsdom": "^28",
|
|
48
|
+
"wtf_wikipedia": "^10"
|
|
49
|
+
},
|
|
50
|
+
"optionalDependencies": {
|
|
51
|
+
"fingerprint-injector": "^2",
|
|
52
|
+
"playwright-core": "^1.50"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/he": "^1.2.3",
|
|
56
|
+
"@types/jsdom": "^28.0.0"
|
|
57
|
+
}
|
|
58
|
+
}
|