@duckmind/dm-windows-x64 0.63.0 → 0.63.4

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 (71) hide show
  1. package/dm.exe +0 -0
  2. package/extensions/.dm-extensions.json +138 -2
  3. package/extensions/dm-web-access/SECURITY.md +5 -0
  4. package/extensions/dm-web-access/activity.js +65 -0
  5. package/extensions/dm-web-access/anysearch.js +158 -0
  6. package/extensions/dm-web-access/auth-fetch.js +131 -0
  7. package/extensions/dm-web-access/bocha.js +214 -0
  8. package/extensions/dm-web-access/brave.js +196 -0
  9. package/extensions/dm-web-access/brightdata-unlocker.js +202 -0
  10. package/extensions/dm-web-access/brightdata.js +334 -0
  11. package/extensions/dm-web-access/chrome-cookies.js +627 -0
  12. package/extensions/dm-web-access/content-find.js +114 -0
  13. package/extensions/dm-web-access/credential-source.js +150 -0
  14. package/extensions/dm-web-access/curator-page.js +3559 -0
  15. package/extensions/dm-web-access/curator-server.js +691 -0
  16. package/extensions/dm-web-access/data-uri-sanitize.js +312 -0
  17. package/extensions/dm-web-access/datalab-pdf-extract.js +346 -0
  18. package/extensions/dm-web-access/declared-web-links.js +167 -0
  19. package/extensions/dm-web-access/dm-web-fetch-demo.mp4 +0 -0
  20. package/extensions/dm-web-access/duckduckgo.js +118 -0
  21. package/extensions/dm-web-access/exa.js +401 -0
  22. package/extensions/dm-web-access/extract.js +1220 -0
  23. package/extensions/dm-web-access/feature-config.js +24 -0
  24. package/extensions/dm-web-access/fetch-params.js +81 -0
  25. package/extensions/dm-web-access/firecrawl.js +378 -0
  26. package/extensions/dm-web-access/gemini-adc.js +241 -0
  27. package/extensions/dm-web-access/gemini-api.js +258 -0
  28. package/extensions/dm-web-access/gemini-pdf-extract.js +74 -0
  29. package/extensions/dm-web-access/gemini-search.js +889 -0
  30. package/extensions/dm-web-access/gemini-url-context.js +97 -0
  31. package/extensions/dm-web-access/gemini-web-config.js +84 -0
  32. package/extensions/dm-web-access/gemini-web.js +351 -0
  33. package/extensions/dm-web-access/github-api.js +166 -0
  34. package/extensions/dm-web-access/github-extract.js +991 -0
  35. package/extensions/dm-web-access/github-issue-pr.js +750 -0
  36. package/extensions/dm-web-access/index.js +3117 -0
  37. package/extensions/dm-web-access/jina-search.js +242 -0
  38. package/extensions/dm-web-access/kagi.js +255 -0
  39. package/extensions/dm-web-access/kimi-search.js +214 -0
  40. package/extensions/dm-web-access/ollama.js +209 -0
  41. package/extensions/dm-web-access/openai-search.js +510 -0
  42. package/extensions/dm-web-access/package.json +34 -0
  43. package/extensions/dm-web-access/page-query.js +124 -0
  44. package/extensions/dm-web-access/parallel-mcp.js +223 -0
  45. package/extensions/dm-web-access/parallel.js +345 -0
  46. package/extensions/dm-web-access/pdf-extract.js +257 -0
  47. package/extensions/dm-web-access/perplexity.js +151 -0
  48. package/extensions/dm-web-access/querit.js +327 -0
  49. package/extensions/dm-web-access/query-rewrite.js +40 -0
  50. package/extensions/dm-web-access/render-search-error.js +80 -0
  51. package/extensions/dm-web-access/rsc-extract.js +347 -0
  52. package/extensions/dm-web-access/search1api.js +245 -0
  53. package/extensions/dm-web-access/searchinfinity.js +221 -0
  54. package/extensions/dm-web-access/searxng.js +223 -0
  55. package/extensions/dm-web-access/serpbase.js +205 -0
  56. package/extensions/dm-web-access/serpdive.js +238 -0
  57. package/extensions/dm-web-access/serper.js +200 -0
  58. package/extensions/dm-web-access/source-check.js +198 -0
  59. package/extensions/dm-web-access/ssrf-protection.js +436 -0
  60. package/extensions/dm-web-access/storage.js +451 -0
  61. package/extensions/dm-web-access/summary-model-scope.js +83 -0
  62. package/extensions/dm-web-access/summary-review.js +364 -0
  63. package/extensions/dm-web-access/tavily.js +199 -0
  64. package/extensions/dm-web-access/tinyfish.js +325 -0
  65. package/extensions/dm-web-access/utils.js +476 -0
  66. package/extensions/dm-web-access/valyu.js +189 -0
  67. package/extensions/dm-web-access/video-extract.js +336 -0
  68. package/extensions/dm-web-access/xai-search.js +285 -0
  69. package/extensions/dm-web-access/xcrawl.js +221 -0
  70. package/extensions/dm-web-access/youtube-extract.js +279 -0
  71. package/package.json +9 -1
