-
Notifications
You must be signed in to change notification settings - Fork 541
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NIP-22 - Generic Comment #1233
base: master
Are you sure you want to change the base?
NIP-22 - Generic Comment #1233
Changes from all commits
75b02b3
bccd745
1c34174
61addbd
a52b483
a6a71cd
6af79cb
278601d
194d1d7
820eb3d
056d9bc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
NIP-22 | ||
====== | ||
|
||
Comment | ||
------- | ||
|
||
`draft` `optional` | ||
|
||
A comment is meant to be used to comment on | ||
or reply to anything except event kinds | ||
whose specifications have already defined other | ||
ways to comment on or reply to them. | ||
|
||
For example, it can be used to comment on a [NIP-23](23.md) `kind:30023` nostr blog post | ||
or on an off-nostr news article or to reply to another comment. | ||
|
||
## Structure | ||
|
||
A comment is an event of `kind:1111` with plaintext `.content` | ||
(no HTML, no Markdown nor other formatting). | ||
|
||
**It must have a `k` tag** pointing to the kind of the subject being commented on. | ||
Its value has a prefix: `"n:"` for nostr subjects and other prefixes (listed in a section ahead) | ||
for things that aren't nostr events. | ||
|
||
For example, when commenting on a `kind:30023`, the `k` tag is set to "n:30023". | ||
When replying to another `kind:1111`, the `k` tag is set to "n:1111". | ||
|
||
The `k` tag is useful to fetch top-level comments about events of specific types, for example, | ||
by filtering with `{ "#k": ["n:30023"], "kinds": [1111] }`. | ||
Comment on lines
+22
to
+30
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do not see the point of trying to get top level replies only, and we should just keep a tag that specifies the top level note's kind. Could we not implement non-existence filters and check for the existence for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunatelly, non-existence filters are a dream that will never come true, according to previous 3 or so discussions about it on this repo. On the lowercase There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Which ones? They can happen without much performance penalty. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I honestly wouldn't dismiss it based off of those opinions. You don't actually need a tag exists/doesn't exist index, as 99.99% of tag nonexistence queries come attached with other indexable fields (kind, other tags, author). I will make a PR soon. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe @mikedilger said the same thing at #683. The caveat is relay may end up returning less events than the requested (even if there were more on DB) - of course considering client didn't request with a bizarre limit like Clients would lose the ability of figuring out if there are more events to fetch depending on the number of returned events. Like, if client wants chunks of 5 events, it requests 6. If relay returns 6, client knows it should ask for more. |
||
|
||
**An uppercase `K` tag must also be present.** The difference is that it is set to the original post (the one starting the thread) kind. | ||
This way a client can request all comments related to the kind it supports, not only the top-level comments. | ||
|
||
### Threads | ||
|
||
**There is always an `o` tag** pointing to the original post that started the thread. | ||
Its value can be an event id (with an `"e:"` prefix), | ||
an event address (`"a:"` prefix) or others shown at below section. The second value | ||
is the optional recommended relay url where the referenced event may be found. | ||
This tag is useful to load all messages of a thread at once. | ||
|
||
Note that if commenting on a replaceable event, one can choose to add both id and address references. | ||
|
||
After the first value, the `o` tag may have a variable number of `<key><space-separator><value>` fields | ||
at any order. When the tag references an event id, both a a [NIP-65](65.md) pubkey hint and a relay hint | ||
are recommended fields while for an event address, just the relay hint. | ||
|
||
Examples: | ||
|
||
- `["o", "e:<event-id>", "p <event-pubkey, optional>", "r <relay-url, optional>"]` | ||
- `["o", "a:<event-kind>:<event-pubkey>:<d-tag, optional>", "r <relay-url, optional>"]` | ||
|
||
Also, **there is always an `r` tag** pointing to the subject being directly commented on or replied to, using the | ||
same structure of the `o` tag. | ||
This tag is useful to lazily load a thread. | ||
|
||
### Other possible `o`/`r` tag values and their corresponding `K/k` tag values | ||
|
||
| `o`/`r` tag | corresponding `K/k` tag | | ||
| - | - | | ||
| "r:`<url>`" | "r:`<domain>`" | | ||
| "i:`<nip-73-id>`" | "i:`<nip-73-kind>`" | | ||
| "t:`<topic>`" | "#:t" | | ||
| "g:`<geohash>`" | "#:g" | | ||
|
||
#### Thread Relays | ||
|
||
If the original post being commented on is a nostr event and | ||
the client supports the [NIP-65](65.md) relay usage spec, | ||
`kind:1111` events should be sent atleast to the original post author's `read` relays. | ||
|
||
### Event Examples | ||
|
||
```js | ||
{ | ||
kind: 1111, | ||
content: 'Agree with your comment.', | ||
tags: [ | ||
// referencing the OP | ||
["o", "r:https://abc.com/articles/1"], | ||
// replying to a parent kind:1111 comment | ||
["r", "e:5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36", "p f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca", "r wss://example.relay"], | ||
// the OP "kind"; for an url, the kind is its domain | ||
["K", "r:https://abc.com"] | ||
// the parent kind | ||
["k", "n:1111"] | ||
] | ||
// other fields | ||
} | ||
``` | ||
|
||
```js | ||
{ | ||
kind: 1111, | ||
content: 'Great blog post! Check this out nostr:npub1sn0wdenkukak0d9dfczzeacvhkrgz92ak56egt7vdgzn8pv2wfqqhrjdv9.', | ||
tags: [ | ||
// top-level comments have the same o and r tags | ||
["o", "a:30023:3c9849383bdea883b0bd16fece1ed36d37e37cdde3ce43b17ea4e9192ec11289:f9347ca7", "r wss://example.relay"], | ||
["r", "a:30023:3c9849383bdea883b0bd16fece1ed36d37e37cdde3ce43b17ea4e9192ec11289:f9347ca7", "r wss://example.relay"], | ||
// the OP kind | ||
["K", "n:30023"] | ||
// the parent kind | ||
["k", "n:30023"], | ||
// the nostr:npub1... mentioned on .content | ||
["p", "84dee6e676e5bb67b4ad4e042cf70cbd8681155db535942fcc6a0533858a7240"] | ||
] | ||
// other fields | ||
} | ||
``` | ||
|
||
Note that ideally there are no `p` tags unless the pubkey is being mentioned on the `.content`. | ||
|
||
### Examples for Commenting on NIP-73 External Content | ||
|
||
A podcast comment example: | ||
|
||
```js | ||
{ | ||
id: "80c48d992a38f9c445b943a9c9f1010b396676013443765750431a9004bdac05", | ||
pubkey: "f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca", | ||
kind: 1111, | ||
content: "This was a great episode!", | ||
tags: [ | ||
[ | ||
"o", | ||
"i:podcast:item:guid:d98d189b-dc7b-45b1-8720-d4b98690f31f", | ||
// note the "r" followed by a space then the url hint | ||
"r https://fountain.fm/episode/z1y9TMQRuqXl2awyrQxg" | ||
], | ||
// same value as "o" tag above, because it is a top-level comment (not a reply to a comment) | ||
[ | ||
"r", | ||
"i:podcast:item:guid:d98d189b-dc7b-45b1-8720-d4b98690f31f", | ||
"r https://fountain.fm/episode/z1y9TMQRuqXl2awyrQxg" | ||
], | ||
|
||
["K", "i:podcast:item:guid"], // uppercase K, this is the OP (original post)'s kind, that is, a podcast item | ||
["k", "i:podcast:item:guid"] // lowercase k; in the case of a top-level comment, it is the same as the uppercase K | ||
], | ||
created_at: 1723748973 | ||
} | ||
``` | ||
|
||
A reply to a podcast comment example: | ||
|
||
```js | ||
{ | ||
kind: 1111, | ||
content: "I'm replying to the above comment.", | ||
tags: [ | ||
[ | ||
"o", | ||
"i:podcast:item:guid:d98d189b-dc7b-45b1-8720-d4b98690f31f", | ||
"r https://fountain.fm/episode/z1y9TMQRuqXl2awyrQxg" | ||
], | ||
// the "r" tag is a reference to the above comment | ||
[ | ||
"r", | ||
// "e:"<id-of-the-above-comment> | ||
"e:80c48d992a38f9c445b943a9c9f1010b396676013443765750431a9004bdac05", | ||
// "p"<space><pubkey-of-the-above-comment-author> | ||
"p f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca", | ||
// "r"<space><url-of-the-relay-where-above-comment-was-fetched-from> | ||
"r wss://example.relay" | ||
], | ||
|
||
["K", "i:podcast:item:guid"], // uppercase K, this is the OP (original post)'s kind, that is, a podcast item | ||
["k", "n:1111"] // lowercase k; this is the above comment's kind | ||
] | ||
// other fields | ||
} | ||
``` | ||
|
||
Note that for podcast items, the K or k tag is `i:podcast:item:guid`, | ||
for books it is `i:isbn` while for movies it is `i:isan`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why prefix with
n
? Seems like it would be better to just use ints for kinds like we do elsewhere, and use prefixes for other stuff.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consistency, to make parser simpler. The first character always indicates what type of value will follow after the colon.
I'm using already existing concepts: prefixes on values like the
a
tag value, uppercase tag, and variadic fields similar toimeta
tag (though not on the first tag value, which we need to be always the same to be searchable).edit: The variadic fields make the tag extensible if the need arises.