improve documentation and add events http endpoint for filter queries

This commit is contained in:
2025-07-25 20:51:25 +01:00
parent f5c3da9bc3
commit 5b06906673
6 changed files with 644 additions and 29 deletions

1
.gitignore vendored
View File

@@ -104,3 +104,4 @@ pkg/database/testrealy
/.idea/material_theme_project_new.xml
/.idea/orly.iml
/.idea/go.imports.xml
/.idea/inspectionProfiles/Project_Default.xml

View File

@@ -14,7 +14,6 @@ import (
"orly.dev/pkg/encoders/tags"
"orly.dev/pkg/encoders/text"
"orly.dev/pkg/encoders/timestamp"
"orly.dev/pkg/encoders/unix"
"orly.dev/pkg/interfaces/signer"
"orly.dev/pkg/utils/chk"
"orly.dev/pkg/utils/errorf"
@@ -92,6 +91,9 @@ func (ev *E) Id() []byte { return ev.ID }
// CreatedAtInt64 returns the created_at timestamp as a standard int64.
func (ev *E) CreatedAtInt64() (i int64) { return ev.CreatedAt.I64() }
// KindInt returns the kind as an int, as is often needed for JSON.
func (ev *E) KindInt() (i int) { return int(ev.Kind.K) }
// KindInt32 returns the kind as an int32, as is often needed for JSON.
func (ev *E) KindInt32() (i int32) { return int32(ev.Kind.K) }
@@ -109,13 +111,13 @@ func (ev *E) ContentString() (s string) { return string(ev.Content) }
// J is an event.E encoded in more basic types than used in this library.
type J struct {
Id string `json:"id"`
Pubkey string `json:"pubkey"`
CreatedAt unix.Time `json:"created_at"`
Kind int32 `json:"kind"`
Tags [][]string `json:"tags"`
Content string `json:"content"`
Sig string `json:"sig"`
Id string `json:"id" doc:"event id (SHA256 hash of canonical form of event, 64 characters hex)"`
Pubkey string `json:"pubkey" doc:"public key of author of event, required to verify signature (BIP-340 Schnorr public key, 64 characters hex)"`
CreatedAt int64 `json:"created_at" doc:"unix timestamp of time when event was created"`
Kind int `json:"kind" doc:"kind number of event"`
Tags [][]string `json:"tags" doc:"tags that add metadata to the event"`
Content string `json:"content" doc:"content of event"`
Sig string `json:"sig" doc:"signature of event (BIP-340 schnorr signature, 128 characters hex)"`
}
// ToEventJ converts an event.E into an event.J.
@@ -123,8 +125,8 @@ func (ev *E) ToEventJ() (j *J) {
j = &J{}
j.Id = ev.IdString()
j.Pubkey = ev.PubKeyString()
j.CreatedAt = unix.Time{ev.CreatedAt.Time()}
j.Kind = ev.KindInt32()
j.CreatedAt = ev.CreatedAt.I64()
j.Kind = ev.KindInt()
j.Content = ev.ContentString()
j.Tags = ev.Tags.ToStringsSlice()
j.Sig = ev.SigString()
@@ -151,6 +153,13 @@ func (ev *E) KindFromInt32(i int32) {
return
}
// KindFromInt encodes an int representation of a kind.T into an event.E.
func (ev *E) KindFromInt(i int) {
ev.Kind = &kind.T{}
ev.Kind.K = uint16(i)
return
}
// PubKeyFromString decodes a hex-encoded string into the event.E Pubkey field.
func (ev *E) PubKeyFromString(s string) (err error) {
if len(s) != 2*schnorr.PubKeyBytesLen {
@@ -200,8 +209,8 @@ func (e J) ToEvent() (ev *E, err error) {
if err = ev.IdFromString(e.Id); chk.E(err) {
return
}
ev.CreatedAtFromInt64(e.CreatedAt.Unix())
ev.KindFromInt32(e.Kind)
ev.CreatedAtFromInt64(e.CreatedAt)
ev.KindFromInt(e.Kind)
if err = ev.PubKeyFromString(e.Pubkey); chk.E(err) {
return
}

View File

@@ -19,15 +19,62 @@ import (
"orly.dev/pkg/utils/log"
)
var EventBody = &huma.RequestBody{
Description: "a signed nostr event",
Content: map[string]*huma.MediaType{
"application/json": {
Schema: &huma.Schema{
Type: huma.TypeObject,
Properties: map[string]*huma.Schema{
"id": {
Type: huma.TypeString,
Description: "SHA256 hash of event in canonical (JSON array with fixed ordering) form, 64 characters hex",
},
"pubkey": {
Type: huma.TypeString,
Description: "BIP-340 Schnorr public key, 64 characters hex",
},
"created_at": {
Type: huma.TypeInteger,
Description: "unix timestamp of time of event creation",
},
"kind": {
Type: huma.TypeInteger,
Description: "kind number of event",
},
"tags": {
Type: huma.TypeArray,
Description: "array of arrays of strings",
Items: &huma.Schema{
Type: huma.TypeArray,
Items: &huma.Schema{
Type: huma.TypeString,
},
},
},
"content": {
Type: huma.TypeString,
Description: "content of event, escaped using NIP-01 standard escapes and UTF-8 encoding",
},
"sig": {
Type: huma.TypeString,
Description: "BIP-340 Schnorr signature, 128 characters hex",
},
},
},
},
},
}
// EventInput is the parameters for the Event HTTP API method.
type EventInput struct {
Auth string `header:"Authorization" doc:"nostr nip-98 (and expiring variant)" required:"false"`
Accept string `header:"Accept" default:"application/nostr+json"`
Body string `doc:"event JSON"`
Auth string `header:"Authorization" doc:"nostr nip-98 (and expiring variant)" required:"false"`
Accept string `header:"Accept" default:"application/nostr+json"`
Body *event.J `doc:"event JSON"`
}
// EventOutput is the return parameters for the HTTP API Event method.
type EventOutput struct{ Body string }
type EventOutput struct{}
// RegisterEvent is the implementation of the HTTP API Event method.
func (x *Operations) RegisterEvent(api huma.API) {
@@ -43,6 +90,7 @@ func (x *Operations) RegisterEvent(api huma.API) {
Path: path,
Method: method,
Tags: []string{"events"},
RequestBody: EventBody,
Description: helpers.GenerateDescription(description, scopes),
Security: []map[string][]string{{"auth": scopes}},
}, func(ctx context.T, input *EventInput) (
@@ -63,17 +111,13 @@ func (x *Operations) RegisterEvent(api huma.API) {
return
}
}
ev := &event.E{}
var rem []byte
if rem, err = ev.Unmarshal([]byte(input.Body)); chk.T(err) {
var ev *event.E
if ev, err = input.Body.ToEvent(); chk.E(err) {
err = huma.Error422UnprocessableEntity(
"Failed to parse event", err,
"Failed to convert event", err,
)
return
}
if len(rem) > 0 {
log.D.F("remainder:\n%s", rem)
}
// these aliases make it so most of the following code can be copied
// verbatim from its counterpart in socketapi.HandleEvent, with the
// aid of a different implementation of the openapi.OK type.
@@ -393,7 +437,6 @@ func (x *Operations) RegisterEvent(api huma.API) {
return
}
}
output = &EventOutput{"event accepted"}
return
},
)

View File

@@ -4,25 +4,583 @@ import (
"errors"
"github.com/danielgtaylor/huma/v2"
"github.com/dgraph-io/badger/v4"
"math"
"net/http"
"orly.dev/pkg/app/relay/helpers"
"orly.dev/pkg/encoders/event"
"orly.dev/pkg/encoders/filter"
"orly.dev/pkg/encoders/filters"
"orly.dev/pkg/encoders/kind"
"orly.dev/pkg/encoders/tag"
"orly.dev/pkg/encoders/timestamp"
"orly.dev/pkg/protocol/auth"
"orly.dev/pkg/utils/context"
"orly.dev/pkg/utils/log"
"orly.dev/pkg/utils/pointers"
)
type Filter struct {
Ids []string `json:"ids,omitempty"`
Kinds []int `json:"kinds,omitempty"`
Authors []string `json:"authors,omitempty"`
Tag_a []string `json:"#a,omitempty"`
Tag_b []string `json:"#b,omitempty"`
Tag_c []string `json:"#c,omitempty"`
Tag_d []string `json:"#d,omitempty"`
Tag_e []string `json:"#e,omitempty"`
Tag_f []string `json:"#f,omitempty"`
Tag_g []string `json:"#g,omitempty"`
Tag_h []string `json:"#h,omitempty"`
Tag_i []string `json:"#i,omitempty"`
Tag_j []string `json:"#j,omitempty"`
Tag_k []string `json:"#k,omitempty"`
Tag_l []string `json:"#l,omitempty"`
Tag_m []string `json:"#m,omitempty"`
Tag_n []string `json:"#n,omitempty"`
Tag_o []string `json:"#o,omitempty"`
Tag_p []string `json:"#p,omitempty"`
Tag_q []string `json:"#q,omitempty"`
Tag_r []string `json:"#r,omitempty"`
Tag_s []string `json:"#s,omitempty"`
Tag_t []string `json:"#t,omitempty"`
Tag_u []string `json:"#u,omitempty"`
Tag_v []string `json:"#v,omitempty"`
Tag_w []string `json:"#w,omitempty"`
Tag_x []string `json:"#x,omitempty"`
Tag_y []string `json:"#y,omitempty"`
Tag_z []string `json:"#z,omitempty"`
Tag_A []string `json:"#A,omitempty"`
Tag_B []string `json:"#B,omitempty"`
Tag_C []string `json:"#C,omitempty"`
Tag_D []string `json:"#D,omitempty"`
Tag_E []string `json:"#E,omitempty"`
Tag_F []string `json:"#F,omitempty"`
Tag_G []string `json:"#G,omitempty"`
Tag_H []string `json:"#H,omitempty"`
Tag_I []string `json:"#I,omitempty"`
Tag_J []string `json:"#J,omitempty"`
Tag_K []string `json:"#K,omitempty"`
Tag_L []string `json:"#L,omitempty"`
Tag_M []string `json:"#M,omitempty"`
Tag_N []string `json:"#N,omitempty"`
Tag_O []string `json:"#O,omitempty"`
Tag_P []string `json:"#P,omitempty"`
Tag_Q []string `json:"#Q,omitempty"`
Tag_R []string `json:"#R,omitempty"`
Tag_S []string `json:"#S,omitempty"`
Tag_T []string `json:"#T,omitempty"`
Tag_U []string `json:"#U,omitempty"`
Tag_V []string `json:"#V,omitempty"`
Tag_W []string `json:"#W,omitempty"`
Tag_X []string `json:"#X,omitempty"`
Tag_Y []string `json:"#Y,omitempty"`
Tag_Z []string `json:"#Z,omitempty"`
Since *int64 `json:"since,omitempty"`
Until *int64 `json:"until,omitempty"`
Search *string `json:"search,omitempty"`
Limit *int `json:"limit,omitempty"`
}
func (f *Filter) ToFilter() (ff *filter.F) {
ff = filter.New()
// Convert Ids
if f.Ids != nil && len(f.Ids) > 0 {
for _, id := range f.Ids {
ff.Ids.Append([]byte(id))
}
}
if f.Kinds != nil && len(f.Kinds) > 0 {
for _, k := range f.Kinds {
ff.Kinds.K = append(ff.Kinds.K, kind.New(uint16(k)))
}
}
if f.Authors != nil && len(f.Authors) > 0 {
for _, author := range f.Authors {
ff.Authors.Append([]byte(author))
}
}
if f.Since != nil {
ts := timestamp.New(*f.Since)
ff.Since = ts
}
if f.Until != nil {
ts := timestamp.New(*f.Until)
ff.Until = ts
}
if f.Search != nil {
ff.Search = []byte(*f.Search)
}
if f.Limit != nil {
u := uint(*f.Limit)
ff.Limit = &u
}
if f.Tag_a != nil && len(f.Tag_a) > 0 {
t := tag.New("#a")
for _, v := range f.Tag_a {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_b != nil && len(f.Tag_b) > 0 {
t := tag.New("#b")
for _, v := range f.Tag_b {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_c != nil && len(f.Tag_c) > 0 {
t := tag.New("#c")
for _, v := range f.Tag_c {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_d != nil && len(f.Tag_d) > 0 {
t := tag.New("#d")
for _, v := range f.Tag_d {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_e != nil && len(f.Tag_e) > 0 {
t := tag.New("#e")
for _, v := range f.Tag_e {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_f != nil && len(f.Tag_f) > 0 {
t := tag.New("#f")
for _, v := range f.Tag_f {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_g != nil && len(f.Tag_g) > 0 {
t := tag.New("#g")
for _, v := range f.Tag_g {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_h != nil && len(f.Tag_h) > 0 {
t := tag.New("#h")
for _, v := range f.Tag_h {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_i != nil && len(f.Tag_i) > 0 {
t := tag.New("#i")
for _, v := range f.Tag_i {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_j != nil && len(f.Tag_j) > 0 {
t := tag.New("#j")
for _, v := range f.Tag_j {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_k != nil && len(f.Tag_k) > 0 {
t := tag.New("#k")
for _, v := range f.Tag_k {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_l != nil && len(f.Tag_l) > 0 {
t := tag.New("#l")
for _, v := range f.Tag_l {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_m != nil && len(f.Tag_m) > 0 {
t := tag.New("#m")
for _, v := range f.Tag_m {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_n != nil && len(f.Tag_n) > 0 {
t := tag.New("#n")
for _, v := range f.Tag_n {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_o != nil && len(f.Tag_o) > 0 {
t := tag.New("#o")
for _, v := range f.Tag_o {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_p != nil && len(f.Tag_p) > 0 {
t := tag.New("#p")
for _, v := range f.Tag_p {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_q != nil && len(f.Tag_q) > 0 {
t := tag.New("#q")
for _, v := range f.Tag_q {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_r != nil && len(f.Tag_r) > 0 {
t := tag.New("#r")
for _, v := range f.Tag_r {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_s != nil && len(f.Tag_s) > 0 {
t := tag.New("#s")
for _, v := range f.Tag_s {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_t != nil && len(f.Tag_t) > 0 {
t := tag.New("#t")
for _, v := range f.Tag_t {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_u != nil && len(f.Tag_u) > 0 {
t := tag.New("#u")
for _, v := range f.Tag_u {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_v != nil && len(f.Tag_v) > 0 {
t := tag.New("#v")
for _, v := range f.Tag_v {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_w != nil && len(f.Tag_w) > 0 {
t := tag.New("#w")
for _, v := range f.Tag_w {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_x != nil && len(f.Tag_x) > 0 {
t := tag.New("#x")
for _, v := range f.Tag_x {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_y != nil && len(f.Tag_y) > 0 {
t := tag.New("#y")
for _, v := range f.Tag_y {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_z != nil && len(f.Tag_z) > 0 {
t := tag.New("#z")
for _, v := range f.Tag_z {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_A != nil && len(f.Tag_A) > 0 {
t := tag.New("#A")
for _, v := range f.Tag_A {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_B != nil && len(f.Tag_B) > 0 {
t := tag.New("#B")
for _, v := range f.Tag_B {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_C != nil && len(f.Tag_C) > 0 {
t := tag.New("#C")
for _, v := range f.Tag_C {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_D != nil && len(f.Tag_D) > 0 {
t := tag.New("#D")
for _, v := range f.Tag_D {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_E != nil && len(f.Tag_E) > 0 {
t := tag.New("#E")
for _, v := range f.Tag_E {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_F != nil && len(f.Tag_F) > 0 {
t := tag.New("#F")
for _, v := range f.Tag_F {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_G != nil && len(f.Tag_G) > 0 {
t := tag.New("#G")
for _, v := range f.Tag_G {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_H != nil && len(f.Tag_H) > 0 {
t := tag.New("#H")
for _, v := range f.Tag_H {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_I != nil && len(f.Tag_I) > 0 {
t := tag.New("#I")
for _, v := range f.Tag_I {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_J != nil && len(f.Tag_J) > 0 {
t := tag.New("#J")
for _, v := range f.Tag_J {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_K != nil && len(f.Tag_K) > 0 {
t := tag.New("#K")
for _, v := range f.Tag_K {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_L != nil && len(f.Tag_L) > 0 {
t := tag.New("#L")
for _, v := range f.Tag_L {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_M != nil && len(f.Tag_M) > 0 {
t := tag.New("#M")
for _, v := range f.Tag_M {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_N != nil && len(f.Tag_N) > 0 {
t := tag.New("#N")
for _, v := range f.Tag_N {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_O != nil && len(f.Tag_O) > 0 {
t := tag.New("#O")
for _, v := range f.Tag_O {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_P != nil && len(f.Tag_P) > 0 {
t := tag.New("#P")
for _, v := range f.Tag_P {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_Q != nil && len(f.Tag_Q) > 0 {
t := tag.New("#Q")
for _, v := range f.Tag_Q {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_R != nil && len(f.Tag_R) > 0 {
t := tag.New("#R")
for _, v := range f.Tag_R {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_S != nil && len(f.Tag_S) > 0 {
t := tag.New("#S")
for _, v := range f.Tag_S {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_T != nil && len(f.Tag_T) > 0 {
t := tag.New("#T")
for _, v := range f.Tag_T {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_U != nil && len(f.Tag_U) > 0 {
t := tag.New("#U")
for _, v := range f.Tag_U {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_V != nil && len(f.Tag_V) > 0 {
t := tag.New("#V")
for _, v := range f.Tag_V {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_W != nil && len(f.Tag_W) > 0 {
t := tag.New("#W")
for _, v := range f.Tag_W {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_X != nil && len(f.Tag_X) > 0 {
t := tag.New("#X")
for _, v := range f.Tag_X {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_Y != nil && len(f.Tag_Y) > 0 {
t := tag.New("#Y")
for _, v := range f.Tag_Y {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
if f.Tag_Z != nil && len(f.Tag_Z) > 0 {
t := tag.New("#Z")
for _, v := range f.Tag_Z {
t.Append([]byte(v))
}
ff.Tags.AppendTags(t)
}
return
}
var exampleSince int64 = 1753432853
var exampleUntil int64 = 1753462853
var exampleLimit int = 20
var created_atMinimum float64 = 0
var created_atMaximum float64 = float64(math.MaxInt64)
var limitMinimum float64 = 0
var limitMaximum float64 = float64(math.MaxUint64)
var EventsBody = &huma.RequestBody{
Description: "array of nostr events",
Content: map[string]*huma.MediaType{
"application/json": {
Schema: &huma.Schema{
Type: huma.TypeObject,
Examples: []any{
Filter{
Kinds: []int{0, 1},
Authors: []string{
"deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008",
"deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008",
},
Tag_e: []string{
"deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008",
"deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008",
"deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008",
"deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008",
},
Since: &exampleSince,
Until: &exampleUntil,
Limit: &exampleLimit,
},
Filter{
Ids: []string{
"deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008",
"deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008",
},
},
},
Properties: map[string]*huma.Schema{
"ids": {
Type: huma.TypeArray,
Description: "list of event IDs to search for (if present, all other fields are excluded)",
Items: &huma.Schema{
Type: huma.TypeString,
},
},
"kinds": {
Type: huma.TypeArray,
Description: "list of event kinds to search for",
Items: &huma.Schema{
Type: huma.TypeInteger,
},
},
"authors": {
Type: huma.TypeArray,
Description: "list of pubkeys to search for",
Items: &huma.Schema{
Type: huma.TypeString,
},
},
"^#[a-zA-Z]$": {
Type: huma.TypeArray,
Description: "list of tag values to search for",
Items: &huma.Schema{
Type: huma.TypeString,
},
},
"since": {
Type: huma.TypeInteger,
Description: "earliest (smallest, inclusive) created_at value for events",
Minimum: &created_atMinimum,
Maximum: &created_atMaximum,
},
"until": {
Type: huma.TypeInteger,
Description: "latest (largest, inclusive) created_at value for events",
Minimum: &created_atMinimum,
Maximum: &created_atMaximum,
},
"limit": {
Type: huma.TypeInteger,
Description: "maximum number of events to return (newest first, reverse chronological order)",
Minimum: &limitMinimum,
Maximum: &limitMaximum,
},
},
},
},
},
}
type EventsInput struct {
Auth string `header:"Authorization" doc:"nostr nip-98 (and expiring variant)" required:"false"`
Accept string `header:"Accept" default:"application/nostr+json"`
Body []byte `doc:"filter JSON (standard NIP-01 filter syntax)"`
Auth string `header:"Authorization" doc:"nostr nip-98 (and expiring variant)" required:"false"`
Accept string `header:"Accept" default:"application/nostr+json"`
Body *Filter `doc:"filter JSON (standard NIP-01 filter syntax)"`
}
type EventsOutput struct {
Body []byte
Body []event.J
}
// RegisterEvents is the implementation of the HTTP API Events method.
@@ -42,6 +600,7 @@ func (x *Operations) RegisterEvents(api huma.API) {
Path: path,
Method: method,
Tags: []string{"events"},
RequestBody: EventsBody,
Description: helpers.GenerateDescription(description, scopes),
Security: []map[string][]string{{"auth": scopes}},
}, func(ctx context.T, input *EventsInput) (

View File

@@ -20,7 +20,9 @@ type ExportOutput struct{ RawBody []byte }
// RegisterExport implements the Export HTTP API method.
func (x *Operations) RegisterExport(api huma.API) {
name := "Export"
description := "Export all events (only works with NIP-98 capable client, will not work with UI)"
description := `Export all events (only works with NIP-98 capable client, will not work with UI)
Returns the events as line structured JSON (JSONL) in the order that they were received by the relay.`
path := x.path + "/export"
scopes := []string{"admin", "read"}
method := http.MethodGet

View File

@@ -16,6 +16,7 @@ import (
// stream of line structured JSON events.
type ImportInput struct {
Auth string `header:"Authorization" doc:"nostr nip-98 (and expiring variant) token for authentication" required:"true"`
Body string `doc:"events in line structured JSON (JSONL)"`
}
// ImportOutput is nothing, basically; a 204 or 200 status is expected.