Чем хорош TRMNL — так это возможностью выводить что‑то своё за считанные минуты.
С помощью «Private Plugins» можно взять ссылку, что отдаёт JSON (недавно добавили поддержку XML и сырого текста), рисуем простой шаблон на HTML с Liquid, готово! Для пущей динамики возможе неще и javascript, что позволяет выводить графики.
Можно опубликовать для других пользователей, можно брать опубликованное другими и либо использовать как есть — либо подправить под себя. Раздолье!
График сахара — пять минут, используя приведённый в документации шаблон графиков и два взмаха жаваскриптом для конвертации данных.
График шагов... А вот тут сложнее. Сервер позволяет простые GET и POST запросы, можно сунуть что‑то в заголовки, URL, тело запроса и т. п. — но вот хранить состояние между запросами нельзя, то есть в лоб OAuth2 не реализуешь. Оно и понятно: они не очень хотят хранить данные авторизации для всех.

Что же делать?
Что ж. Решим задачу.
Дано:
есть платформа, которая может запрашивать урлы, но не хранит состояние;
есть источники данных, которые отдают по REST что попросишь — но требуют OAuth2 авторизации;
OAuth2 запросы авторизуется простыми ключами, но ключи требуют изначальной авторизации для выдачи прав, а потом постоянной ротации, чтоб поддерживать в актуальном состоянии;
нет желания поднимать и обслуживать виртуалку где бы то ни было;
нагрузка АЖ запрос раз в 15 минут. Может, если вдруг захочется, десяток запросов.
Решение:
берём бесплатный CloudFlare;
рисуем прокси, который будет проверять входящие запросы по статическому токену (без авторотации), и отсылать запросы дальше подписав динамическим токеном;
рисуем крон, который будет поддерживать динамические токены в актуальном состоянии.
Так как задача простая как пробка, что справится кто угодно, почему бы не попытаться заставить это сделать машину?
Так что дополнительное развлечение: будем вайбокодить.
Подготовка к решению
Устанавливаем курсор. Запускаем. Пытаемся «перенести» плагины — получается нерабочий ужас.
Сносим курсор, чистим, устанавливаем заново, говорим оставить только рекомендованные плагины. Пытаемся доставить нужные, не находим в маркете. Просто забиваем на это дело, «и так сойдёт» и будем ковыряться с деплоем вручную.
Активируем триальную лицензию (заодно узнаем, стоит ли за неё платить). Создаём новый Git репозиторий, устанавливаем nodejs и npm внутри wsl и на винде.
В общем и целом, часть команд он запускать может, интеграция с Wsl сломана, интеграция через ssh внутрь wsl работает но как‑то косо. Я просто открыл папку проекта и держу открытый отдельный terminator, благо монитор достаточно широкий.
Всё, более‑менее всё дышит, можно начинать вайбокодить.
Процесс решения
Попытка «в лоб» сформулировать задачу как бы я её задавал человеку оказалась катастрофически провальной, но это я знал заранее, так как уже игрался с сеточками для поиска решений.
Дао «заставить одну сеть составить план, который скармливать потом курсору» я не постиг: я сломался на попытке получить план, с которым я был бы согласен. Этот навык набивать можно будет позднее, перейдём к практике.
Кодить будем по шагам, и план простой: создать админку => добавить oauth авторизацию и хранение => добавить прокси => добавить ротацию => деплоим.
Часть первая: админка
(1) Говорим агенту, что мы пишем под CloudFlare workers на Javascript и просим создать скелет c двумя endpoint'ами: для настройки и для админки, админке нужен логин-пароль который хранится в KV базе.
Он создаёт какой-то код, который оч похож на правду. Восторгаемся пассажу про
<div class="credentials-info">
<p>Development credentials:</p>
<p>Username: admin</p>
<p>Password: password123</p>
</div>
Но игнорируем, так как нигде внутри кода это не захардкожено.
Спрашиваем как его запустить для пощупать (я ничего не знаю про CloudFlare), его ответ не работает (wrangler в лоб не запускается ни на винде ни в wsl), вопрос в gemini объяснил недостающее, ставлю пакеты, через npx wrangler dev
запускаю, не работает копируют ошибку про KV курсору, он прави тnamespace на local, оно запускается.
Прошу создать .gitignore, он его создаёт, и вроде даже похоже на правду. Коммитим, первый шаг готов.
(2) Просим в админке создать форму создания нового приложения и список приложений, в котором есть кнопка удалить и отредактировать. Для каждого приложения задаются его название, client id, пути для авторизации и API. Client ID и название редактировать нельзя, пути — можно.
Тут я познакомился с его подходом «простите, что‑то не получилось, я сейчас еще раз». Раза с третьего он смог интегрировать своё решение в редактор. Выглядит так, что он иногда пытается сгенерировать дифф, а иногда полный файл.