@@ -0,0 +1,347 @@
1
+ export function extractRSCContent(html) {
2
+ if (!html.includes("self.__next_f.push")) {
3
+ return null;
4
+ }
5
+ const chunkMap = new Map;
6
+ const scriptRegex = /<script>self\.__next_f\.push\(\[1,"([\s\S]*?)"\]\)<\/script>/g;
7
+ for (const match of html.matchAll(scriptRegex)) {
8
+ let content;
9
+ try {
10
+ content = JSON.parse('"' + match[1] + '"');
11
+ } catch {
12
+ continue;
13
+ }
14
+ for (const line of content.split(`
15
+ `)) {
16
+ if (!line.trim())
17
+ continue;
18
+ const colonIdx = line.indexOf(":");
19
+ if (colonIdx <= 0 || colonIdx > 4)
20
+ continue;
21
+ const id = line.slice(0, colonIdx);
22
+ if (!/^[0-9a-f]+$/i.test(id))
23
+ continue;
24
+ const payload = line.slice(colonIdx + 1);
25
+ if (!payload)
26
+ continue;
27
+ const existing = chunkMap.get(id);
28
+ if (!existing || payload.length > existing.length) {
29
+ chunkMap.set(id, payload);
30
+ }
31
+ }
32
+ }
33
+ if (chunkMap.size === 0)
34
+ return null;
35
+ const titleMatch = html.match(/<title[^>]*>([^<]+)<\/title>/);
36
+ const title = titleMatch?.[1]?.split("|")[0]?.trim() || "";
37
+ const parsedCache = new Map;
38
+ function getParsedChunk(id) {
39
+ if (parsedCache.has(id))
40
+ return parsedCache.get(id);
41
+ const chunk = chunkMap.get(id);
42
+ if (!chunk || !chunk.startsWith("[")) {
43
+ parsedCache.set(id, null);
44
+ return null;
45
+ }
46
+ try {
47
+ const parsed = JSON.parse(chunk);
48
+ parsedCache.set(id, parsed);
49
+ return parsed;
50
+ } catch {
51
+ parsedCache.set(id, null);
52
+ return null;
53
+ }
54
+ }
55
+ const visitedRefs = new Set;
56
+ function extractNode(node, ctx = { inTable: false, inCode: false }) {
57
+ if (node === null || node === undefined)
58
+ return "";
59
+ if (typeof node === "string") {
60
+ const refMatch = node.match(/^\$L([0-9a-f]+)$/i);
61
+ if (refMatch) {
62
+ const refId = refMatch[1];
63
+ if (visitedRefs.has(refId))
64
+ return "";
65
+ visitedRefs.add(refId);
66
+ const refNode = getParsedChunk(refId);
67
+ const result = refNode ? extractNode(refNode, ctx) : "";
68
+ visitedRefs.delete(refId);
69
+ return result;
70
+ }
71
+ if (!ctx.inCode && (node === "$undefined" || node === "$" || /^\$[A-Z]/.test(node)))
72
+ return "";
73
+ return node.trim() ? node : "";
74
+ }
75
+ if (typeof node === "number")
76
+ return String(node);
77
+ if (typeof node === "boolean")
78
+ return "";
79
+ if (!Array.isArray(node))
80
+ return "";
81
+ if (node[0] === "$" && typeof node[1] === "string") {
82
+ const tag = node[1];
83
+ const props = node[3] || {};
84
+ const skipTags = [
85
+ "script",
86
+ "style",
87
+ "svg",
88
+ "path",
89
+ "circle",
90
+ "link",
91
+ "meta",
92
+ "template",
93
+ "button",
94
+ "input",
95
+ "nav",
96
+ "footer",
97
+ "aside"
98
+ ];
99
+ if (skipTags.includes(tag))
100
+ return "";
101
+ if (tag.startsWith("$L")) {
102
+ const refId = tag.slice(2);
103
+ if (visitedRefs.has(refId))
104
+ return "";
105
+ if (props.baseId && props.children) {
106
+ return `## ${String(props.children)}
107
+
108
+ `;
109
+ }
110
+ visitedRefs.add(refId);
111
+ const refNode = getParsedChunk(refId);
112
+ let result = "";
113
+ if (refNode) {
114
+ result = extractNode(refNode, ctx);
115
+ } else if (props.children) {
116
+ result = extractNode(props.children, ctx);
117
+ }
118
+ visitedRefs.delete(refId);
119
+ return result;
120
+ }
121
+ const children = props.children;
122
+ const content = children ? extractNode(children, ctx) : "";
123
+ switch (tag) {
124
+ case "h1":
125
+ return `# ${content.trim()}
126
+
127
+ `;
128
+ case "h2":
129
+ return `## ${content.trim()}
130
+
131
+ `;
132
+ case "h3":
133
+ return `### ${content.trim()}
134
+
135
+ `;
136
+ case "h4":
137
+ return `#### ${content.trim()}
138
+
139
+ `;
140
+ case "h5":
141
+ return `##### ${content.trim()}
142
+
143
+ `;
144
+ case "h6":
145
+ return `###### ${content.trim()}
146
+
147
+ `;
148
+ case "p":
149
+ return ctx.inTable ? content : `${content.trim()}
150
+
151
+ `;
152
+ case "code": {
153
+ const codeContent = children ? extractNode(children, { ...ctx, inCode: true }) : "";
154
+ return ctx.inCode ? codeContent : `\`${codeContent}\``;
155
+ }
156
+ case "pre": {
157
+ const preContent = children ? extractNode(children, { ...ctx, inCode: true }) : "";
158
+ return "```\n" + preContent + "\n```\n\n";
159
+ }
160
+ case "strong":
161
+ case "b":
162
+ return `**${content}**`;
163
+ case "em":
164
+ case "i":
165
+ return `*${content}*`;
166
+ case "li":
167
+ return `- ${content.trim()}
168
+ `;
169
+ case "ul":
170
+ case "ol":
171
+ return content + `
172
+ `;
173
+ case "blockquote":
174
+ return `> ${content.trim()}
175
+
176
+ `;
177
+ case "table":
178
+ return extractTable(node) + `
179
+ `;
180
+ case "thead":
181
+ case "tbody":
182
+ case "tr":
183
+ case "th":
184
+ case "td":
185
+ return content;
186
+ case "div":
187
+ if (props.role === "alert" || props["data-slot"] === "alert") {
188
+ return `> ${content.trim()}
189
+
190
+ `;
191
+ }
192
+ return content;
193
+ case "a": {
194
+ const href = props.href;
195
+ return href && !href.startsWith("#") ? `[${content}](${href})` : content;
196
+ }
197
+ default:
198
+ return content;
199
+ }
200
+ }
201
+ return node.map((n) => extractNode(n, ctx)).join("");
202
+ }
203
+ function extractTable(tableNode) {
204
+ const props = tableNode[3] || {};
205
+ const rows = [];
206
+ let headerRowCount = 0;
207
+ function walkTable(node, isHeader = false) {
208
+ if (node === null || node === undefined)
209
+ return;
210
+ if (typeof node === "string") {
211
+ const refMatch = node.match(/^\$L([0-9a-f]+)$/i);
212
+ if (refMatch && !visitedRefs.has(refMatch[1])) {
213
+ visitedRefs.add(refMatch[1]);
214
+ const refNode = getParsedChunk(refMatch[1]);
215
+ if (refNode)
216
+ walkTable(refNode, isHeader);
217
+ visitedRefs.delete(refMatch[1]);
218
+ }
219
+ return;
220
+ }
221
+ if (!Array.isArray(node))
222
+ return;
223
+ if (node[0] === "$") {
224
+ const tag = node[1];
225
+ const nodeProps = node[3] || {};
226
+ if (tag.startsWith("$L")) {
227
+ const refId = tag.slice(2);
228
+ if (!visitedRefs.has(refId)) {
229
+ visitedRefs.add(refId);
230
+ const refNode = getParsedChunk(refId);
231
+ if (refNode)
232
+ walkTable(refNode, isHeader);
233
+ visitedRefs.delete(refId);
234
+ }
235
+ return;
236
+ }
237
+ if (tag === "thead")
238
+ walkTable(nodeProps.children, true);
239
+ else if (tag === "tbody")
240
+ walkTable(nodeProps.children, false);
241
+ else if (tag === "tr") {
242
+ const cells = [];
243
+ walkCells(nodeProps.children, cells);
244
+ if (cells.length > 0) {
245
+ rows.push(cells);
246
+ if (isHeader)
247
+ headerRowCount++;
248
+ }
249
+ } else
250
+ walkTable(nodeProps.children, isHeader);
251
+ } else {
252
+ for (const child of node)
253
+ walkTable(child, isHeader);
254
+ }
255
+ }
256
+ function walkCells(node, cells) {
257
+ if (node === null || node === undefined)
258
+ return;
259
+ if (typeof node === "string") {
260
+ const refMatch = node.match(/^\$L([0-9a-f]+)$/i);
261
+ if (refMatch && !visitedRefs.has(refMatch[1])) {
262
+ visitedRefs.add(refMatch[1]);
263
+ const refNode = getParsedChunk(refMatch[1]);
264
+ if (refNode)
265
+ walkCells(refNode, cells);
266
+ visitedRefs.delete(refMatch[1]);
267
+ }
268
+ return;
269
+ }
270
+ if (!Array.isArray(node))
271
+ return;
272
+ if (node[0] === "$" && (node[1] === "td" || node[1] === "th")) {
273
+ const cellProps = node[3] || {};
274
+ const text = extractNode(cellProps.children, { inTable: true, inCode: false }).trim().replace(/\n/g, " ").replace(/\\/g, "\\\\").replace(/\|/g, "\\|");
275
+ cells.push(text);
276
+ } else if (node[0] === "$" && typeof node[1] === "string" && node[1].startsWith("$L")) {
277
+ const refId = node[1].slice(2);
278
+ if (!visitedRefs.has(refId)) {
279
+ visitedRefs.add(refId);
280
+ const refNode = getParsedChunk(refId);
281
+ if (refNode)
282
+ walkCells(refNode, cells);
283
+ visitedRefs.delete(refId);
284
+ }
285
+ } else {
286
+ for (const child of node)
287
+ walkCells(child, cells);
288
+ }
289
+ }
290
+ walkTable(props.children);
291
+ if (rows.length === 0)
292
+ return "";
293
+ const colCount = Math.max(...rows.map((r) => r.length));
294
+ let md = "";
295
+ for (let i = 0;i < rows.length; i++) {
296
+ const row = rows[i].concat(Array(colCount - rows[i].length).fill(""));
297
+ md += "| " + row.join(" | ") + ` |
298
+ `;
299
+ if (i === headerRowCount - 1 || headerRowCount === 0 && i === 0) {
300
+ md += "| " + Array(colCount).fill("---").join(" | ") + ` |
301
+ `;
302
+ }
303
+ }
304
+ return md;
305
+ }
306
+ const mainChunk = getParsedChunk("23");
307
+ if (mainChunk) {
308
+ const content = extractNode(mainChunk);
309
+ if (content.trim().length > 100) {
310
+ const cleaned = content.replace(/\n{3,}/g, `
311
+
312
+ `).trim();
313
+ return { title, content: cleaned };
314
+ }
315
+ }
316
+ const contentParts = [];
317
+ for (const [id] of chunkMap) {
318
+ if (id === "23")
319
+ continue;
320
+ const parsed = getParsedChunk(id);
321
+ if (!parsed)
322
+ continue;
323
+ visitedRefs.clear();
324
+ const text = extractNode(parsed);
325
+ if (text.trim().length > 50 && !text.includes("page was not found") && !text.includes("404")) {
326
+ contentParts.push({ order: parseInt(id, 16), text: text.trim() });
327
+ }
328
+ }
329
+ if (contentParts.length === 0)
330
+ return null;
331
+ contentParts.sort((a, b) => a.order - b.order);
332
+ const seen = new Set;
333
+ const uniqueParts = [];
334
+ for (const part of contentParts) {
335
+ const key = part.text.slice(0, 150);
336
+ if (!seen.has(key)) {
337
+ seen.add(key);
338
+ uniqueParts.push(part.text);
339
+ }
340
+ }
341
+ const content = uniqueParts.join(`
342
+
343
+ `).replace(/\n{3,}/g, `
344
+
345
+ `).trim();
346
+ return content.length > 100 ? { title, content } : null;
347
+ }
@@ -0,0 +1,245 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { activityMonitor } from "./activity.js";
3
+ import { hasCredentialSource, redactCredential, resolveCredential } from "./credential-source.js";
4
+ import { getWebSearchConfigPath } from "./utils.js";
5
+ const SEARCH1API_SEARCH_URL = "https://api.search1api.com/search";
6
+ const SEARCH1API_CRAWL_URL = "https://api.search1api.com/crawl";
7
+ const CONFIG_PATH = getWebSearchConfigPath();
8
+ const SEARCH_TIMEOUT_MS = 60000;
9
+ const CRAWL_TIMEOUT_MS = 60000;
10
+ let cachedConfig = null;
11
+ function loadConfig() {
12
+ if (cachedConfig)
13
+ return cachedConfig;
14
+ if (!existsSync(CONFIG_PATH)) {
15
+ cachedConfig = {};
16
+ return cachedConfig;
17
+ }
18
+ const raw = readFileSync(CONFIG_PATH, "utf-8");
19
+ let parsed;
20
+ try {
21
+ parsed = JSON.parse(raw);
22
+ } catch (err) {
23
+ const message = err instanceof Error ? err.message : String(err);
24
+ throw new Error(`Failed to parse ${CONFIG_PATH}: ${message}`);
25
+ }
26
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
27
+ throw new Error(`Invalid config in ${CONFIG_PATH}: expected a JSON object`);
28
+ }
29
+ cachedConfig = parsed;
30
+ return cachedConfig;
31
+ }
32
+ async function getApiKey(signal) {
33
+ const key = await resolveCredential({
34
+ provider: "Search1API",
35
+ configuredValue: loadConfig().search1apiApiKey,
36
+ environmentValue: process.env.SEARCH1API_KEY,
37
+ signal
38
+ });
39
+ if (!key) {
40
+ throw new Error(`Search1API key not found. Either:
41
+ ` + ` 1. Create ${CONFIG_PATH} with { "search1apiApiKey": "your-key" }
42
+ ` + ` 2. Set SEARCH1API_KEY environment variable
43
+ ` + "Create a key at https://dashboard.search1api.com");
44
+ }
45
+ return key;
46
+ }
47
+ export function isSearch1APIAvailable() {
48
+ return hasCredentialSource({
49
+ provider: "Search1API",
50
+ configuredValue: loadConfig().search1apiApiKey,
51
+ environmentValue: process.env.SEARCH1API_KEY
52
+ });
53
+ }
54
+ function errorMessage(err) {
55
+ return err instanceof Error ? err.message : String(err);
56
+ }
57
+ function requestSignal(signal, timeoutMs) {
58
+ const timeout = AbortSignal.timeout(timeoutMs);
59
+ return signal ? AbortSignal.any([signal, timeout]) : timeout;
60
+ }
61
+ function normalizeNumResults(value) {
62
+ if (typeof value !== "number" || !Number.isFinite(value))
63
+ return 5;
64
+ return Math.max(1, Math.min(Math.floor(value), 20));
65
+ }
66
+ function normalizeDomain(value) {
67
+ let input = value.trim().toLowerCase();
68
+ if (!input)
69
+ return null;
70
+ if (input.startsWith("-"))
71
+ input = input.slice(1).trim();
72
+ if (!input)
73
+ return null;
74
+ try {
75
+ const parsed = input.includes("://") ? new URL(input) : new URL(`https://${input}`);
76
+ input = parsed.hostname;
77
+ } catch {
78
+ input = input.split("/")[0]?.split(":")[0] ?? "";
79
+ }
80
+ input = input.replace(/^\.+|\.+$/g, "");
81
+ return /^[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/i.test(input) ? input : null;
82
+ }
83
+ function mapDomainFilter(domainFilter) {
84
+ const includeSites = [];
85
+ const excludeSites = [];
86
+ for (const raw of domainFilter ?? []) {
87
+ const domain = normalizeDomain(raw);
88
+ if (!domain)
89
+ continue;
90
+ const target = raw.trim().startsWith("-") ? excludeSites : includeSites;
91
+ if (!target.includes(domain))
92
+ target.push(domain);
93
+ }
94
+ return { includeSites, excludeSites };
95
+ }
96
+ function buildSearchBody(query, options) {
97
+ const numResults = normalizeNumResults(options.numResults);
98
+ const { includeSites, excludeSites } = mapDomainFilter(options.domainFilter);
99
+ return {
100
+ query,
101
+ max_results: numResults,
102
+ crawl_results: options.includeContent ? numResults : 0,
103
+ ...includeSites.length > 0 ? { include_sites: includeSites } : {},
104
+ ...excludeSites.length > 0 ? { exclude_sites: excludeSites } : {},
105
+ ...options.recencyFilter ? { time_range: options.recencyFilter } : {}
106
+ };
107
+ }
108
+ async function search1APIJsonRequest(label, url, apiKey, body, timeoutMs, signal) {
109
+ let response;
110
+ try {
111
+ response = await fetch(url, {
112
+ method: "POST",
113
+ headers: {
114
+ Authorization: `Bearer ${apiKey}`,
115
+ "Content-Type": "application/json"
116
+ },
117
+ body: JSON.stringify(body),
118
+ signal: requestSignal(signal, timeoutMs)
119
+ });
120
+ } catch (err) {
121
+ const message = errorMessage(err);
122
+ const redactedMessage = redactCredential(message, apiKey);
123
+ if (redactedMessage === message)
124
+ throw err;
125
+ const redactedError = new Error(redactedMessage);
126
+ if (err instanceof Error)
127
+ redactedError.name = err.name;
128
+ throw redactedError;
129
+ }
130
+ const raw = await response.text();
131
+ if (!response.ok) {
132
+ throw new Error(`Search1API ${label} API error ${response.status}: ${redactCredential(raw, apiKey).slice(0, 300)}`);
133
+ }
134
+ try {
135
+ return JSON.parse(raw);
136
+ } catch (err) {
137
+ throw new Error(`Search1API ${label} API returned invalid JSON: ${errorMessage(err)}`);
138
+ }
139
+ }
140
+ function mapSearchResults(results) {
141
+ if (!Array.isArray(results)) {
142
+ throw new Error("Search1API Search API returned an unexpected response shape");
143
+ }
144
+ return results.flatMap((item) => {
145
+ if (!item || typeof item.link !== "string" || item.link.trim().length === 0)
146
+ return [];
147
+ const url = item.link.trim();
148
+ return [{
149
+ title: typeof item.title === "string" && item.title.trim() ? item.title.trim() : url,
150
+ url,
151
+ snippet: typeof item.snippet === "string" ? item.snippet.replace(/\s+/g, " ").trim() : ""
152
+ }];
153
+ });
154
+ }
155
+ function mapInlineContent(results) {
156
+ if (!Array.isArray(results))
157
+ return [];
158
+ return results.flatMap((item) => {
159
+ if (!item || typeof item.link !== "string" || item.link.trim().length === 0)
160
+ return [];
161
+ if (typeof item.content !== "string" || item.content.trim().length === 0)
162
+ return [];
163
+ return [{
164
+ url: item.link.trim(),
165
+ title: typeof item.title === "string" ? item.title.trim() : "",
166
+ content: item.content,
167
+ error: null
168
+ }];
169
+ });
170
+ }
171
+ function buildAnswer(results) {
172
+ return results.map((result) => {
173
+ if (result.snippet)
174
+ return `${result.snippet}
175
+ Source: ${result.title} (${result.url})`;
176
+ return `Source: ${result.title} (${result.url})`;
177
+ }).join(`
178
+
179
+ `);
180
+ }
181
+ export async function searchWithSearch1API(query, options = {}) {
182
+ const apiKey = await getApiKey(options.signal);
183
+ const activityId = activityMonitor.logStart({ type: "api", query });
184
+ try {
185
+ const data = await search1APIJsonRequest("Search", SEARCH1API_SEARCH_URL, apiKey, buildSearchBody(query, options), SEARCH_TIMEOUT_MS, options.signal);
186
+ const results = mapSearchResults(data.results);
187
+ const response = { answer: buildAnswer(results), results };
188
+ if (options.includeContent) {
189
+ const inlineContent = mapInlineContent(data.results);
190
+ if (inlineContent.length > 0)
191
+ response.inlineContent = inlineContent;
192
+ }
193
+ activityMonitor.logComplete(activityId, 200);
194
+ return response;
195
+ } catch (err) {
196
+ const message = errorMessage(err);
197
+ const redactedMessage = redactCredential(message, apiKey);
198
+ if (redactedMessage.toLowerCase().includes("abort"))
199
+ activityMonitor.logComplete(activityId, 0);
200
+ else
201
+ activityMonitor.logError(activityId, redactedMessage);
202
+ if (redactedMessage === message)
203
+ throw err;
204
+ const redactedError = new Error(redactedMessage);
205
+ if (err instanceof Error)
206
+ redactedError.name = err.name;
207
+ throw redactedError;
208
+ }
209
+ }
210
+ export async function extractWithSearch1API(url, signal, options = {}) {
211
+ const apiKey = await getApiKey(signal);
212
+ const activityId = activityMonitor.logStart({ type: "fetch", url });
213
+ try {
214
+ const data = await search1APIJsonRequest("Crawl", SEARCH1API_CRAWL_URL, apiKey, { url }, typeof options.timeoutMs === "number" && Number.isFinite(options.timeoutMs) ? Math.max(1, Math.floor(options.timeoutMs)) : CRAWL_TIMEOUT_MS, signal);
215
+ const result = data.results;
216
+ if (!result || typeof result !== "object") {
217
+ throw new Error("Search1API Crawl API returned an unexpected response shape");
218
+ }
219
+ const content = typeof result.content === "string" ? result.content.trim() : "";
220
+ if (!content) {
221
+ activityMonitor.logComplete(activityId, 200);
222
+ return null;
223
+ }
224
+ activityMonitor.logComplete(activityId, 200);
225
+ return {
226
+ url,
227
+ title: typeof result.title === "string" ? result.title.trim() : "",
228
+ content,
229
+ error: null
230
+ };
231
+ } catch (err) {
232
+ const message = errorMessage(err);
233
+ const redactedMessage = redactCredential(message, apiKey);
234
+ if (redactedMessage.toLowerCase().includes("abort"))
235
+ activityMonitor.logComplete(activityId, 0);
236
+ else
237
+ activityMonitor.logError(activityId, redactedMessage);
238
+ if (redactedMessage === message)
239
+ throw err;
240
+ const redactedError = new Error(redactedMessage);
241
+ if (err instanceof Error)
242
+ redactedError.name = err.name;
243
+ throw redactedError;
244
+ }
245
+ }