Skip to content

Latest commit

 

History

History
195 lines (155 loc) · 6.98 KB

61.md

File metadata and controls

195 lines (155 loc) · 6.98 KB

NIP-61

Event Set

draft optional

An event set is represented by a group of events, not a single event. Each event of a specific set has the same pubkey and n (set "n"ame) tag.

An event can have many n tags, thus being member of many event sets. To remove an event from a set, remove the corresponding n tag from the event or send a deletion event (kind:5).

Referencing

An event set is referenced by an s tag. It references many events from an author instead of a single one:

["s", "<kind>:<pubkey>:<n-tag>", "<recommended-relay-URL, optional>"]

One may also use an nset NIP-19 entity through a NIP-21 URI: nostr:nset1qqstn...794234d.

How to add items to a set

Just add an n tag to your event. For example, adding one of your long-form posts to a set named "a-set-name-example":

{
  "kind": 30023,
  "tags": [
    ["d", "<random>"],
    ["n", "a-set-name-example"]
    // other tags
  ]
  // other fields
}

Tagging into Event Sets

You SHOULD use a list of pre-defined event kinds to tag existing events, public keys, or other references into sets.

The kind and d tag value will vary depending on the type of item being referenced.

Some of the event kinds require a k tag set to the referenced item kind to help with filtering or other tags.

Table of "Set Item Reference" Event Kinds and Structure by Referenced Item Type:

Type Kind d-tag other required tags
pubkey 30382 <user-pubkey>
event 30383 <event-id> ["k", "<event-kind>"], ["p", "<event-pubkey>"]
(parameterized) replaceable event 30384 <event-kind>:<event-pubkey>:<event-d-tag> ["k", "<event-kind>"]
hashtag 30385 <t-tag>
url 30386 <url-with-protocol-without-trailing-slash>
relay 30387 <relay-url-with-protocol-without-trailing-slash>
emoji 30388 <emoji-image-url-with-protocol-without-trailing-slash>) ["emoji", "<shortcode>"]
word 30389 <lowercase-string>

These events may have tags other than n with extra metadata about the referenced item. Because of that, when removing some metadata during an edit, clients should only delete the event when all tags other than the d one were removed and the content is an empty string.

Example of 1 item (a pubkey) that is simultaneously part of 3 event sets:

{
  "kind": 30382,
  "pubkey": "<me>",
  "tags": [
    ["d", "<another-user-pubkey>"],
    ["n", "follow"],
    ["n", "friend"],
    ["n", "Best Friends Forever"]
    // ...other metadata
  ],
  // ...empty string or secret metadata
  "content": nip44Encrypt(JSON.stringify([
    ["petname", "Zygote"],
    ["summary", "Owes me a beer"],
    // ...other secret metadata
  ])),
  // ...other fields
}

Private "Set Item Reference" Event:

What makes such events private is the process of obfuscating the d tag value and adding the clear version of it inside the encrypted .content.

To obfuscate a value, it is deterministically hashed by generating an auxiliary private key with the NIP-44 HKDF function and salt set to "nip61", concatenating it with the to-be-obfuscated value, hashing the result with SHA256, then encoding it to hex.

Table of Private "Set Item Reference" Event Kinds and Structure by Referenced Item Type: Note that obfuscate(<value>) is representing the step taken to hash the d tag value explained above.

Type Kind d-tag other required tags
pubkey (private) 31382 obfuscate(<user-pubkey>)
event (private) 31383 obfuscate(<event-id>) ["k", obfuscate("<event-kind>")], ["p", obfuscate("<event-pubkey>")]
(parameterized) replaceable event (private) 31384 obfuscate(<event-kind>:<event-pubkey>:<event-d-tag>) ["k", obfuscate("<event-kind>")]
hashtag (private) 31385 obfuscate(<t-tag>)
url (private) 31386 obfuscate(<url-with-protocol-without-trailing-slash>)
relay (private) 31387 obfuscate(<relay-url-with-protocol-without-trailing-slash>
emoji (private) 31388 obfuscate(<emoji-image-url-with-protocol-without-trailing-slash>) addToEncryptedContent(["emoji", "<shortcode>"])
word (private) 31389 obfuscate(<lowercase-string>)

Example event:

{
  "kind": 31382,
  "pubkey": "<me>",
  "tags": [
    ["d", toHex(sha256(hkdf("<my-private-key>", salt: "nip61") || "<another-user-pubkey>"))]
    ["n", "example-set-name"]
  ],
  "content": nip44Encrypt(JSON.stringify([
    ["d", "<another-user-pubkey>"]
    // ...other secret metadata
  ])),
  // ...other fields
}

Set Names

There are two types of sets: those with a "standard" name and those with a "custom" one (most likely user-generated name).

Standard

Standard sets have one of the names (the n tag value) listed here to guarantee interoperability. The convention is to prefer lowercase English words in singular form with dash separator.

n-tag description
bookmark list of things a user wants to save
contact pubkeys to whom the user sent DMs or started an interaction such as an one-on-one audio/video call
file adds events and files (urls) to a root directory similar to "/"
follow followed pubkeys, hashtags, etc
friend friends' pubkeys
mute pubkeys, hashtags, words or notes the user doesn't want to see in their feeds and blocked relays
notification notes monitored for new replies, zaps and reactions
pin events to showcase in the user profile page
upload files (urls) - requires m tag set to the MIME type

Custom

To keep track of the custom set names, the encrypted parameterized replaceable "Custom Sets" kind:30061 event is used.

Such event with d-tag="" lists custom set names with no expected special treatment by clients (these sets effectively work like labels).

However, adding a standard set name to the d tag instructs clients to treat the listed custom sets the same as they treat the corresponding standard set. For example, sets listed within a kind:30061 with d-tag="follow" are treated by clients the same way as the "follow" set, i.e., they could be used as custom feeds.

A kind:30061 event has one map tag for each custom set. A map tag has the first value as the custom set name. When the user doesn't want to reveal the real custom set name, the map tag's first value can be a fake or random string that maps to the map tag's second value, which holds the real custom set name that just the user will see.

Examples:

{
  "kind": 30061,
  "tags": [
    ["d", ""]
  ]
  "content": nip44Encrypt(JSON.stringify([
    ["map", "<public-name>", "<real-name>"],
    ["map", "Good Fellow", "Good Fellow"],
    ["map", "6064460175057025", "Debtor"]
  ])),
  // ...other fields
}
{
  "kind": 30061,
  "tags": [
    ["d", "file"]
  ]
  "content": nip44Encrypt(JSON.stringify([
    ["map", "4234649720408324", "/sub/directory"],
    ["map", "/home", "/home"]
  ]))
  // other fields
}