Десктопный менеджер цен для веб-версии Яндекс Go. Приложение показывает текущие тарифы, сравнивает их с лучшей ценой за последние 10 минут и позволяет заказать по минимальной сохранённой котировке после явного подтверждения.
- извлекает текущий маршрут из актуального Redux-состояния Яндекс Go;
- использует
ymaps3/React Fiber только как резервный источник; - последовательно обновляет цены без параллельных запросов и гонок;
- отделяет текущие предложения от исторических значений;
- считает разницу только внутри одного маршрута и тарифа;
- хранит
offerIdминимальных котировок только в приватной памяти приложения; - не подменяет подтверждённую цену другим предложением;
- показывает состояния загрузки, отсутствия маршрута, offline, авторизации и ограничения запросов;
- изолирует интерфейс от страницы через Shadow DOM;
- не выводит в консоль адреса, координаты, идентификаторы сессии и предложения заказа.
Яндекс Go не предоставляет публичного контракта для используемых внутренних web API. Адаптер валидирует данные во время выполнения и сообщает о несовместимости, но после обновлений страницы может потребоваться актуализация.
Подробные исследовательские материалы:
- основной каталог внутреннего web API 4.130.0;
- возможности Яндекс Go и Яндекс Такси;
- сравнение официальных, внутренних и исторических API-контуров.
Создание заказа включено. Для каждого тарифа кнопка использует минимальную котировку, полученную за последние 10 минут, и её исходный offerId. Перед orderdraft приложение показывает отдельный диалог с ценой заказа, текущей ценой, выгодой, маршрутом и способом оплаты.
Сохранение offerId в течение 10 минут не гарантирует, что Яндекс Go всё ещё примет предложение: окончательная проверка происходит на orderdraft. Если предложение отклонено, приложение не заказывает автоматически по следующей или текущей цене — пользователь должен увидеть новую минимальную цену и подтвердить её отдельно.
Для аварийного режима «только мониторинг» можно явно отключить order-flow при сборке:
YGPM_ENABLE_ORDERING=false npm startCommit не повторяется автоматически при таймауте или неизвестном результате. Неопределённый результат блокирует новый заказ, пока пользователь не проверит активные поездки в Яндекс Go.
Перед единственным вызовом ordercommit приложение атомарно сохраняет зашифрованный commit-intent в каталоге Electron userData, а непосредственно до fetch — фазу commit-dispatched. После подтверждения сохраняется состояние активного заказа. При перезапуске состояния commit-intent, commit-dispatched, unknown и active восстанавливаются до включения кнопок заказа и не снимаются по таймеру. Снять pre-dispatch intent можно только после нативного подтверждения; повторная проверка фазы не даст сделать это, если запрос успел перейти границу отправки.
В журнал не записываются маршрут, адреса, координаты, offerId, котировка, cookies, CSRF-токен и исходный userId. Для привязки к сессии хранится необратимый fingerprint; orderId остаётся только внутри зашифрованного журнала и не попадает в публичный UI snapshot.
Перед созданием draft приложение требует, чтобы загруженное Redux-состояние подтверждало отсутствие другого активного заказа. Финальное подтверждение цены и маршрута выполняется в системном диалоге Electron; его одноразовая capability нужна main process для записи commit-intent.
Кнопка «Проверить активный заказ» сначала выполняет read-only taxiontheway для приватного orderId из зашифрованного журнала, не возвращая идентификатор странице. Локальный Redux используется как дополнительная fail-closed проверка всего аккаунта. Даже два terminal-ответа провайдера не разблокируют приложение автоматически: пользователь подтверждает действие в отдельном нативном диалоге, после чего приложение повторно проверяет отсутствие другого активного заказа. При другой сессии, незагруженном состоянии страницы или ошибке защищённого хранилища блокировка сохраняется. Временную ошибку можно проверить повторно; повреждённый журнал автоматически не удаляется.
taxiontheway и локальный Redux не являются публичными авторитетными API Яндекс Go. Поэтому ручная разблокировка после неизвестного результата — осознанный аварийный путь пользователя, а не доказательство отмены или отсутствия заказа. При любых сомнениях безопаснее оставить блокировку.
- Node.js 22.13 или новее;
- npm 10 или новее;
- учётная запись Яндекса с активной web-сессией.
npm install
npm startDevelopment-сборка открывает DevTools автоматически. В любой сборке их можно открыть или вернуть на передний план через F12, ⌘⌥I на macOS или Ctrl+Shift+I на Windows/Linux.
npm run lint
npm test
npm run test:coverage
npm run build
npm run packagenpm run package создаёт unpacked-сборку без запуска executable, а npm run dist — установочные артефакты для текущей платформы. Отдельный packaged-app launch smoke пока остаётся release gap.
Локальная macOS-сборка подписывается ad-hoc, чтобы Electron Framework оставался запускаемым после установки fuses. Для распространения вне локальной машины нужна отдельная Developer ID подпись и notarization.
Electron main
├─ политика навигации и permissions
├─ encrypted order journal (safeStorage + atomic write)
├─ allowlisted IPC через sandboxed preload
└─ контролируемая инъекция на taxi.yandex.ru
↓
Yandex adapter → quote monitor → app store → Shadow DOM panel
↓
order state machine (feature-gated)
src/main— жизненный цикл Electron, разрешённые origin, encrypted journal и инъекция;src/preload— минимальный allowlisted bridge к журналу без доступа страницы кipcRenderer;src/injection/adapters/yandex— адаптация внутренних runtime-контрактов;src/injection/infrastructure— сессия и HTTP-клиент;src/injection/domain— нормализация маршрутов и предложений;src/injection/services— polling и безопасный order workflow;src/injection/store— неизменяемые снимки состояния и история;src/injection/ui— изолированная панель.
Проект использует один packaging stack — electron-builder. Webpack отдельно собирает:
dist/main.jsс targetelectron-main;dist/preload.jsс targetelectron-preload;dist/injection.jsс targetweb;- стили интерфейса встраиваются внутрь Shadow DOM вместе с
dist/injection.js.
dist/ и build/ являются генерируемыми каталогами и не хранятся в Git.