Skip to content
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 - Comment #1233

Merged
merged 24 commits into from
Nov 7, 2024
Merged
Changes from 23 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
184 changes: 184 additions & 0 deletions 22.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
NIP-22
======

Comment
-------

`draft` `optional`

A comment is a threading note always scoped to a root event or an `I`-tag.

It uses `kind:1111` with plaintext `.content` (no HTML, Markdown, or other formatting).

Comments MUST point to the root scope using uppercase tag names (e.g. `K`, `E`, `A` or `I`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be a SHOULD instead of a MUST. Clients don't always have access to the root event.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If everyone follows the spec from start, the first level thread comments will have root references, then the next level of comments would just copy these references from their parent comment, even if the root event is missing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only works when commenting on events that use this spec and you would have to trust the parent author to set the correct root data.

A comment only needs its parent data. Adding root data might be helpful for clients implementing full threads but is burdensome for clients that just want to create a comment. It should be encouraged but not be a requirement.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The root data is not even that useful. Right now you would get the whole thread by querying E because most threads are tiny. When threads get bigger you would hit relay restrictions and only receive a subset of the comments many of which will be n-level instead top-level replies, which are not useful for building the thread from the root.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm with you. Going the easy route of loading the full thread (relying on the uppercase E/A/I tags) in contrast to lazy loading is bad cause it loads too much events.

The uppercase K tag being the root item's kind though is very useful to filter by { authors: [someone], kinds: [1111], "#K": ["30023", ...others kinds this client cares about] }

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What should be set when the parent does not set an E tag (we shouldn't rely on other people complying) and you also don't know the root?
Having the root scope as a MUST requirement doesn't make sense in this case. It should be SHOULD.

I personally don't really care about it as I'm going to disrespect the root scope the same way I disrespect nip10, but when a library dev sees a MUST he will implement it that way and I would like to use a library function instead of building the event myself.

and MUST point to the parent item with lowercase ones (e.g. `k`, `e`, `a` or `i`).

```js
{
kind: 1111,
content: '<comment>',
tags: [
// root scope: event addresses, event ids, or I-tags.
["<A, E, I>", "<address, id or I-value>", "<relay or web page hint>", "<root event's pubkey, if an E tag>"],
// the root kind or type if r.
arthurfranca marked this conversation as resolved.
Show resolved Hide resolved
["K", "<root kind>"],
arthurfranca marked this conversation as resolved.
Show resolved Hide resolved

// parent item: event addresses, event ids, or i-tags.
["<a, e, i>", "<address, id or i-value>", "<relay or web page hint>", "<parent event's pubkey, if an e tag>"],
// parent item kind
["k", "<parent comment kind>"]
]
// other fields
}
```

Tags `K` and `k` MUST be present to define the event kind of the root and the parent items.

`I` and `i` tags create scopes for hashtags, geohashes, URLs, and other external identifiers.

The possible values for `i` tags – and `k` tags, when related to an extenal identity – are listed on [NIP-73](73.md).
Their uppercase versions use the same type of values but relate to the root item instead of the parent one.

`q` tags MAY be used when citing events in the `.content` with [NIP-21](21.md).

```json
["q", "<event-id> or <event-address>", "<relay-url>", "<pubkey-if-a-regular-event>"]
```

`p` tags SHOULD be used when mentioning pubkeys in the `.content` with [NIP-21](21.md).
If the parent item is an event, a `p` tag set to the parent event's author SHOULD be added.

```json
["p", "<pubkey>", "<relay-url>"]
```

arthurfranca marked this conversation as resolved.
Show resolved Hide resolved
## Examples

A comment on a blog post looks like this:

```js
{
kind: 1111,
content: 'Great blog post!',
tags: [
// top-level comments scope to event addresses or ids
["A", "30023:3c9849383bdea883b0bd16fece1ed36d37e37cdde3ce43b17ea4e9192ec11289:f9347ca7", "wss://example.relay"],
// the root kind
["K", "30023"],

// the parent event address (same as root for top-level comments)
["a", "30023:3c9849383bdea883b0bd16fece1ed36d37e37cdde3ce43b17ea4e9192ec11289:f9347ca7", "wss://example.relay"],
// when the parent event is replaceable or addressable, also include an `e` tag referencing its id
["e", "5b4fc7fed15672fefe65d2426f67197b71ccc82aa0cc8a9e94f683eb78e07651", "wss://example.relay"],
arthurfranca marked this conversation as resolved.
Show resolved Hide resolved
// the parent event kind
["k", "30023"]
]
// other fields
}
```

A comment on a [NIP-94](94.md) file looks like this:

```js
{
kind: 1111,
content: 'Great file!',
tags: [
// top-level comments have the same scope and reply to addresses or ids
["E", "768ac8720cdeb59227cf95e98b66560ef03d8bc9a90d721779e76e68fb42f5e6", "wss://example.relay", "3721e07b079525289877c366ccab47112bdff3d1b44758ca333feb2dbbbbe5bb"],
// the root kind
["K", "1063"],

// the parent event id (same as root for top-level comments)
["e", "768ac8720cdeb59227cf95e98b66560ef03d8bc9a90d721779e76e68fb42f5e6", "wss://example.relay", "3721e07b079525289877c366ccab47112bdff3d1b44758ca333feb2dbbbbe5bb"],
// the parent kind
["k", "1063"]
]
// other fields
}
```

A reply to a comment looks like this:

```js
{
kind: 1111,
content: 'This is a reply to "Great file!"',
tags: [
// nip-94 file event id
["E", "768ac8720cdeb59227cf95e98b66560ef03d8bc9a90d721779e76e68fb42f5e6", "wss://example.relay", "fd913cd6fa9edb8405750cd02a8bbe16e158b8676c0e69fdc27436cc4a54cc9a"],
// the root kind
["K", "1063"],

// the parent event
["e", "5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36", "wss://example.relay", "93ef2ebaaf9554661f33e79949007900bbc535d239a4c801c33a4d67d3e7f546"],
// the parent kind
["k", "1111"]
]
// other fields
}
```

A comment on a website's url looks like this:

```js
{
kind: 1111,
content: 'Nice article!',
tags: [
// referencing the root url
["I", "https://abc.com/articles/1"],
// the root "kind": for an url, the kind is its domain
["K", "https://abc.com"],

// the parent reference (same as root for top-level comments)
["i", "https://abc.com/articles/1"],
// the parent "kind": for an url, the kind is its domain
["k", "https://abc.com"]
]
// other fields
}
```

A podcast comment example:

```js
{
id: "80c48d992a38f9c445b943a9c9f1010b396676013443765750431a9004bdac05",
pubkey: "252f10c83610ebca1a059c0bae8255eba2f95be4d1d7bcfa89d7248a82d9f111",
kind: 1111,
content: "This was a great episode!",
tags: [
// podcast episode reference
["I", "podcast:item:guid:d98d189b-dc7b-45b1-8720-d4b98690f31f", "https://fountain.fm/episode/z1y9TMQRuqXl2awyrQxg"],
// podcast episode type
["K", "podcast:item:guid"],

// same value as "I" tag above, because it is a top-level comment (not a reply to a comment)
["i", "podcast:item:guid:d98d189b-dc7b-45b1-8720-d4b98690f31f", "https://fountain.fm/episode/z1y9TMQRuqXl2awyrQxg"],
["k", "podcast:item:guid"]
]
// other fields
}
```

A reply to a podcast comment:

```js
{
kind: 1111,
content: "I'm replying to the above comment.",
tags: [
// podcast episode reference
["I", "podcast:item:guid:d98d189b-dc7b-45b1-8720-d4b98690f31f", "https://fountain.fm/episode/z1y9TMQRuqXl2awyrQxg"],
// podcast episode type
["K", "podcast:item:guid"],

// this is a reference to the above comment
["e", "80c48d992a38f9c445b943a9c9f1010b396676013443765750431a9004bdac05", "wss://example.relay", "252f10c83610ebca1a059c0bae8255eba2f95be4d1d7bcfa89d7248a82d9f111"],
// the parent comment kind
["k", "1111"]
]
// other fields
}
```