From e9c4deaf6d9a6d01a938303ba7d35e2c20e6ffa7 Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Tue, 23 Dec 2025 21:31:54 -0300 Subject: [PATCH] nak req --spell for creating spells. --- req.go | 30 ++++++++++++++++++++--- spell.go | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 3 deletions(-) diff --git a/req.go b/req.go index 3ca109c..b43efb3 100644 --- a/req.go +++ b/req.go @@ -92,6 +92,10 @@ example: Usage: "after connecting, for a nip42 \"AUTH\" message to be received, act on it and only then send the \"REQ\"", Category: CATEGORY_SIGNER, }, + &cli.BoolFlag{ + Name: "spell", + Usage: "output a spell event (kind 777) instead of a filter", + }, )..., ), ArgsUsage: "[relay...]", @@ -111,7 +115,16 @@ example: return fmt.Errorf("incompatible flags --paginate and --outbox") } + if c.Bool("bare") && c.Bool("spell") { + return fmt.Errorf("incompatible flags --bare and --spell") + } + relayUrls := c.Args().Slice() + + if len(relayUrls) > 0 && (c.Bool("bare") || c.Bool("spell")) { + return fmt.Errorf("relay URLs are incompatible with --bare or --spell") + } + if len(relayUrls) > 0 && !negentropy { // this is used both for the normal AUTH (after "auth-required:" is received) or forced pre-auth // connect to all relays we expect to use in this call in parallel @@ -225,15 +238,26 @@ example: performReq(ctx, filter, relayUrls, c.Bool("stream"), c.Bool("outbox"), c.Uint("outbox-relays-per-pubkey"), c.Bool("paginate"), c.Duration("paginate-interval"), "nak-req") } } else { - // no relays given, will just print the filter + // no relays given, will just print the filter or spell var result string - if c.Bool("bare") { + if c.Bool("spell") { + // output a spell event instead of a filter + kr, _, err := gatherKeyerFromArguments(ctx, c) + if err != nil { + return err + } + spellEvent := createSpellEvent(ctx, filter, kr) + j, _ := json.Marshal(spellEvent) + result = string(j) + } else if c.Bool("bare") { + // bare filter output result = filter.String() } else { + // normal filter j, _ := json.Marshal(nostr.ReqEnvelope{SubscriptionID: "nak", Filters: []nostr.Filter{filter}}) result = string(j) - } + } stdout(result) } } diff --git a/spell.go b/spell.go index e6d3252..146a62b 100644 --- a/spell.go +++ b/spell.go @@ -471,3 +471,77 @@ func logSpellDetails(spell nostr.Event) { desc, ) } + +func createSpellEvent(ctx context.Context, filter nostr.Filter, kr nostr.Keyer) nostr.Event { + spell := nostr.Event{ + Kind: 777, + Tags: make(nostr.Tags, 0), + } + + // add cmd tag + spell.Tags = append(spell.Tags, nostr.Tag{"cmd", "REQ"}) + + // add kinds + if len(filter.Kinds) > 0 { + kindTag := nostr.Tag{"k"} + for _, kind := range filter.Kinds { + kindTag = append(kindTag, strconv.Itoa(int(kind))) + } + spell.Tags = append(spell.Tags, kindTag) + } + + // add authors + if len(filter.Authors) > 0 { + authorsTag := nostr.Tag{"authors"} + for _, author := range filter.Authors { + authorsTag = append(authorsTag, author.Hex()) + } + spell.Tags = append(spell.Tags, authorsTag) + } + + // add ids + if len(filter.IDs) > 0 { + idsTag := nostr.Tag{"ids"} + for _, id := range filter.IDs { + idsTag = append(idsTag, id.Hex()) + } + spell.Tags = append(spell.Tags, idsTag) + } + + // add tags + for tagName, values := range filter.Tags { + if len(values) > 0 { + tag := nostr.Tag{"tag", tagName} + for _, value := range values { + tag = append(tag, value) + } + spell.Tags = append(spell.Tags, tag) + } + } + + // add limit + if filter.Limit > 0 { + spell.Tags = append(spell.Tags, nostr.Tag{"limit", strconv.Itoa(filter.Limit)}) + } + + // add since + if filter.Since > 0 { + spell.Tags = append(spell.Tags, nostr.Tag{"since", strconv.FormatInt(int64(filter.Since), 10)}) + } + + // add until + if filter.Until > 0 { + spell.Tags = append(spell.Tags, nostr.Tag{"until", strconv.FormatInt(int64(filter.Until), 10)}) + } + + // add search + if filter.Search != "" { + spell.Tags = append(spell.Tags, nostr.Tag{"search", filter.Search}) + } + + if err := kr.SignEvent(ctx, &spell); err != nil { + log("failed to sign spell: %s\n", err) + } + + return spell +}