В любом случае, он создал нечто, от чего я был в полном восторге: он добавил управление сессией! Сам !После проверки логина и пароля, он создал сессию и больше не надо вводить пароль, всё работает!

Очень внимательно полюбуйтесь на это. Пароль больше не надо вводить, да. Нужен только логин, который сохраняется в куку, очень удобно.
Просим переделать на использование рандомной куки, которая будет жить минут 15. Переделывает.
Спрашиваем «а не может ли KV проверять срок жизни?»... Может, говорит, и переделывает.
Уф, теперь ничего сходу страшного не обнаруживается, коммитим.
Часть вторая: oauth хранение и авторизация
(3) Пришла пора проверить его догадливость. Просим для каждого приложения добавить кнопку oauth авторизации, которую сохранять в базе приложения.
И он справляется! Сам добавляет хранение токенов, отдельный endpoint для callback'а при авторизации, генератор рандомного кода для верификации, причем реюзнул тот же что для сессий сделал на прошлом шаге. Ручные эксперименты с fitbit web api потребовали только прописать scope не «read write» а «activity».
Вот только редиректы — не работают. Несколько жалоб с копированием ошибки таки привели к кое‑как рабочему решению.
Коммитим, пока не поломалось.
(4) Просим сделать scope параметром для приложения. Коммитим.
(5) Так как сервера часто проверяют callback url и требуют его ввести при настройке, просим вывести его на форму.

Он выводит и добавляет, как он сам сказал, для удобства, кнопочку копирования. Коммитим.
(6) Просим для приложений добавить уникальные прокси токены, с возможностью перегенерировать их если вдруг захочется — и вывести их для каждого приложения. Коммитим.
Часть третья: прокси
(7) Добрались до второй части нашего балета: GET прокси. Просим сделать так, чтоб /get/
эндпоинт брал первое слово после /get/ как имя приложения, а всё что дальше — использовал как путь для API. Проверял, что в запросе передали правильный proxyToken
и если да — добавлял остаток ссылки у API адресу и пересылал подписав текущим OAuth ключом.
Неплохо справляется с первого раза. Вторым запросом просим сохранить любые GET параметры запроса (кроме proxyToken). Коммитим.
// Construct the target URL with all query parameters except proxyToken
const targetUrl = new URL(path, app.apiPath);
// Copy all query parameters except proxyToken
for (const [key, value] of url.searchParams.entries()) {
if (key !== 'proxyToken') {
targetUrl.searchParams.set(key, value);
}
}
(Неплохо же для первого раза в жизни?)
Часть четвертая: свежевание ключей
(8) В смысле — просим создать workflow, который будет рефрешить ключи для всех приложений, у которых осталось меньше 3х часов свежести. И добавить крон, который раз в 2 часа будет запускать воркфлоу.
Он создаёт новый файл с новым кодом, который на мой неопытный глаз вообще выглядит не так, как документация говорит. Даём ему ссылку на документацию и просим сделать согласно актуальной спеки. Он переделывает, код похож, а вот техническая обёртка вокруг — нет. Просим еще раз переделать, сложив всё вместе. Переделывает, поломав и новый и старый код. А я не коммитил! К счастью, после известной истории, «откатить текущий шаг» доступен после каждой рекомендации (причем иногда при редактировании запроса — срабатывает, так как какой‑то из хоткеев редактирования текста работает как «отменить всё»). Откатываем, сливаем файлы вручную. Просим еще раз привести к актуальному виду (дав ссылку). Приводит, поломав всего ничего по дороге. Чиним вручную.
Вручную локальный код работает, workflow локально тестировать невозможно. Фиг с ним, код на первый взгляд делает что просили — коммитим.
Часть пятая: деплоим и тестим на «проде»
(9) Поскольку нельзя нормально Workflow протестировать локально, несмотря на то, что документация говорит обратное (о чем разные сетки врут по‑разному: те, что умеют искать в гугле — находят что нельзя, те, что не умеют — как только ни галлюцинируют) — деплоим.

