| 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 | router.post('/visit', jsonParser, async (request, response) => { | 341 | router.post('/visit', jsonParser, async (request, response) => { |
| 301 | try { | 342 | try { |
| 302 | const url = request.body.url; | 343 | const url = request.body.url; |