| 297 | 297 | } |
| 298 | 298 | }); |
| 299 | 299 | |
| 300 | +router.post('/serper', jsonParser, async (request, response) => { |
| 301 | + try { |
| 302 | + const key = readSecret(request.user.directories, SECRET_KEYS.SERPER); |
| 303 | + |
| 304 | + if (!key) { |
| 305 | + console.error('No Serper key found'); |
| 306 | + return response.sendStatus(400); |
| 307 | + } |
| 308 | + |
| 309 | + const { query, images } = request.body; |
| 310 | + |
| 311 | + const url = images |
| 312 | + ? 'https://google.serper.dev/images' |
| 313 | + : 'https://google.serper.dev/search'; |
| 314 | + |
| 315 | + const result = await fetch(url, { |
| 316 | + method: 'POST', |
| 317 | + headers: { |
| 318 | + 'X-API-KEY': key, |
| 319 | + 'Content-Type': 'application/json', |
| 320 | + }, |
| 321 | + redirect: 'follow', |
| 322 | + body: JSON.stringify({ q: query }), |
| 323 | + }); |
| 324 | + |
| 325 | + console.debug('Serper query', query); |
| 326 | + |
| 327 | + if (!result.ok) { |
| 328 | + const text = await result.text(); |
| 329 | + console.warn('Serper request failed', result.statusText, text); |
| 330 | + return response.status(500).send(text); |
| 331 | + } |
| 332 | + |
| 333 | + const data = await result.json(); |
| 334 | + return response.json(data); |
| 335 | + } catch (error) { |
| 336 | + console.error(error); |
| 337 | + return response.sendStatus(500); |
| 338 | + } |
| 339 | +}); |
| 340 | + |
| 300 | 341 | router.post('/visit', jsonParser, async (request, response) => { |
| 301 | 342 | try { |
| 302 | 343 | const url = request.body.url; |