Спрашиваем как, пробуем, не работает, гуглим, находим, побеждаем. Обновляем вранглер, просим еще раз обновить код (ранее вручную смерженный в один файл) согласно последней документации (даём ссылку на неё) и еще раз полируем после него вручную (он запутался выдал смесь TypeScript и JavaScript).
Просим как быть с реквизитами (созданные для key-value), после трёх итераций сдаёмся, нагугливаем ответ.
(Ответ, кстати, мне не нравится: надо wrangler.toml
внести в.gitignore, и положить пример под другим именем. То есть мержить и держить их в актуальном состоянии — боль — но неважно, это делается на «раз поставил и забыл».)
Окей, как только деплой прошел на ура и приложение ожило — обновляем инструкции и коммитим.
Часть шестая: причесываем
(10) Первое, что бросилось в глаза на тестах: в процессе авторизации приложения слетает сессия админки. Курсор сломался решить проблему: предлагал пучок разных решений, но так и не догадался, что проблема в secure cookie, которые он сам же и проставил с самого начала. Но даже когда я ему объяснил в чем дело — не понял. Пришлось прямо сказать чтоб воткнул в середине процесса восстановление куки и редирект через HTML (то есть не через 302 Location а через 200 + meta‑refresh). В процессе хоть вспомнил зачем HTML редирект делался :))).
(11) Пароли плейнтекстом.

Нет, я всё понимаю, но не надо так. Попросил его. Без обиняков. Просто, мол, сделай пароли солёными.
Он решил пойти простым путём, и если есть логин но нет пароля — первое же использование задаёт пароль. Что примечательно: он сам догадался поправить README, но форму, которая говорит про password123
не стал менять. А я тем более не буду: не барское это дело! Я уже за ним вручную линтеры прогонял и копипастил.
(12) Позже выяснилось, что если Fitbit пофиг, то вот Netatmo таки требует проверки clientSecret
. Просим добавить clientSecret
к приложениям — он добавляет. Просим пописать еще и к рефрешу. Добавляет, радуемся.

Что мы делаем? Выводы
Итого, за несколько присестов в выходные удалось создать желаемое: trmnl-oauth-proxy.
Приложение позволяет быстро развернуть на бесплатном cloudflare тарифе персональный oauth прокси, так что можно создавать и авторизовывать источники данных для своих нужд и легко выводить их в своём TRMNL терминале.

А что на счет вайб кодинга?
Задача решена? Да — плюс. Умеет читать документацию, если ему её показать. Тоже плюс.
Как средство решения задач — еще слишком юно. Требует постоянный глаз да глаз. Норовит пропустить что‑то. Добавить от себя. Решить ну очень не правильным методом. Забывает, что попросили. Истории нет. Часто пытается перегенерировать всё заново, ломая по дороге то, что уже починил. Объём контекста ограничен. Путается в показаниях.
Короче очень юный джун. Но, к сожалению, джун, который не учится. Когда‑нибудь, когда он станет лучше... Возможно. Но сейчас — нет. Работы по проверке за ним больше, чем экономия времени.
Основной плюс AI для программирования для себя: избавиться от чистого листа. Попросить скелет / набросок решения. Выкинуть потом оттуда всё и переписать под себя зачастую быстрее, чем пытаться совсем писать с нуля. Ну, так я уже могу — и тут курсор не единственное решение. Хоть они и были более‑менее первыми — таки платить ему мне не за чем.
Но сколько сеток — столько мнений, так что у читателя может сложиться своё мнение. С удовольствием послушаю в комментария о другом личном опыте!