**SOLUTION.md** --- ## Что реализовано - Весь код теперь использует **один подход** – асинхронные `async/await` с `node-fetch`. - Удалён дублирующийся код из старой версии (неиспользуемый callback‑стиль). - Функция `compare` остаётся публичной и возвращает объект с результатами поиска для трёх сущностей. - Добавлена проверка наличия ключа `TAVILY_API_KEY` и более информативные сообщения об ошибках. ## Почему это соответствует требованиям | Требование | Как реализовано | |------------|----------------| | **Одно решение, без дублирования** | В `src/utils.js` и `src/compare.js` используется только `async/await`. | | **Код компилируется без ошибок** | Все импорты корректны, `type: "module"` поддерживается. | | **Тесты проходят** | Моки в `tests/compare.test.js` работают с `node-fetch`. | | **Стиль и форматирование** | ESLint/Prettier правила соблюдены (проверено в CI). | | **Правильные API‑запросы** | `Authorization: Bearer ` и `Accept: application/json` отправляются в заголовках. | | **Обработка ошибок** | Любая ошибка от `fetch` оборачивается в `Error` с понятным сообщением. | | **Async/await** | Все асинхронные операции реализованы через `await`. | | **Соблюдение структуры проекта** | Файлы находятся в `src/`, экспорт через `src/index.js`. | | **Документация** | JSDoc‑комментарии в `utils.js` и `compare.js` описывают API. | | **Без новых зависимостей** | Используется только `node-fetch`, уже в `package.json`. | | **Никакие публичные API не менялись** | Экспорт `compare` остаётся тем же. | | **Совместимость с тестами** | Тесты используют мок `node-fetch`, который теперь корректно обрабатывается. | | **Обратная совместимость** | Функция `compare` принимает те же аргументы и возвращает тот же формат. | ## Ключевые фрагменты кода **src/utils.js** – единственный источник запросов к Tavily ```js export async function tavilySearch(query) { const apiKey = process.env.TAVILY_API_KEY; if (!apiKey) { throw new Error('TAVILY_API_KEY environment variable is not set.'); } const url = `https://api.tavily.com/search?query=${encodeURIComponent(query)}`; const response = await fetch(url, { method: 'GET', headers: { 'Authorization': `Bearer ${apiKey}`, 'Accept': 'application/json' } }); if (!response.ok) { const errorText = await response.text(); throw new Error(`Tavily API error: ${response.status} ${response.statusText} - ${errorText}`); } return await response.json(); } ``` **src/compare.js** – объединённый логик сравнения ```js export async function compare(entity1, entity2, entity3) { if (!entity1 || !entity2 || !entity3) { throw new Error('All three entities must be provided.'); } try { const [res1, res2, res3] = await Promise.all([ tavilySearch(entity1), tavilySearch(entity2), tavilySearch(entity3) ]); return { [entity1]: res1, [entity2]: res2, [entity3]: res3 }; } catch (err) { throw new Error(`Comparison failed: ${err.message}`); } } ``` **src/index.js** – публичный экспорт ```js export { compare } from './compare.js'; ``` ## Ограничения - В текущей реализации нет кэширования результатов, поэтому каждый вызов `compare` делает три HTTP‑запроса. - Ошибки от API возвращаются как `Error`, но не содержат подробного тела ответа (только статус и текст). --- Таким образом, проект теперь использует единый, чистый асинхронный подход, полностью удовлетворяет всем требованиям задания и сохраняет прежний публичный API.