nak 0.21.0 читает списки релеев и разрешает пути petname
Описание релиза пустое, поэтому единственным источником сведений о нём остаётся diff. Выделяются два добавления: новая подкоманда для списков релеев NIP-65 и разрешение путей petname, встроенное в общий разборщик публичных ключей, а не в одну команду.
Nostr WoT Newsroom
Материал подготовлен редакцией Nostr WoT на основе указанных первоисточников и опубликован автоматически, без индивидуальной проверки человеком.
nak, инструмент командной строки для Nostr, получил тег v0.21.0 3 октября 2026 года. Текст публикации пуст, поэтому семнадцать коммитов с момента v0.20.7 остаются единственным свидетельством того, что изменилось. Два из них добавляют возможности, а не исправляют поведение, и оба опираются на спецификации, о которых этот сайт уже писал.
Команда для списков релеев NIP-65
55707c26 добавляет relays.go, файл на 58 строк, который регистрирует новую подкоманду верхнего уровня. Строка её описания задаёт область применения: prints the nip65 relays for a given pubkey, one relay per line.
Она принимает публичный ключ как аргумент или через стандартный ввод и печатает по одному URL релея на строку. Два флага сужают вывод, и каждый снабжён псевдонимом, называющим вторую половину словаря NIP-65:
--inbox, --read only print relays marked as inbox/read
--outbox, --write only print relays marked as outbox/writeЛогику фильтра стоит читать буквально, потому что совмещённый случай не является объединением. Передача обоих флагов требует обеих отметок на одном релее:
if wantInbox && wantOutbox {
if !(rl.Inbox && rl.Outbox) {
continue
}
}Поэтому --inbox --outbox печатает только те релеи, которые обслуживают оба направления, что по NIP-65 даёт неразмеченный тег r, а если не передать ни одного флага, выводится весь список. Вместе два флага сужают набор, а не расширяют его, и это важно, когда вывод подаётся на шаг публикации.
Названия направлений соответствуют роли, описанной в руководстве по маршрутизации NIP-65, опубликованном сегодня же: из исходящих релеев автора забирают его события, а во входящие релеи получателя доставляют события с его упоминанием. Команда делает обе цели пригодными для скриптов без разбора события kind 10002 вручную.
Пути petname, в общем разборщике
Пути petname из NIP-02 появляются в два этапа, и второй исправляет первый. Это та возможность, которую добавили в NIP-02 в редакции, описанной 20 сентября, и ограничили до ASCII в продолжении три дня спустя.
4011cba5 не добавляет команду. Он меняет общий разборщик: parsePubKey получает второй аргумент, публичный ключ, относительно которого ведётся разрешение, и передаёт всё, что начинается с тильды, в новый resolvePetnamePath.
func parsePubKey(value string, from nostr.PubKey) (nostr.PubKey, error) {
value = strings.TrimPrefix(value, "nostr:")
if strings.HasPrefix(value, "~") {
return resolvePetnamePath(value, from)
}Этот помощник вызывает sys.ResolvePetnamePath с тайм-аутом в пять секунд. Его комментарий описывает механизм и приводит смешанную форму, которую допускает NIP-02: путь ~erin/david/frank проходит по списку подписок каждого имени в цепочке, а первое имя может быть вместо этого идентификатором NIP-05, как в [email protected]/david/frank. Поскольку нижележащий поиск профиля скрывает ошибки NIP-05, неудачное разрешение перепроверяется через nip05.QueryIdentifier, чтобы проблема DNS или HTTP сообщалась как она есть, а не как неразрешимый petname. Коммит обновляет все места вызова и добавляет 239 строк тестов.
Чего этот этап не решает, так это от какого ключа начинается относительный путь. Pull request #220, влитый 25 сентября, добавляет petname_cli.go и обёртку parsePubKeyForCommand, которая классифицирует корень:
absolute := hexErr == nil || nip05.IsValidIdentifier(parts[0]) ||
(nip19Err == nil && (prefix == "npub" || prefix == "nprofile"))Путь, укоренённый в шестнадцатеричном публичном ключе, корректном идентификаторе NIP-05 либо в npub или nprofile, считается абсолютным, и комментарий фиксирует, почему этот случай выделен: Absolute roots must also work without access to a signing key. Только относительный путь вызывает gatherKeyerFromArguments и берёт публичный ключ этого подписывающего за точку отсчёта. Чтение наружу от того, кого можно назвать, не требует ключа, а путь, начинающийся от ваших собственных подписок, требует.
Тот же pull request исправляет проблему порядка аргументов. Вызов в init применяет deferPetnameFlags ко всему дереву команд и заменяет каждый флаг, несущий публичные ключи, обёрткой, которая сохраняет исходную строку и разрешает её лишь после разбора всех флагов. Комментарий объясняет причину: флаг подписывающего, например --sec, может стоять в командной строке после флага petname, а разрешению нужен подписывающий. Он добавляет ещё 169 строк тестов.
Автодополнение и три меньших исправления
5f28b21c выставляет EnableShellCompletion: true на корневой команде, что открывает nak completion bash, zsh и fish. В README добавлены три пути установки для оболочек, чей пакет этого не делает.
Три исправления поведения узки, но каждое закрывает случай, когда инструмент делал что-то бесполезное вместо того, чтобы сообщить о проблеме:
30551476добавляет--githubкnak event, и строка описания объясняет причину:treat empty stdin as no stdin at all, as GitHub Actions always opens it. В этой среде всегда открытый, но пустой стандартный ввод нельзя было отличить от ввода по конвейеру.nak key encryptс единственным аргументом теперь завершается с ошибкойno password given or key piped on stdin, если стандартный ввод не является конвейером, вместо того чтобы читать этот одинокий аргумент как пароль, не имея ключа, к которому его применить.blossomубираетRequired: trueиз флага--server, так что сервер можно задать на уровне подкоманды, а его отсутствие теперь даётno server specified.blossom uploadполучает--auto, который разрешает медиасерверы, объявленные текущим пользователем.nsite downloadпринимает указательnevent1илиnaddr1наряду с URL сайта и забирает данные с релеев записи автора и по подсказкам, которые несёт указатель.
Что это значит на практике
Оба добавления убирают по одному шагу, который прежде делали руками все, кто пишет скрипты для Nostr. Ответ на вопрос, куда публиковать и откуда читать, больше не требует получать и разбирать событие kind 10002, а путь по подпискам можно написать там, где раньше стояла шестнадцатеричная строка из 64 символов. Ни то, ни другое не меняет спецификаций: это инструмент догоняет NIP-02 и NIP-65 в том виде, в каком они уже существуют. Правило абсолютного корня стоит запомнить, потому что путь petname, начинающийся от ваших собственных подписок, попросит ключ.
Источники
Каждое утверждение в этом материале ссылается на первоисточник.
- nak v0.21.0 — fiatjaf/nak (3 октября 2026 г.)
- Сравнение v0.20.7...v0.21.0 — fiatjaf/nak (3 октября 2026 г.)
- nak relays — fiatjaf/nak (1 октября 2026 г.)
- petname support in parsePubKey() — fiatjaf/nak (17 сентября 2026 г.)
- Pull request #220: Resolve relative petnames using the selected signer — fiatjaf/nak (25 сентября 2026 г.)
- enable shell completion generation — fiatjaf/nak (1 октября 2026 г.)
- Correct nak event behaviour if 0 lines received from an open stdin — fiatjaf/nak (25 сентября 2026 г.)