Compare commits

...

3 Commits

Author SHA1 Message Date
fiatjaf d3975679e4 add labels to subscriptions for easier debugging. 2025-08-14 13:28:15 -03:00
fiatjaf 23e27da077 use isatty for detecting stuff for the fancy output (it doesn't work). 2025-08-14 13:28:15 -03:00
fiatjaf 1a221a133c cleanup and fix readme. 2025-08-14 13:28:15 -03:00
8 changed files with 34 additions and 34 deletions

View File

@ -3,6 +3,8 @@
install with `go install github.com/fiatjaf/nak@latest` or install with `go install github.com/fiatjaf/nak@latest` or
[download a binary](https://github.com/fiatjaf/nak/releases). [download a binary](https://github.com/fiatjaf/nak/releases).
or get the source with `git clone https://github.com/fiatjaf/nak` then install with `go install` or run with docker using `docker build -t nak . && docker run nak event`.
## what can you do with it? ## what can you do with it?
take a look at the help text that comes in it to learn all possibilities, but here are some: take a look at the help text that comes in it to learn all possibilities, but here are some:
@ -128,17 +130,13 @@ type the password to decrypt your secret key: **********
985d66d2644dfa7676e26046914470d66ebc7fa783a3f57f139fde32d0d631d7 985d66d2644dfa7676e26046914470d66ebc7fa783a3f57f139fde32d0d631d7
``` ```
### sign an event using [Amber](https://github.com/greenart7c3/Amber) (or other bunker provider) ### sign an event using a bunker provider (amber, promenade etc)
```shell ```shell
~> export NOSTR_CLIENT_KEY="$(nak key generate)" ~> export NOSTR_CLIENT_KEY="$(nak key generate)"
~> nak event --sec 'bunker://a9e0f110f636f3191644110c19a33448daf09d7cda9708a769e91b7e91340208?relay=wss%3A%2F%2Frelay.damus.io&relay=wss%3A%2F%2Frelay.nsecbunker.com&relay=wss%3A%2F%2Fnos.lol&secret=TWfGbjQCLxUf' -c 'hello from bunker' ~> nak event --sec 'bunker://a9e0f110f636f3191644110c19a33448daf09d7cda9708a769e91b7e91340208?relay=wss%3A%2F%2Frelay.damus.io&relay=wss%3A%2F%2Frelay.nsecbunker.com&relay=wss%3A%2F%2Fnos.lol&secret=TWfGbjQCLxUf' -c 'hello from bunker'
``` ```
> [!IMPORTANT] (in most cases it's better to set `NOSTR_CLIENT_KEY` permanently on your shell, as that identity will be recorded by the bunker provider.)
> Remember to set a `NOSTR_CLIENT_KEY` permanently on your shell, otherwise you'll only be able to use the bunker once. For `bash`:
> ```shell
> echo 'export NOSTR_CLIENT_KEY="$(nak key generate)"' >> ~/.bashrc
> ```
### sign an event using a NIP-49 encrypted key ### sign an event using a NIP-49 encrypted key
```shell ```shell
@ -180,16 +178,11 @@ you can also display a QR code for the bunker URI by adding the `--qrcode` flag:
~> nak bunker --qrcode --sec ncryptsec1... relay.damus.io ~> nak bunker --qrcode --sec ncryptsec1... relay.damus.io
``` ```
### start a bunker that persists its metadata to disc ### start a bunker that persists its metadata (secret key, relays, authorized client pubkeys) to disc
```shell ```shell
~> nak bunker --persist --sec ncryptsec1... relay.nsec.app nos.lol ~> nak bunker --persist --sec ncryptsec1... relay.nsec.app nos.lol
``` ```
> [!CAUTION]
> when you start a bunker with `--persist` or `--profile`, it will store `--sec` credentials and authorized keys in
> `~/.config/nak/bunker`. if you don't want your private key to be stored in plain text, you can
> [encrypt it with NIP-49](#encrypt-key-with-nip-49) it beforehand.
```shell ```shell
then later just then later just
@ -250,7 +243,7 @@ type the password to decrypt your secret key: ********
~> nak req -i 412f2d3e73acc312942c055ac2a695dc60bf58ff97e06689a8a79e97796c4cdb relay.westernbtc.com | jq -r .content > ~/.jq ~> nak req -i 412f2d3e73acc312942c055ac2a695dc60bf58ff97e06689a8a79e97796c4cdb relay.westernbtc.com | jq -r .content > ~/.jq
``` ```
### watch a NIP-53 livestream (zap.stream etc) ### watch a NIP-53 livestream (zap.stream, amethyst, shosho etc)
```shell ```shell
~> # this requires the jq utils from the step above ~> # this requires the jq utils from the step above
~> mpv $(nak fetch naddr1qqjxvvm9xscnsdtx95cxvcfk956rsvtx943rje3k95mx2dp389jnwwrp8ymxgqg4waehxw309aex2mrp0yhxgctdw4eju6t09upzpn6956apxcad0mfp8grcuugdysg44eepex68h50t73zcathmfs49qvzqqqrkvu7ed38k | jq -r 'tag_value("streaming")') ~> mpv $(nak fetch naddr1qqjxvvm9xscnsdtx95cxvcfk956rsvtx943rje3k95mx2dp389jnwwrp8ymxgqg4waehxw309aex2mrp0yhxgctdw4eju6t09upzpn6956apxcad0mfp8grcuugdysg44eepex68h50t73zcathmfs49qvzqqqrkvu7ed38k | jq -r 'tag_value("streaming")')
@ -307,20 +300,12 @@ echo "#surely you're joking, mr npub1l2vyh47mk2p0qlsku7hg0vn29faehy9hy34ygaclpn6
# and there is a --confirm flag that gives you a chance to confirm before actually publishing the result to relays. # and there is a --confirm flag that gives you a chance to confirm before actually publishing the result to relays.
``` ```
### record and publish an audio note of 10s (yakbak etc) signed from a bunker ### record and publish an audio note (yakbak, nostur etc) signed from a bunker
```shell ```shell
ffmpeg -f alsa -i default -f webm -t 00:00:03 pipe:1 | nak blossom --server blossom.primal.net upload | jq -rc '{content: .url}' | nak event -k 1222 --sec 'bunker://urlgoeshere' pyramid.fiatjaf.com nostr.wine ffmpeg -f alsa -i default -f webm -t 00:00:03 pipe:1 | nak blossom --server blossom.primal.net upload | jq -rc '{content: .url}' | nak event -k 1222 --sec 'bunker://urlgoeshere' pyramid.fiatjaf.com nostr.wine
``` ```
### from a file with events get only those that have kind 1111 and were created by a given pubkey ### from a file with events get only those that have kind 1111 and were created by a given pubkey
```shell ```shell
~> cat all.jsonl | nak filter -k 1111 > filtered.jsonl ~> cat all.jsonl | nak filter -k 1111 -a 117673e191b10fe1aedf1736ee74de4cffd4c132ca701960b70a5abad5870faa > filtered.jsonl
```
### run nak in Docker
If you want to run nak inside a container (i.e. to run nak as a server, or to avoid installing the Go toolchain) you can run it with Docker:
```shell
docker build -t nak .
docker run nak event
``` ```

View File

@ -141,7 +141,9 @@ var count = &cli.Command{
} }
for _, relayUrl := range relayUrls { for _, relayUrl := range relayUrls {
relay, _ := sys.Pool.EnsureRelay(relayUrl) relay, _ := sys.Pool.EnsureRelay(relayUrl)
count, hllRegisters, err := relay.Count(ctx, filter, nostr.SubscriptionOptions{}) count, hllRegisters, err := relay.Count(ctx, filter, nostr.SubscriptionOptions{
Label: "nak-count",
})
fmt.Fprintf(os.Stderr, "%s%s: ", strings.Repeat(" ", biggerUrlSize-len(relayUrl)), relayUrl) fmt.Fprintf(os.Stderr, "%s%s: ", strings.Repeat(" ", biggerUrlSize-len(relayUrl)), relayUrl)
if err != nil { if err != nil {

View File

@ -106,7 +106,9 @@ var fetch = &cli.Command{
continue continue
} }
for ie := range sys.Pool.FetchMany(ctx, relays, filter, nostr.SubscriptionOptions{}) { for ie := range sys.Pool.FetchMany(ctx, relays, filter, nostr.SubscriptionOptions{
Label: "nak-fetch",
}) {
stdout(ie.Event) stdout(ie.Event)
} }
} }

6
go.mod
View File

@ -16,6 +16,7 @@ require (
github.com/mailru/easyjson v0.9.0 github.com/mailru/easyjson v0.9.0
github.com/mark3labs/mcp-go v0.8.3 github.com/mark3labs/mcp-go v0.8.3
github.com/markusmobius/go-dateparser v1.2.3 github.com/markusmobius/go-dateparser v1.2.3
github.com/mattn/go-isatty v0.0.20
github.com/mattn/go-tty v0.0.7 github.com/mattn/go-tty v0.0.7
github.com/mdp/qrterminal/v3 v3.2.1 github.com/mdp/qrterminal/v3 v3.2.1
github.com/stretchr/testify v1.10.0 github.com/stretchr/testify v1.10.0
@ -56,7 +57,6 @@ require (
github.com/kylelemons/godebug v1.1.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect
github.com/magefile/mage v1.14.0 // indirect github.com/magefile/mage v1.14.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
@ -76,9 +76,11 @@ require (
golang.org/x/crypto v0.36.0 // indirect golang.org/x/crypto v0.36.0 // indirect
golang.org/x/net v0.37.0 // indirect golang.org/x/net v0.37.0 // indirect
golang.org/x/sync v0.16.0 // indirect golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.33.0 // indirect golang.org/x/sys v0.34.0 // indirect
golang.org/x/text v0.23.0 // indirect golang.org/x/text v0.23.0 // indirect
google.golang.org/protobuf v1.36.2 // indirect google.golang.org/protobuf v1.36.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
rsc.io/qr v0.2.0 // indirect rsc.io/qr v0.2.0 // indirect
) )
replace fiatjaf.com/nostr => ../nostrlib

6
go.sum
View File

@ -1,8 +1,6 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
fiatjaf.com/lib v0.3.1 h1:/oFQwNtFRfV+ukmOCxfBEAuayoLwXp4wu2/fz5iHpwA= fiatjaf.com/lib v0.3.1 h1:/oFQwNtFRfV+ukmOCxfBEAuayoLwXp4wu2/fz5iHpwA=
fiatjaf.com/lib v0.3.1/go.mod h1:Ycqq3+mJ9jAWu7XjbQI1cVr+OFgnHn79dQR5oTII47g= fiatjaf.com/lib v0.3.1/go.mod h1:Ycqq3+mJ9jAWu7XjbQI1cVr+OFgnHn79dQR5oTII47g=
fiatjaf.com/nostr v0.0.0-20250715161459-840e2846ed15 h1:XQq9DyW9j14wRKCU0cNyBUDCjJO6HAm+rK9abLLJKes=
fiatjaf.com/nostr v0.0.0-20250715161459-840e2846ed15/go.mod h1:lJ9x/Ehcq/7x2mf6iMlC4AOjPUh3WbfLMY+3PyaPRNs=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/FastFilter/xorfilter v0.2.1 h1:lbdeLG9BdpquK64ZsleBS8B4xO/QW1IM0gMzF7KaBKc= github.com/FastFilter/xorfilter v0.2.1 h1:lbdeLG9BdpquK64ZsleBS8B4xO/QW1IM0gMzF7KaBKc=
github.com/FastFilter/xorfilter v0.2.1/go.mod h1:aumvdkhscz6YBZF9ZA/6O4fIoNod4YR50kIVGGZ7l9I= github.com/FastFilter/xorfilter v0.2.1/go.mod h1:aumvdkhscz6YBZF9ZA/6O4fIoNod4YR50kIVGGZ7l9I=
@ -269,8 +267,8 @@ golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@ -24,6 +24,7 @@ import (
"github.com/chzyer/readline" "github.com/chzyer/readline"
"github.com/fatih/color" "github.com/fatih/color"
jsoniter "github.com/json-iterator/go" jsoniter "github.com/json-iterator/go"
"github.com/mattn/go-isatty"
"github.com/mattn/go-tty" "github.com/mattn/go-tty"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"golang.org/x/term" "golang.org/x/term"
@ -315,6 +316,10 @@ func supportsDynamicMultilineMagic() bool {
return false return false
} }
if !isatty.IsTerminal(os.Stdout.Fd()) {
return false
}
width, _, err := term.GetSize(int(os.Stderr.Fd())) width, _, err := term.GetSize(int(os.Stderr.Fd()))
if err != nil { if err != nil {
return false return false

8
mcp.go
View File

@ -165,7 +165,9 @@ var mcpServer = &cli.Command{
res := strings.Builder{} res := strings.Builder{}
res.WriteString("Search results: ") res.WriteString("Search results: ")
l := 0 l := 0
for result := range sys.Pool.FetchMany(ctx, []string{"relay.nostr.band", "nostr.wine"}, filter, nostr.SubscriptionOptions{}) { for result := range sys.Pool.FetchMany(ctx, []string{"relay.nostr.band", "nostr.wine"}, filter, nostr.SubscriptionOptions{
Label: "nak-mcp-search",
}) {
l++ l++
pm, _ := sdk.ParseMetadata(result.Event) pm, _ := sdk.ParseMetadata(result.Event)
res.WriteString(fmt.Sprintf("\n\nResult %d\nUser name: \"%s\"\nPublic key: \"%s\"\nDescription: \"%s\"\n", res.WriteString(fmt.Sprintf("\n\nResult %d\nUser name: \"%s\"\nPublic key: \"%s\"\nDescription: \"%s\"\n",
@ -219,7 +221,9 @@ var mcpServer = &cli.Command{
} }
} }
events := sys.Pool.FetchMany(ctx, []string{relay}, filter, nostr.SubscriptionOptions{}) events := sys.Pool.FetchMany(ctx, []string{relay}, filter, nostr.SubscriptionOptions{
Label: "nak-mcp-profile-events",
})
result := strings.Builder{} result := strings.Builder{}
for ie := range events { for ie := range events {

4
req.go
View File

@ -154,7 +154,9 @@ example:
fn = sys.Pool.SubscribeMany fn = sys.Pool.SubscribeMany
} }
for ie := range fn(ctx, relayUrls, filter, nostr.SubscriptionOptions{}) { for ie := range fn(ctx, relayUrls, filter, nostr.SubscriptionOptions{
Label: "nak-req",
}) {
stdout(ie.Event) stdout(ie.Event)
} }
} }