From eb58bbb0cbc53bb61e16306ae6507c865845dd63 Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Sun, 17 Sep 2023 15:24:54 -0300 Subject: [PATCH 01/36] Add bunch --- 61.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 61.md diff --git a/61.md b/61.md new file mode 100644 index 000000000..f22723b6b --- /dev/null +++ b/61.md @@ -0,0 +1,28 @@ +NIP-61 +====== + +Bunch of Events +--------------- + +An event with a `kind` in the range 40000 <= n < 50000 is one of a bunch of events +of the same kind, pubkey and `d` tag. Publishing an event with these same three fields +won't replace the previous one. + +## Referencing + +A bunch of events is referenced by a `b` tag. +It has the same format of an `a` tag +but references a bunch of events instead of a single one: + +`["b", ":<32-bytes lowercase hex of a pubkey>:", ""]` + +It may be used to reference an unbounded list of events, different from NIP-51 lists +which may have a limit on the number of items depending on relay's event size restrictions. + +To reference one of the events, use a regular `e` tag. +Using an `a` tag will reference the last inserted event of the list. + +## Deleting + +Use a kind `5` event with an `e` tag to delete items from the bunch +or with an `a` tag to delete all of them. From 0b56cbc2971b8a5717b0d1991e2b15c8ad5aea94 Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Mon, 18 Sep 2023 09:45:09 -0300 Subject: [PATCH 02/36] Change to unbounded lists --- 61.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/61.md b/61.md index f22723b6b..be3992d19 100644 --- a/61.md +++ b/61.md @@ -1,28 +1,28 @@ NIP-61 ====== -Bunch of Events +Unbounded lists --------------- -An event with a `kind` in the range 40000 <= n < 50000 is one of a bunch of events -of the same kind, pubkey and `d` tag. Publishing an event with these same three fields -won't replace the previous one. +An unbounded list is a group of events within the `kind` range 40000 <= n < 50000, all +with same kind, pubkey and `d` tag. Publishing an event with these same three fields +won't replace the previous one. An unbounded list itself is referenced by an `u` tag. ## Referencing -A bunch of events is referenced by a `b` tag. +An unbounded list is referenced by an `u` tag. It has the same format of an `a` tag -but references a bunch of events instead of a single one: +but references a list of events instead of a single one: -`["b", ":<32-bytes lowercase hex of a pubkey>:", ""]` +`["u", ":<32-bytes lowercase hex of a pubkey>:", ""]` -It may be used to reference an unbounded list of events, different from NIP-51 lists -which may have a limit on the number of items depending on relay's event size restrictions. +It is different from NIP-51 lists because these can have a limit on the number of items depending on relay's event size restrictions. To reference one of the events, use a regular `e` tag. Using an `a` tag will reference the last inserted event of the list. ## Deleting -Use a kind `5` event with an `e` tag to delete items from the bunch -or with an `a` tag to delete all of them. +Use a kind `5` event with `e` tags to delete individual items from the bunch +or with an `a` tag to delete all of them, similar to deleting parameterized +replaceable events. From 2885dcfc32ce48923699eaea3d4fcfd99065b238 Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Wed, 20 Sep 2023 08:27:33 -0300 Subject: [PATCH 03/36] Use s tag and nset entity for referencing --- 61.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/61.md b/61.md index be3992d19..c8dd03b99 100644 --- a/61.md +++ b/61.md @@ -4,25 +4,26 @@ NIP-61 Unbounded lists --------------- -An unbounded list is a group of events within the `kind` range 40000 <= n < 50000, all +An unbounded list is a group of events within the `kind` range `40000 <= n < 50000`, all with same kind, pubkey and `d` tag. Publishing an event with these same three fields -won't replace the previous one. An unbounded list itself is referenced by an `u` tag. +won't replace the previous one. An unbounded list itself is referenced by an `s` tag +or by an `nset` [NIP-19](19.md) entity using [NIP-21](21.md) URI. + +Unbounded lists are different from NIP-51 lists because these can have a limit on +the number of items depending on relay's event size restrictions. ## Referencing -An unbounded list is referenced by an `u` tag. -It has the same format of an `a` tag -but references a list of events instead of a single one: +An unbounded list is referenced by an `s` tag. +It references a set of events instead of a single one: -`["u", ":<32-bytes lowercase hex of a pubkey>:", ""]` +`["s", "::<32-bytes lowercase hex of a pubkey>", ""]` -It is different from NIP-51 lists because these can have a limit on the number of items depending on relay's event size restrictions. +One may use an `nset` entity URI too: `nostr:nset1qqstn...` -To reference one of the events, use a regular `e` tag. -Using an `a` tag will reference the last inserted event of the list. +To reference one of the events in the list, use a regular `e` tag, `nevent` or `note` entities. ## Deleting -Use a kind `5` event with `e` tags to delete individual items from the bunch -or with an `a` tag to delete all of them, similar to deleting parameterized -replaceable events. +Use a kind `5` event with `e` tags to delete individual items from the list +or with an `s` tag to delete all of them. From 02dbc0fdcc6e08f953b986458c017e12e600c3ea Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Wed, 20 Sep 2023 16:46:43 -0300 Subject: [PATCH 04/36] Change how unbounded lists are created and referenced --- 61.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/61.md b/61.md index c8dd03b99..a89c4c9f6 100644 --- a/61.md +++ b/61.md @@ -1,29 +1,29 @@ NIP-61 ====== -Unbounded lists ---------------- +Unbounded List +-------------- -An unbounded list is a group of events within the `kind` range `40000 <= n < 50000`, all -with same kind, pubkey and `d` tag. Publishing an event with these same three fields -won't replace the previous one. An unbounded list itself is referenced by an `s` tag -or by an `nset` [NIP-19](19.md) entity using [NIP-21](21.md) URI. +An unbounded list is a group of events with the same pubkey and `n` (name) tag. +An event can have many `n` tags, thus being member of many unbounded lists. -Unbounded lists are different from NIP-51 lists because these can have a limit on -the number of items depending on relay's event size restrictions. +An unbounded list itself is referenced by an `u` tag +or by an `nunb` [NIP-19](19.md) entity using [NIP-21](21.md) URI. -## Referencing +## Use Cases + +Unbounded lists are an option to hold a big number of items. In contrast, NIP-51 lists +have a limit on the number of items depending on relay's event size restrictions. -An unbounded list is referenced by an `s` tag. -It references a set of events instead of a single one: +In fact, an unbounded list can be made of different NIP-51 lists from the same author. -`["s", "::<32-bytes lowercase hex of a pubkey>", ""]` +For example, the NIP-51 lists may be "Close Friends" and "Family" but all sharing the same `n` tag, +effectively making an unbounded list combining both sets of `p` tags. -One may use an `nset` entity URI too: `nostr:nset1qqstn...` +## Referencing -To reference one of the events in the list, use a regular `e` tag, `nevent` or `note` entities. +An unbounded list is referenced by an `u` tag. It references a set of events instead of a single one: -## Deleting +`["u", "<32-bytes lowercase hex of a pubkey>:", ""]` -Use a kind `5` event with `e` tags to delete individual items from the list -or with an `s` tag to delete all of them. +One may also use an `nunb` entity URI: `nostr:nunb1qqstn...794234d`. From 01d5527472a9f65ea3c7078739a5ce5bf0d8c10b Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Thu, 21 Sep 2023 10:14:18 -0300 Subject: [PATCH 05/36] Reserve kind and add example --- 61.md | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/61.md b/61.md index a89c4c9f6..6c8445539 100644 --- a/61.md +++ b/61.md @@ -4,6 +4,8 @@ NIP-61 Unbounded List -------------- +`draft` `optional` `author:arthurfranca` + An unbounded list is a group of events with the same pubkey and `n` (name) tag. An event can have many `n` tags, thus being member of many unbounded lists. @@ -12,18 +14,74 @@ or by an `nunb` [NIP-19](19.md) entity using [NIP-21](21.md) URI. ## Use Cases -Unbounded lists are an option to hold a big number of items. In contrast, NIP-51 lists +Unbounded lists are an option to hold a big number of items. In contrast, [NIP-51](51.md) lists have a limit on the number of items depending on relay's event size restrictions. In fact, an unbounded list can be made of different NIP-51 lists from the same author. -For example, the NIP-51 lists may be "Close Friends" and "Family" but all sharing the same `n` tag, +For example, the NIP-51 lists may be "close_friends" and "family" and both sharing the same `n` tag, effectively making an unbounded list combining both sets of `p` tags. ## Referencing -An unbounded list is referenced by an `u` tag. It references a set of events instead of a single one: +An unbounded list is referenced by an `u` tag. +It references a set of events from an author instead of a single one: `["u", "<32-bytes lowercase hex of a pubkey>:", ""]` One may also use an `nunb` entity URI: `nostr:nunb1qqstn...794234d`. + +## Unbounded List Event Kinds + +Any event kind can be part of an unbounded list by just adding an `n` tag. Nevertheless, +there are reserved kinds for specific usage: + +| kind | list type | +| ------ | ----------| +| 33118 | People | + +Tags other than `d` and `n` may be encrypted with [NIP-44](#44.md) similar to NIP-51 lists. + +### Unbounded People List + +An event with kind `33118` is defined as a parameterized replaceable unbounded list event for people. +The `n` tag(s) holds the list name(s) the event is currently part of. +The `p` tags included in these lists MUST follow the format of kind 3 events as defined in [NIP-02 - Contact List and Petnames](02.md). + +## Event Examples + +```js +{ + "kind": 33118, + "tags": [ + ["d", "random6467362966154779"] + // this is enough to mark it as a "subscribers" unbounded list + ["n", "subscribers"], + // This also adds this event to other unbounded list (e.g.: meant + // to hold all pubkeys who can access the + // 5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36 event) + // made of the "subscribers" unbounded list events + // and other events such as NIP-51 Categorized People lists + ["n", "private:5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36"], + ], + "content": "", + ...other fields +} +``` + +```js +{ + "kind": 30000, + "tags": [ + ["d", "close_friends"] + ["n", "private:5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36"], + ], + "content": "", + ...other fields +} +``` From 17f6cbddb1869072061686bf5c5ddb11b02b40cb Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Thu, 21 Sep 2023 11:06:50 -0300 Subject: [PATCH 06/36] Add contact event example --- 61.md | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/61.md b/61.md index 6c8445539..6d348bb8d 100644 --- a/61.md +++ b/61.md @@ -4,7 +4,7 @@ NIP-61 Unbounded List -------------- -`draft` `optional` `author:arthurfranca` +`draft` `optional` `author:arthurfranca` `author:vitorpamplona` An unbounded list is a group of events with the same pubkey and `n` (name) tag. An event can have many `n` tags, thus being member of many unbounded lists. @@ -46,11 +46,13 @@ Tags other than `d` and `n` may be encrypted with [NIP-44](#44.md) similar to NI An event with kind `33118` is defined as a parameterized replaceable unbounded list event for people. The `n` tag(s) holds the list name(s) the event is currently part of. -The `p` tags included in these lists MUST follow the format of kind 3 events as defined in [NIP-02 - Contact List and Petnames](02.md). +The single `p` tag included in these lists MUST follow the format of kind 3 events as defined in [NIP-02 - Contact List and Petnames](02.md). ## Event Examples ```js +// Unbounded subscriber list event also part of the unbounded +// "private:5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36" list { "kind": 33118, "tags": [ @@ -72,6 +74,8 @@ The `p` tags included in these lists MUST follow the format of kind 3 events as ``` ```js +// A NIP-51 list being part of the unbounded +// "private:5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36" list { "kind": 30000, "tags": [ @@ -85,3 +89,25 @@ The `p` tags included in these lists MUST follow the format of kind 3 events as ...other fields } ``` + +```js +// Unbounded contact list can be made of +// thousands of events like the one below +{ + "kind": 33118, + "tags": [ + ["d", "random5189992173907396"] + ["n", "contacts"] + ], + "content": "`], + ["summary", ""], + ["email", "bla@ble.com"] + ])>", + ...other fields +} +``` From 502a40b2532eec45262b4c1c2e8187f491161c03 Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Thu, 21 Sep 2023 12:51:22 -0300 Subject: [PATCH 07/36] Update examples --- 61.md | 62 ++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/61.md b/61.md index 6d348bb8d..06ecc16f7 100644 --- a/61.md +++ b/61.md @@ -46,65 +46,71 @@ Tags other than `d` and `n` may be encrypted with [NIP-44](#44.md) similar to NI An event with kind `33118` is defined as a parameterized replaceable unbounded list event for people. The `n` tag(s) holds the list name(s) the event is currently part of. -The single `p` tag included in these lists MUST follow the format of kind 3 events as defined in [NIP-02 - Contact List and Petnames](02.md). +The **single** `p` tag included in these list events MUST follow the format of kind 3 events as defined in [NIP-02 - Contact List and Petnames](02.md). -## Event Examples +## Examples + +### Private ACL ```js -// Unbounded subscriber list event also part of the unbounded +// A NIP-51 list being part of the unbounded // "private:5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36" list { - "kind": 33118, + "kind": 30000, "tags": [ - ["d", "random6467362966154779"] - // this is enough to mark it as a "subscribers" unbounded list - ["n", "subscribers"], - // This also adds this event to other unbounded list (e.g.: meant - // to hold all pubkeys who can access the - // 5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36 event) - // made of the "subscribers" unbounded list events - // and other events such as NIP-51 Categorized People lists + ["d", "close_friends"] + // This event is of an ubounded list meant to hold all pubkeys who can access the + // 5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36 event ["n", "private:5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36"], ], "content": "", ...other fields } ``` +### People List + ```js -// A NIP-51 list being part of the unbounded +// Unbounded subscriber list event also part of the unbounded // "private:5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36" list { - "kind": 30000, + "kind": 33118, "tags": [ - ["d", "close_friends"] + ["d", "random6467362966154779"] + // this is enough to mark it as a "subscribers" unbounded list + ["n", "subscribers"], + // This also adds this event to other unbounded list (e.g.: meant + // to hold all pubkeys who can access the + // 5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36 event) + // made of the "subscribers" unbounded list events + // and other events such as the above "close_friends" NIP-51 Categorized People list event ["n", "private:5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36"], ], "content": "", ...other fields } ``` +### Relationship Status + ```js -// Unbounded contact list can be made of -// thousands of events like the one below +// Unbounded contact lists can be made of +// thousands of events like this NIP-81 one below { - "kind": 33118, + "kind": 30382, // contact kind "tags": [ - ["d", "random5189992173907396"] - ["n", "contacts"] + ["d", "91cf9..4e5ca"] // contact's pubkey + // can fetch all Scammer List but no one else but the author knows + ["n", ""], + ["relay", ""], ], "content": "`], + ["nickname", "Big Joe"], ["summary", ""], ["email", "bla@ble.com"] ])>", From b0e96e5e3d9047d43bbc7bb6df24b4c81e58a67c Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Thu, 21 Sep 2023 14:21:12 -0300 Subject: [PATCH 08/36] Add suggestion --- 61.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/61.md b/61.md index 06ecc16f7..1934e371a 100644 --- a/61.md +++ b/61.md @@ -17,6 +17,8 @@ or by an `nunb` [NIP-19](19.md) entity using [NIP-21](21.md) URI. Unbounded lists are an option to hold a big number of items. In contrast, [NIP-51](51.md) lists have a limit on the number of items depending on relay's event size restrictions. +Public and encrypted data can coexist in unbounded list events similar to NIP-51 lists. + In fact, an unbounded list can be made of different NIP-51 lists from the same author. For example, the NIP-51 lists may be "close_friends" and "family" and both sharing the same `n` tag, From c209e55846fd19be28121c333c02b039ec249e68 Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Thu, 21 Sep 2023 18:05:51 -0300 Subject: [PATCH 09/36] Fix relationship status event example --- 61.md | 63 +++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 25 deletions(-) diff --git a/61.md b/61.md index 1934e371a..c621399bb 100644 --- a/61.md +++ b/61.md @@ -52,49 +52,50 @@ The **single** `p` tag included in these list events MUST follow the format of k ## Examples -### Private ACL +### People List ```js -// A NIP-51 list being part of the unbounded +// Unbounded subscriber list event also part of the unbounded // "private:5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36" list { - "kind": 30000, + "kind": 33118, "tags": [ - ["d", "close_friends"] - // This event is of an ubounded list meant to hold all pubkeys who can access the - // 5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36 event + ["d", "random6467362966154779"] + // This is enough to mark it as a "subscribers" unbounded list + ["n", "subscribers"], + // This also adds this event to other unbounded list (e.g.: meant + // to hold all pubkeys who can access the + // 5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36 event) + // made of the "subscribers" unbounded list events + // and other events such as the above "close_friends" NIP-51 Categorized People list event ["n", "private:5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36"], ], "content": "", - ...other fields + // ...other fields } ``` -### People List +### Private ACL ```js -// Unbounded subscriber list event also part of the unbounded +// A NIP-51 list being part of the unbounded // "private:5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36" list { - "kind": 33118, + "kind": 30000, "tags": [ - ["d", "random6467362966154779"] - // this is enough to mark it as a "subscribers" unbounded list - ["n", "subscribers"], - // This also adds this event to other unbounded list (e.g.: meant - // to hold all pubkeys who can access the - // 5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36 event) - // made of the "subscribers" unbounded list events - // and other events such as the above "close_friends" NIP-51 Categorized People list event + ["d", "close_friends"] + // This event is added to an ubounded list meant to hold all pubkeys who can access the + // 5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36 event just like the event above ["n", "private:5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36"], ], "content": "", - ...other fields + // ...other fields } ``` @@ -107,8 +108,10 @@ The **single** `p` tag included in these list events MUST follow the format of k "kind": 30382, // contact kind "tags": [ ["d", "91cf9..4e5ca"] // contact's pubkey - // can fetch all Scammer List but no one else but the author knows - ["n", ""], + // Can fetch all Scammer List but no one else but the author knows + // The author should keep all n "relaltionship status names" to "random string" mapping + // in an encrypted NIP-51 list (see kind:10003 event below) + ["n", ""], ["relay", ""], ], "content": ""], ["email", "bla@ble.com"] ])>", - ...other fields + // ...other fields +} + +{ + "kind": 10003, + "content": "", + // ...other fields } ``` From fc97c78d156ec51394df47f41568f557741c3b56 Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Fri, 10 May 2024 10:47:30 -0300 Subject: [PATCH 10/36] make text more intelligible --- 61.md | 141 ++++++++++++++++------------------------------------------ 1 file changed, 39 insertions(+), 102 deletions(-) diff --git a/61.md b/61.md index c621399bb..8bfd55caa 100644 --- a/61.md +++ b/61.md @@ -1,134 +1,71 @@ NIP-61 ====== -Unbounded List +Unbound List -------------- -`draft` `optional` `author:arthurfranca` `author:vitorpamplona` +`draft` `optional` -An unbounded list is a group of events with the same pubkey and `n` (name) tag. -An event can have many `n` tags, thus being member of many unbounded lists. +An unbound list is a group of events with the same pubkey and `n` (list "n"ame) tag. +An event can have many `n` tags, thus being member of many unbound lists. -An unbounded list itself is referenced by an `u` tag -or by an `nunb` [NIP-19](19.md) entity using [NIP-21](21.md) URI. +To add an event to the "Close Friends" list, +add a "close-friend" (prefer singular form with dash separator) `n` tag to the event. + +To remove an event from a "Close Friends" list, +remove the "close-friend" `n` tag from the event. + +An unbound list itself is referenced by an `u` tag +or by an `nlist` [NIP-19](19.md) entity using [NIP-21](21.md) URI. ## Use Cases -Unbounded lists are an option to hold a big number of items. In contrast, [NIP-51](51.md) lists -have a limit on the number of items depending on relay's event size restrictions. +Unbound lists can be used wherever a [NIP-51](51.md) list fits. -Public and encrypted data can coexist in unbounded list events similar to NIP-51 lists. +NIP-51 lists have a limit on the number of items they can hold depending on relay's event size restrictions. +While unbound lists can have any number of items. -In fact, an unbounded list can be made of different NIP-51 lists from the same author. +The downside of unbound lists is that migrating a list from one relay to another can be rate limited +due to saving many individual events during a small time window. -For example, the NIP-51 lists may be "close_friends" and "family" and both sharing the same `n` tag, -effectively making an unbounded list combining both sets of `p` tags. +Public and encrypted data can coexist in unbound list events, similar to NIP-51 lists. ## Referencing -An unbounded list is referenced by an `u` tag. +An unbound list is referenced by an `u` tag. It references a set of events from an author instead of a single one: `["u", "<32-bytes lowercase hex of a pubkey>:", ""]` -One may also use an `nunb` entity URI: `nostr:nunb1qqstn...794234d`. - -## Unbounded List Event Kinds - -Any event kind can be part of an unbounded list by just adding an `n` tag. Nevertheless, -there are reserved kinds for specific usage: - -| kind | list type | -| ------ | ----------| -| 33118 | People | - -Tags other than `d` and `n` may be encrypted with [NIP-44](#44.md) similar to NIP-51 lists. - -### Unbounded People List +One may also use an `nlist` entity URI: `nostr:nlist1qqstn...794234d`. -An event with kind `33118` is defined as a parameterized replaceable unbounded list event for people. -The `n` tag(s) holds the list name(s) the event is currently part of. -The **single** `p` tag included in these list events MUST follow the format of kind 3 events as defined in [NIP-02 - Contact List and Petnames](02.md). +## Event Kinds -## Examples - -### People List - -```js -// Unbounded subscriber list event also part of the unbounded -// "private:5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36" list -{ - "kind": 33118, - "tags": [ - ["d", "random6467362966154779"] - // This is enough to mark it as a "subscribers" unbounded list - ["n", "subscribers"], - // This also adds this event to other unbounded list (e.g.: meant - // to hold all pubkeys who can access the - // 5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36 event) - // made of the "subscribers" unbounded list events - // and other events such as the above "close_friends" NIP-51 Categorized People list event - ["n", "private:5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36"], - ], - "content": "", - // ...other fields -} -``` +The the same `n` tag can be applied to any event no matter the `kind` or structure. +However, it is better to add `n` tag(s) to parameterized replaceable events, because +such events can be removed from a list later by removing the corresponding `n` tag, +due to their editable nature. -### Private ACL +The following example is based on the unreleased +[Relationship Status](https://github.com/vitorpamplona/nips/blob/relationship-status/81.md) spec: ```js -// A NIP-51 list being part of the unbounded -// "private:5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36" list { - "kind": 30000, + "kind": 30382, // This is a kind for public relationship info between the signer and another user + "pubkey": "", "tags": [ - ["d", "close_friends"] - // This event is added to an ubounded list meant to hold all pubkeys who can access the - // 5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36 event just like the event above - ["n", "private:5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36"], + ["d", ""], + ["n", "follow"], // A "follow" "n" tag turns this event into a kind 3 equivalent entry + ["n", "friend"], // He is part of may "Friends" list + ["n", "close-friend"], // He is also part of the smaller "Close Friends" list + // ...other metadata describing the relationship + ["T", "3:driver"] // This is using an unreleased spec to rate this user as a great driver ], - "content": "", + "content": "" // ...other fields } ``` -### Relationship Status - -```js -// Unbounded contact lists can be made of -// thousands of events like this NIP-81 one below -{ - "kind": 30382, // contact kind - "tags": [ - ["d", "91cf9..4e5ca"] // contact's pubkey - // Can fetch all Scammer List but no one else but the author knows - // The author should keep all n "relaltionship status names" to "random string" mapping - // in an encrypted NIP-51 list (see kind:10003 event below) - ["n", ""], - ["relay", ""], - ], - "content": ""], - ["email", "bla@ble.com"] - ])>", - // ...other fields -} - -{ - "kind": 10003, - "content": "", - // ...other fields -} -``` +In the above example, when removing someone from an unbound list (considering a `kind:30382` event), +a client should only delete the event when all tags other +than the `d` one were removed and the content is an empty string. From 7d202156dcd01301efc8f5f093d189f4024130cb Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Fri, 10 May 2024 10:59:00 -0300 Subject: [PATCH 11/36] Add contacts list to the example --- 61.md | 1 + 1 file changed, 1 insertion(+) diff --git a/61.md b/61.md index 8bfd55caa..77960ad2a 100644 --- a/61.md +++ b/61.md @@ -58,6 +58,7 @@ The following example is based on the unreleased ["n", "follow"], // A "follow" "n" tag turns this event into a kind 3 equivalent entry ["n", "friend"], // He is part of may "Friends" list ["n", "close-friend"], // He is also part of the smaller "Close Friends" list + ["n", "contact"], // My contacts are users to whom I've sent DMs or started an one-to-one audio/video call // ...other metadata describing the relationship ["T", "3:driver"] // This is using an unreleased spec to rate this user as a great driver ], From 577335496bea3f9b7335034d4717d78bc2ea682a Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Fri, 10 May 2024 11:05:45 -0300 Subject: [PATCH 12/36] Add lowercase convention --- 61.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/61.md b/61.md index 77960ad2a..c79437816 100644 --- a/61.md +++ b/61.md @@ -10,7 +10,7 @@ An unbound list is a group of events with the same pubkey and `n` (list "n"ame) An event can have many `n` tags, thus being member of many unbound lists. To add an event to the "Close Friends" list, -add a "close-friend" (prefer singular form with dash separator) `n` tag to the event. +add a "close-friend" (prefer lowercase English words in singular form with dash separator) `n` tag to the event. To remove an event from a "Close Friends" list, remove the "close-friend" `n` tag from the event. @@ -41,7 +41,7 @@ One may also use an `nlist` entity URI: `nostr:nlist1qqstn...794234d`. ## Event Kinds -The the same `n` tag can be applied to any event no matter the `kind` or structure. +The same `n` tag can be applied to any event no matter the `kind` or structure. However, it is better to add `n` tag(s) to parameterized replaceable events, because such events can be removed from a list later by removing the corresponding `n` tag, due to their editable nature. @@ -57,7 +57,7 @@ The following example is based on the unreleased ["d", ""], ["n", "follow"], // A "follow" "n" tag turns this event into a kind 3 equivalent entry ["n", "friend"], // He is part of may "Friends" list - ["n", "close-friend"], // He is also part of the smaller "Close Friends" list + ["n", "close-friend"], // He is also part of my smaller "Close Friends" list ["n", "contact"], // My contacts are users to whom I've sent DMs or started an one-to-one audio/video call // ...other metadata describing the relationship ["T", "3:driver"] // This is using an unreleased spec to rate this user as a great driver From eefdb7e09537c9a35e83548163b2e5e64d10f5fd Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Fri, 10 May 2024 11:22:57 -0300 Subject: [PATCH 13/36] Add more info about differences in relation to NIP-51 --- 61.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/61.md b/61.md index c79437816..8fb657308 100644 --- a/61.md +++ b/61.md @@ -70,3 +70,7 @@ The following example is based on the unreleased In the above example, when removing someone from an unbound list (considering a `kind:30382` event), a client should only delete the event when all tags other than the `d` one were removed and the content is an empty string. + +Above example's `T` tag comes from the [Trust Rank](https://github.com/arthurfranca/nips/blob/trust-rank/64.md) +unreleaed spec and it illustrates how unbound list entries can hold extra +data in contrast to NIP-51 list entries that are simple event id/address references. From 9dbedf0477f146f59dd659100d8a49771ec99759 Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Fri, 10 May 2024 19:57:15 -0300 Subject: [PATCH 14/36] Update 61.md Co-authored-by: Vitor Pamplona --- 61.md | 1 - 1 file changed, 1 deletion(-) diff --git a/61.md b/61.md index 8fb657308..8f7ffc520 100644 --- a/61.md +++ b/61.md @@ -20,7 +20,6 @@ or by an `nlist` [NIP-19](19.md) entity using [NIP-21](21.md) URI. ## Use Cases -Unbound lists can be used wherever a [NIP-51](51.md) list fits. NIP-51 lists have a limit on the number of items they can hold depending on relay's event size restrictions. While unbound lists can have any number of items. From 4cb16ea401b07ca7849dd84f2fa252b74fb99d3d Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Fri, 10 May 2024 19:57:25 -0300 Subject: [PATCH 15/36] Update 61.md Co-authored-by: Vitor Pamplona --- 61.md | 1 - 1 file changed, 1 deletion(-) diff --git a/61.md b/61.md index 8f7ffc520..87e1f6d1c 100644 --- a/61.md +++ b/61.md @@ -21,7 +21,6 @@ or by an `nlist` [NIP-19](19.md) entity using [NIP-21](21.md) URI. ## Use Cases -NIP-51 lists have a limit on the number of items they can hold depending on relay's event size restrictions. While unbound lists can have any number of items. The downside of unbound lists is that migrating a list from one relay to another can be rate limited From 049a6eca3e62c1a42b2913b44540cb57e4cc03c5 Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Fri, 10 May 2024 19:57:39 -0300 Subject: [PATCH 16/36] Update 61.md Co-authored-by: Vitor Pamplona --- 61.md | 1 - 1 file changed, 1 deletion(-) diff --git a/61.md b/61.md index 87e1f6d1c..65a012aea 100644 --- a/61.md +++ b/61.md @@ -21,7 +21,6 @@ or by an `nlist` [NIP-19](19.md) entity using [NIP-21](21.md) URI. ## Use Cases -While unbound lists can have any number of items. The downside of unbound lists is that migrating a list from one relay to another can be rate limited due to saving many individual events during a small time window. From f49e3ef96c439d8bf9f1357cf52bcd48b0bf6226 Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Fri, 10 May 2024 19:58:50 -0300 Subject: [PATCH 17/36] Update 61.md Co-authored-by: Vitor Pamplona --- 61.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/61.md b/61.md index 65a012aea..8394676db 100644 --- a/61.md +++ b/61.md @@ -13,7 +13,7 @@ To add an event to the "Close Friends" list, add a "close-friend" (prefer lowercase English words in singular form with dash separator) `n` tag to the event. To remove an event from a "Close Friends" list, -remove the "close-friend" `n` tag from the event. +remove the "close-friend" `n` tag from the event or send a deletion event (`kind:5`). An unbound list itself is referenced by an `u` tag or by an `nlist` [NIP-19](19.md) entity using [NIP-21](21.md) URI. From e916266c80060c24668e6a2687a76fe2d4df677f Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Fri, 10 May 2024 20:08:42 -0300 Subject: [PATCH 18/36] Apply suggestions --- 61.md | 39 +++++++++++++++------------------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/61.md b/61.md index 8394676db..9e661021a 100644 --- a/61.md +++ b/61.md @@ -1,13 +1,13 @@ NIP-61 ====== -Unbound List --------------- +Event Sets +---------- `draft` `optional` -An unbound list is a group of events with the same pubkey and `n` (list "n"ame) tag. -An event can have many `n` tags, thus being member of many unbound lists. +An event set is a group of events with the same pubkey and `n` (list "n"ame) tag. +An event can have many `n` tags, thus being member of many event sets. To add an event to the "Close Friends" list, add a "close-friend" (prefer lowercase English words in singular form with dash separator) `n` tag to the event. @@ -15,33 +15,21 @@ add a "close-friend" (prefer lowercase English words in singular form with dash To remove an event from a "Close Friends" list, remove the "close-friend" `n` tag from the event or send a deletion event (`kind:5`). -An unbound list itself is referenced by an `u` tag +An event set itself is referenced by an `u` tag or by an `nlist` [NIP-19](19.md) entity using [NIP-21](21.md) URI. -## Use Cases - - - -The downside of unbound lists is that migrating a list from one relay to another can be rate limited -due to saving many individual events during a small time window. - -Public and encrypted data can coexist in unbound list events, similar to NIP-51 lists. - ## Referencing -An unbound list is referenced by an `u` tag. +An event set is referenced by an `u` tag. It references a set of events from an author instead of a single one: -`["u", "<32-bytes lowercase hex of a pubkey>:", ""]` +`["u", ":<32-bytes lowercase hex of a pubkey>:", ""]` One may also use an `nlist` entity URI: `nostr:nlist1qqstn...794234d`. ## Event Kinds The same `n` tag can be applied to any event no matter the `kind` or structure. -However, it is better to add `n` tag(s) to parameterized replaceable events, because -such events can be removed from a list later by removing the corresponding `n` tag, -due to their editable nature. The following example is based on the unreleased [Relationship Status](https://github.com/vitorpamplona/nips/blob/relationship-status/81.md) spec: @@ -57,17 +45,20 @@ The following example is based on the unreleased ["n", "close-friend"], // He is also part of my smaller "Close Friends" list ["n", "contact"], // My contacts are users to whom I've sent DMs or started an one-to-one audio/video call // ...other metadata describing the relationship - ["T", "3:driver"] // This is using an unreleased spec to rate this user as a great driver ], "content": "" // ...other fields } ``` -In the above example, when removing someone from an unbound list (considering a `kind:30382` event), +In the above example, when removing someone from an event set (considering a `kind:30382` event), a client should only delete the event when all tags other than the `d` one were removed and the content is an empty string. -Above example's `T` tag comes from the [Trust Rank](https://github.com/arthurfranca/nips/blob/trust-rank/64.md) -unreleaed spec and it illustrates how unbound list entries can hold extra -data in contrast to NIP-51 list entries that are simple event id/address references. +## Final Considerations + +NIP-51 lists have a limit on the number of items they can hold depending on relay's event size restrictions, +while event sets can have any number of items. + +The downside of event sets is that migrating a list from one relay to another can be rate limited +due to saving many individual events during a small time window. From ca6a812e41b8169fa6503570d815c367e4d42957 Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Fri, 10 May 2024 20:14:31 -0300 Subject: [PATCH 19/36] Replace list with set --- 61.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/61.md b/61.md index 9e661021a..9ef9ce37c 100644 --- a/61.md +++ b/61.md @@ -6,26 +6,26 @@ Event Sets `draft` `optional` -An event set is a group of events with the same pubkey and `n` (list "n"ame) tag. +An event set is a group of events with the same pubkey and `n` (set "n"ame) tag. An event can have many `n` tags, thus being member of many event sets. -To add an event to the "Close Friends" list, +To add an event to the "Close Friends" set, add a "close-friend" (prefer lowercase English words in singular form with dash separator) `n` tag to the event. -To remove an event from a "Close Friends" list, +To remove an event from a "Close Friends" set, remove the "close-friend" `n` tag from the event or send a deletion event (`kind:5`). -An event set itself is referenced by an `u` tag -or by an `nlist` [NIP-19](19.md) entity using [NIP-21](21.md) URI. +An event set itself is referenced by an `s` tag +or by an `nset` [NIP-19](19.md) entity using [NIP-21](21.md) URI. ## Referencing -An event set is referenced by an `u` tag. +An event set is referenced by an `s` tag. It references a set of events from an author instead of a single one: -`["u", ":<32-bytes lowercase hex of a pubkey>:", ""]` +`["s", ":<32-bytes lowercase hex of a pubkey>:", ""]` -One may also use an `nlist` entity URI: `nostr:nlist1qqstn...794234d`. +One may also use an `nset` entity URI: `nostr:nset1qqstn...794234d`. ## Event Kinds @@ -41,8 +41,8 @@ The following example is based on the unreleased "tags": [ ["d", ""], ["n", "follow"], // A "follow" "n" tag turns this event into a kind 3 equivalent entry - ["n", "friend"], // He is part of may "Friends" list - ["n", "close-friend"], // He is also part of my smaller "Close Friends" list + ["n", "friend"], // He is part of may "Friends" set + ["n", "close-friend"], // He is also part of my smaller "Close Friends" set ["n", "contact"], // My contacts are users to whom I've sent DMs or started an one-to-one audio/video call // ...other metadata describing the relationship ], @@ -60,5 +60,5 @@ than the `d` one were removed and the content is an empty string. NIP-51 lists have a limit on the number of items they can hold depending on relay's event size restrictions, while event sets can have any number of items. -The downside of event sets is that migrating a list from one relay to another can be rate limited +The downside of event sets is that migrating a set from one relay to another can be rate limited due to saving many individual events during a small time window. From f1df1d60d55c367a4c2d386a4048e68133ae1455 Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Wed, 15 May 2024 17:56:54 -0300 Subject: [PATCH 20/36] Make room for NIP-51 migration --- 61.md | 151 ++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 116 insertions(+), 35 deletions(-) diff --git a/61.md b/61.md index 9ef9ce37c..78269e5ef 100644 --- a/61.md +++ b/61.md @@ -6,59 +6,140 @@ Event Sets `draft` `optional` -An event set is a group of events with the same pubkey and `n` (set "n"ame) tag. +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`). -To add an event to the "Close Friends" set, -add a "close-friend" (prefer lowercase English words in singular form with dash separator) `n` tag to the event. +## Referencing -To remove an event from a "Close Friends" set, -remove the "close-friend" `n` tag from the event or send a deletion event (`kind:5`). +An event set is referenced by an `s` tag. It +references many events from an author instead of a single one: -An event set itself is referenced by an `s` tag -or by an `nset` [NIP-19](19.md) entity using [NIP-21](21.md) URI. +`["s", ",:<32-bytes lowercase hex of a pubkey>:", ""]` -## Referencing +One may also use an `nset` [NIP-19](19.md) entity through a [NIP-21](21.md) URI: `nostr:nset1qqstn...794234d`. -An event set is referenced by an `s` tag. -It references a set of events from an author instead of a single one: +## Set types -`["s", ":<32-bytes lowercase hex of a pubkey>:", ""]` +There are two types of sets: standard and user-generated. -One may also use an `nset` entity URI: `nostr:nset1qqstn...794234d`. +### Standard -## Event Kinds +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. -The same `n` tag can be applied to any event no matter the `kind` or structure. +| n-tag | description | expected d-tag prefixes if using kind:30161 | +|-|-|-| +| bookmark | uncategorized, "global" list of things a user wants to save | "i:" (kind:1 notes), "a:" (kind:30023 articles), "t:" (hashtags), "r:" (URLs) | +| contact | pubkeys to whom the user sent DMs or started an interaction such as an one-on-one audio/video call | "p:" | +| follow | followed pubkeys | "p:" | +| follow-hashtag | followed hashtags | "t:" | +| file | adds events and files (urls) to a root directory similar to "/" | "i:", "a:", "r:" (url) | +| friend | friends' pubkeys | "p:" | +| mute | pubkeys whose posts the user doesn't want to see in their feeds | "p" (pubkey) | +| mute-event | muted notes | "i:" (event), "a:" (event) | +| mute-hashtag | muted hashtags | "t:" (hashtag) | +| mute-word | muted words | "word:" (lowercase string) | -The following example is based on the unreleased -[Relationship Status](https://github.com/vitorpamplona/nips/blob/relationship-status/81.md) spec: +### User-generated + +Set names must be prefixed with a "\`" (backtick) when on `n` tags to avoid name clashing. +To keep track of these custom names, a "Custom Set" `kind:30061` event is used for each of them. +The `d` tag is the name. Example: ```js { - "kind": 30382, // This is a kind for public relationship info between the signer and another user - "pubkey": "", - "tags": [ - ["d", ""], - ["n", "follow"], // A "follow" "n" tag turns this event into a kind 3 equivalent entry - ["n", "friend"], // He is part of may "Friends" set - ["n", "close-friend"], // He is also part of my smaller "Close Friends" set - ["n", "contact"], // My contacts are users to whom I've sent DMs or started an one-to-one audio/video call - // ...other metadata describing the relationship - ], - "content": "" - // ...other fields + kind: 30061, + tags: [ + ["d", "Good Fellows"] // this name needs a ` (backtick) prefix only when set to an "n" tag + ] + // other fields } ``` -In the above example, when removing someone from an event set (considering a `kind:30382` event), -a client should only delete the event when all tags other +An user-generated set may be grouped in other sets to make them related. +The below example shows how clients can fetch `kind:30061` events with `n-tag=follow` +to discover custom follow set names: + +```js +{ + kind: 30061, + tags: [ + ["d", "Best Friends Forever"], + ["n", "follow"] + ] + // other fields +} +``` + +For names that are secret, an encrypted `map` tag maps the obfuscated set name to its real meaning. +Creating a private directory name example: + +```js +{ + kind: 30061, + tags: [ + ["d", "14pqug65sgl"], // random and unique + ["n", "file"] + ["map", nip44Encrypt("/sub/directory")] + ] + // other fields +} +``` + +## How to add items to a set + +There are two ways: + +**1) Set a `n` tag to the event to be added itself:** Do this if the event set is only made of +events you own. For example, adding one of your long-form posts to the (obfuscated) "/sub/directory": + +```js +{ + kind: 30023, + tags: [ + ["d", ""], + ["n", "`14pqug65sgl"] + // other tags + ] + // other fields +} +``` + +**2) Add a `n` tag to a "Set Item Reference" `kind:30382` event that references the item to be added:** +Do this if the set may include events you don't own or other things that aren't events. + +The `kind:30382` event 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. -## Final Considerations +The `d` tag is set to the item reference with the format `:`. The notable exception +is using `i:::` instead of `e:` for referencing non-replaceable events. +Other common `d` tag values: `a:::`, `p:`, `t:`, `r:`, `word:`. -NIP-51 lists have a limit on the number of items they can hold depending on relay's event size restrictions, -while event sets can have any number of items. +Example of 1 item (a pubkey) that is simultaneously part of 4 event sets: -The downside of event sets is that migrating a set from one relay to another can be rate limited -due to saving many individual events during a small time window. +```js +{ + "kind": 30382, + "pubkey": "", + "tags": [ + ["d", "p:"], + ["n", "follow"], + ["n", "friend"], + ["n", "`Best Friends Forever"], + ["n", "`cfgsq3idn4p"] + // ...other metadata + ], + // ...empty string or secret metadata + "content": "nip44Encrypt(JSON.stringify([ + ["petname", "Zygote"], + ["summary", "Owes me a beer"], + // ...other secret metadata + ]))", + // ...other fields +} +``` From 4149111a2db30d6a533d8af6b8b3c3fc161ea45c Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Thu, 16 May 2024 11:27:48 -0300 Subject: [PATCH 21/36] Apply suggestions --- 61.md | 80 +++++++++++++++++++++++++++++++---------------------------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/61.md b/61.md index 78269e5ef..e56e26a8a 100644 --- a/61.md +++ b/61.md @@ -18,51 +18,46 @@ send a deletion event (`kind:5`). An event set is referenced by an `s` tag. It references many events from an author instead of a single one: -`["s", ",:<32-bytes lowercase hex of a pubkey>:", ""]` +`["s", "::", ""]` One may also use an `nset` [NIP-19](19.md) entity through a [NIP-21](21.md) URI: `nostr:nset1qqstn...794234d`. ## Set types -There are two types of sets: standard and user-generated. +There are two types of sets: standard and custom (most likely user-generated names). ### 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 | expected d-tag prefixes if using kind:30161 | -|-|-|-| -| bookmark | uncategorized, "global" list of things a user wants to save | "i:" (kind:1 notes), "a:" (kind:30023 articles), "t:" (hashtags), "r:" (URLs) | -| contact | pubkeys to whom the user sent DMs or started an interaction such as an one-on-one audio/video call | "p:" | -| follow | followed pubkeys | "p:" | -| follow-hashtag | followed hashtags | "t:" | -| file | adds events and files (urls) to a root directory similar to "/" | "i:", "a:", "r:" (url) | -| friend | friends' pubkeys | "p:" | -| mute | pubkeys whose posts the user doesn't want to see in their feeds | "p" (pubkey) | -| mute-event | muted notes | "i:" (event), "a:" (event) | -| mute-hashtag | muted hashtags | "t:" (hashtag) | -| mute-word | muted words | "word:" (lowercase string) | - -### User-generated - -Set names must be prefixed with a "\`" (backtick) when on `n` tags to avoid name clashing. -To keep track of these custom names, a "Custom Set" `kind:30061` event is used for each of them. +| 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 | + +### Custom + +To **keep track of the custom set names**, a "Custom Set" `kind:30061` event is published for each of them. The `d` tag is the name. Example: ```js { kind: 30061, tags: [ - ["d", "Good Fellows"] // this name needs a ` (backtick) prefix only when set to an "n" tag + ["d", "Good Fellows"] ] // other fields } ``` -An user-generated set may be grouped in other sets to make them related. +**A custom set may be grouped in other sets to make them related by adding an `n` tag**. The below example shows how clients can fetch `kind:30061` events with `n-tag=follow` -to discover custom follow set names: +to discover custom follow-like set names: ```js { @@ -75,7 +70,7 @@ to discover custom follow set names: } ``` -For names that are secret, an encrypted `map` tag maps the obfuscated set name to its real meaning. +**For names that are secret**, an encrypted `map` tag maps the obfuscated set name to its real name. Creating a private directory name example: ```js @@ -83,7 +78,7 @@ Creating a private directory name example: kind: 30061, tags: [ ["d", "14pqug65sgl"], // random and unique - ["n", "file"] + ["n", "file"] // to hint to clients it is a directory-like custom set ["map", nip44Encrypt("/sub/directory")] ] // other fields @@ -94,44 +89,53 @@ Creating a private directory name example: There are two ways: -**1) Set a `n` tag to the event to be added itself:** Do this if the event set is only made of -events you own. For example, adding one of your long-form posts to the (obfuscated) "/sub/directory": +**1) Set a `n` tag to the event to be added itself:** Do this for events that the author is you. +For example, adding one of your long-form posts to the (obfuscated) "/sub/directory": ```js { kind: 30023, tags: [ ["d", ""], - ["n", "`14pqug65sgl"] + ["n", "14pqug65sgl"] // other tags ] // other fields } ``` -**2) Add a `n` tag to a "Set Item Reference" `kind:30382` event that references the item to be added:** -Do this if the set may include events you don't own or other things that aren't events. +**2) Add a `n` tag to a "Set Item Reference" event that references the item to be added:** +Do this if the set include events for which you aren't the author or for other things that aren't events. + +The kind and `d` tag value will vary depending on the type of item being referenced. +The `d` tag value is set to an item reference. +**Some** of the kinds **require** a `k` tag set to the referenced event kind to help with filtering. +Other indexable tags may be added to further assist with filtering: -The `kind:30382` event may have tags other than `n` with extra metadata about the referenced item. +| Type | Kind | d-tag | k-tag required | +|-|-|-|-| +| **pubkey** | 30382 | `` | | +| **event** | 30383 | `:` | :heavy_check_mark: | +| **(parameterized) replaceable event** | 30384 | `::` | :heavy_check_mark: | +| **hashtag** | 30385 | `` | | +| **url** | 30386 | `` | | +| **word** | 30387 | `` | | + +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. -The `d` tag is set to the item reference with the format `:`. The notable exception -is using `i:::` instead of `e:` for referencing non-replaceable events. -Other common `d` tag values: `a:::`, `p:`, `t:`, `r:`, `word:`. - -Example of 1 item (a pubkey) that is simultaneously part of 4 event sets: +Example of 1 item (a pubkey) that is simultaneously part of 3 event sets: ```js { "kind": 30382, "pubkey": "", "tags": [ - ["d", "p:"], + ["d", ""], ["n", "follow"], ["n", "friend"], - ["n", "`Best Friends Forever"], - ["n", "`cfgsq3idn4p"] + ["n", "Best Friends Forever"] // ...other metadata ], // ...empty string or secret metadata From 3566a45048e6321279f46f8530fb4da0b932b25b Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Tue, 21 May 2024 15:48:21 -0300 Subject: [PATCH 22/36] Add private sets --- 61.md | 63 +++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 15 deletions(-) diff --git a/61.md b/61.md index e56e26a8a..b79c48dbc 100644 --- a/61.md +++ b/61.md @@ -77,9 +77,9 @@ Creating a private directory name example: { kind: 30061, tags: [ - ["d", "14pqug65sgl"], // random and unique + ["d", "14pqug65sgl"], // obfuscated set name (random and unique) ["n", "file"] // to hint to clients it is a directory-like custom set - ["map", nip44Encrypt("/sub/directory")] + ["map", nip44Encrypt("/sub/directory")] // the real set name is encrypted ] // other fields } @@ -108,18 +108,24 @@ For example, adding one of your long-form posts to the (obfuscated) "/sub/direct Do this if the set include events for which you aren't the author or for other things that aren't events. The kind and `d` tag value will vary depending on the type of item being referenced. + +For each type of item being referenced, there is a public "Set Item Reference" event kind and a private kind. +Both have the same structure and tags. The unique features of the private version will be explained later. + The `d` tag value is set to an item reference. -**Some** of the kinds **require** a `k` tag set to the referenced event kind to help with filtering. -Other indexable tags may be added to further assist with filtering: - -| Type | Kind | d-tag | k-tag required | -|-|-|-|-| -| **pubkey** | 30382 | `` | | -| **event** | 30383 | `:` | :heavy_check_mark: | -| **(parameterized) replaceable event** | 30384 | `::` | :heavy_check_mark: | -| **hashtag** | 30385 | `` | | -| **url** | 30386 | `` | | -| **word** | 30387 | `` | | +**Some** of the event kinds **require** a `k` tag set to the referenced item kind to help with filtering. +Other indexable tags may be added to further assist with filtering. + +**Table of "Set Item Reference" Event Kinds and Structure by Referenced Item Type**: + +| Type | Kind | Private Kind | d-tag | k-tag | +|-|-|-|-|-| +| **pubkey** | 30382 | 31382 | `` | | +| **event** | 30383 | 31383 | `:` | `` | +| **(parameterized) replaceable event** | 30384 | 31384 | `::` | `` | +| **hashtag** | 30385 | 31385 | `` | | +| **url** | 30386 | 31386 | `` | | +| **word** | 30387 | 31387 | `` | | 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 @@ -139,11 +145,38 @@ Example of 1 item (a pubkey) that is simultaneously part of 3 event sets: // ...other metadata ], // ...empty string or secret metadata - "content": "nip44Encrypt(JSON.stringify([ + "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](44.md) 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. + +Example event: + +```js +{ + "kind": 31382, + "pubkey": "", + "tags": [ + ["d", toHex(sha256(hkdf("", salt: "nip61") || ""))] + ["n", "example-set-name"] + ], + "content": nip44Encrypt(JSON.stringify([ + ["d", ""] + // ...other secret metadata + ])), // ...other fields } ``` From 4415ffcea7229b0fff6843b8fa0a9d78751bbae5 Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Tue, 21 May 2024 18:59:41 -0300 Subject: [PATCH 23/36] move sections --- 61.md | 134 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/61.md b/61.md index b79c48dbc..025e855a6 100644 --- a/61.md +++ b/61.md @@ -22,82 +22,19 @@ references many events from an author instead of a single one: One may also use an `nset` [NIP-19](19.md) entity through a [NIP-21](21.md) URI: `nostr:nset1qqstn...794234d`. -## Set types - -There are two types of sets: standard and custom (most likely user-generated names). - -### 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 | - -### Custom - -To **keep track of the custom set names**, a "Custom Set" `kind:30061` event is published for each of them. -The `d` tag is the name. Example: - -```js -{ - kind: 30061, - tags: [ - ["d", "Good Fellows"] - ] - // other fields -} -``` - -**A custom set may be grouped in other sets to make them related by adding an `n` tag**. -The below example shows how clients can fetch `kind:30061` events with `n-tag=follow` -to discover custom follow-like set names: - -```js -{ - kind: 30061, - tags: [ - ["d", "Best Friends Forever"], - ["n", "follow"] - ] - // other fields -} -``` - -**For names that are secret**, an encrypted `map` tag maps the obfuscated set name to its real name. -Creating a private directory name example: - -```js -{ - kind: 30061, - tags: [ - ["d", "14pqug65sgl"], // obfuscated set name (random and unique) - ["n", "file"] // to hint to clients it is a directory-like custom set - ["map", nip44Encrypt("/sub/directory")] // the real set name is encrypted - ] - // other fields -} -``` - ## How to add items to a set There are two ways: -**1) Set a `n` tag to the event to be added itself:** Do this for events that the author is you. -For example, adding one of your long-form posts to the (obfuscated) "/sub/directory": +**1) Include a `n` tag (the set's name) in the event to be added itself:** Do this for events that the author is you. +For example, adding one of your long-form posts to a set named "a-set-name-example": ```js { kind: 30023, tags: [ ["d", ""], - ["n", "14pqug65sgl"] + ["n", "a-set-name-example"] // other tags ] // other fields @@ -105,7 +42,7 @@ For example, adding one of your long-form posts to the (obfuscated) "/sub/direct ``` **2) Add a `n` tag to a "Set Item Reference" event that references the item to be added:** -Do this if the set include events for which you aren't the author or for other things that aren't events. +Do this if the set includes events for which you aren't the author or for other things that aren't events. The kind and `d` tag value will vary depending on the type of item being referenced. @@ -180,3 +117,66 @@ Example event: // ...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 | + +### Custom + +To **keep track of the custom set names**, a "Custom Set" `kind:30061` event is published for each of them. +The `d` tag is the name. Example: + +```js +{ + kind: 30061, + tags: [ + ["d", "Good Fellows"] + ] + // other fields +} +``` + +**A custom set may be grouped in other sets to make them related by adding an `n` tag**. +The below example shows how clients can fetch `kind:30061` events with `n-tag=follow` +to discover custom follow-like set names: + +```js +{ + kind: 30061, + tags: [ + ["d", "Best Friends Forever"], + ["n", "follow"] + ] + // other fields +} +``` + +**For names that are secret**, an encrypted `map` tag maps the obfuscated set name to its real name. +Creating a private directory name example: + +```js +{ + kind: 30061, + tags: [ + ["d", "14pqug65sgl"], // obfuscated set name (random and unique) + ["n", "file"] // to hint to clients it is a directory-like custom set + ["map", nip44Encrypt("/sub/directory")] // the real set name is encrypted + ] + // other fields +} +``` From fec7136c93aa9c31b79b714f3a999c34a8d7cf00 Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Wed, 22 May 2024 18:29:07 -0300 Subject: [PATCH 24/36] Add missing item types --- 61.md | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/61.md b/61.md index 025e855a6..ca7c5141b 100644 --- a/61.md +++ b/61.md @@ -47,22 +47,34 @@ Do this if the set includes events for which you aren't the author or for other The kind and `d` tag value will vary depending on the type of item being referenced. For each type of item being referenced, there is a public "Set Item Reference" event kind and a private kind. -Both have the same structure and tags. The unique features of the private version will be explained later. +Both have the same structure and tags. The unique features of the private version will be explained on the next section. The `d` tag value is set to an item reference. **Some** of the event kinds **require** a `k` tag set to the referenced item kind to help with filtering. Other indexable tags may be added to further assist with filtering. -**Table of "Set Item Reference" Event Kinds and Structure by Referenced Item Type**: - -| Type | Kind | Private Kind | d-tag | k-tag | -|-|-|-|-|-| -| **pubkey** | 30382 | 31382 | `` | | -| **event** | 30383 | 31383 | `:` | `` | -| **(parameterized) replaceable event** | 30384 | 31384 | `::` | `` | -| **hashtag** | 30385 | 31385 | `` | | -| **url** | 30386 | 31386 | `` | | -| **word** | 30387 | 31387 | `` | | +**Table of "Set Item Reference" Event Kinds and Structure by Referenced Item Type**: Note that `obfuscate()` +is representing a step taken to hash the `d` tag value when building private "Set Item Reference" events, +explained on the next section. + +| Type | Kind | d-tag | other required tags | +|-|-|-|-| +| **pubkey** | 30382 | `` | | +| **pubkey** (private) | 31382 | obfuscate(``) | | +| **event** | 30383 | `:` | `["k", ""]` | +| **event** (private) | 31383 | obfuscate(`:`) | `["k", ""]` | +| **(parameterized) replaceable event** | 30384 | `::` | `["k", ""]` | +| **(parameterized) replaceable event** (private) | 31384 | obfuscate(`::`) | `["k", ""]` | +| **hashtag** | 30385 | `` | | +| **hashtag** (private) | 31385 | obfuscate(``) | | +| **url** | 30386 | `` | | +| **url** (private) | 31386 | obfuscate(``) | | +| **relay** | 30387 | `` | | +| **relay** (private) | 31387 | obfuscate(`` | | +| **emoji** | 30388 | ``) | `["emoji", ""]` | +| **emoji** (private) | 31388 | obfuscate(``) | `["emoji", ""]` | +| **word** | 30389 | `` | | +| **word** (private) | 31389 | obfuscate(``) | | 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 From 7c39167c6cd3dba18c62342237269be737570353 Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Wed, 22 May 2024 18:32:19 -0300 Subject: [PATCH 25/36] Add pin set --- 61.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/61.md b/61.md index ca7c5141b..5d58cc36f 100644 --- a/61.md +++ b/61.md @@ -146,7 +146,8 @@ The convention is to prefer lowercase English words in singular form with dash s | 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 | +| mute | pubkeys, hashtags, words or notes the user doesn't want to see in their feeds and blocked relays | +| pin | events to showcase in the user profile page | ### Custom From 3d904c397876a9d4ad521d9b46381b7961d01b72 Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Thu, 23 May 2024 12:03:20 -0300 Subject: [PATCH 26/36] Update 61.md Co-authored-by: Vitor Pamplona --- 61.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/61.md b/61.md index 5d58cc36f..b8787b1a8 100644 --- a/61.md +++ b/61.md @@ -42,7 +42,7 @@ For example, adding one of your long-form posts to a set named "a-set-name-examp ``` **2) Add a `n` tag to a "Set Item Reference" event that references the item to be added:** -Do this if the set includes events for which you aren't the author or for other things that aren't events. +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. From 03bd37f93e4cd83b6df316348345b8beb3b756a5 Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Thu, 23 May 2024 12:03:30 -0300 Subject: [PATCH 27/36] Update 61.md Co-authored-by: Vitor Pamplona --- 61.md | 1 - 1 file changed, 1 deletion(-) diff --git a/61.md b/61.md index b8787b1a8..a92deeea8 100644 --- a/61.md +++ b/61.md @@ -49,7 +49,6 @@ The kind and `d` tag value will vary depending on the type of item being referen For each type of item being referenced, there is a public "Set Item Reference" event kind and a private kind. Both have the same structure and tags. The unique features of the private version will be explained on the next section. -The `d` tag value is set to an item reference. **Some** of the event kinds **require** a `k` tag set to the referenced item kind to help with filtering. Other indexable tags may be added to further assist with filtering. From d16e8b9164762ff91a784a3b44aa6a710280755b Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Thu, 23 May 2024 12:03:44 -0300 Subject: [PATCH 28/36] Update 61.md Co-authored-by: Vitor Pamplona --- 61.md | 1 - 1 file changed, 1 deletion(-) diff --git a/61.md b/61.md index a92deeea8..97d319a2b 100644 --- a/61.md +++ b/61.md @@ -46,7 +46,6 @@ You SHOULD use a list of pre-defined event kinds to tag existing events, public The kind and `d` tag value will vary depending on the type of item being referenced. -For each type of item being referenced, there is a public "Set Item Reference" event kind and a private kind. Both have the same structure and tags. The unique features of the private version will be explained on the next section. **Some** of the event kinds **require** a `k` tag set to the referenced item kind to help with filtering. From 47a0aceac6ff45337c255b2018a3740851a4422c Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Thu, 23 May 2024 12:03:59 -0300 Subject: [PATCH 29/36] Update 61.md Co-authored-by: Vitor Pamplona --- 61.md | 1 - 1 file changed, 1 deletion(-) diff --git a/61.md b/61.md index 97d319a2b..74c23a284 100644 --- a/61.md +++ b/61.md @@ -46,7 +46,6 @@ You SHOULD use a list of pre-defined event kinds to tag existing events, public The kind and `d` tag value will vary depending on the type of item being referenced. -Both have the same structure and tags. The unique features of the private version will be explained on the next section. **Some** of the event kinds **require** a `k` tag set to the referenced item kind to help with filtering. Other indexable tags may be added to further assist with filtering. From 687707013ab8a879e996b3d89831eb05e58fd0ee Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Thu, 23 May 2024 14:37:45 -0300 Subject: [PATCH 30/36] Move things and change kind 30061 --- 61.md | 101 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 52 insertions(+), 49 deletions(-) diff --git a/61.md b/61.md index 74c23a284..d83ddd668 100644 --- a/61.md +++ b/61.md @@ -1,8 +1,8 @@ NIP-61 ====== -Event Sets ----------- +Event Set +--------- `draft` `optional` @@ -24,15 +24,12 @@ One may also use an `nset` [NIP-19](19.md) entity through a [NIP-21](21.md) URI: ## How to add items to a set -There are two ways: - -**1) Include a `n` tag (the set's name) in the event to be added itself:** Do this for events that the author is you. -For example, adding one of your long-form posts to a set named "a-set-name-example": +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": ```js { - kind: 30023, - tags: [ + "kind": 30023, + "tags": [ ["d", ""], ["n", "a-set-name-example"] // other tags @@ -41,14 +38,13 @@ For example, adding one of your long-form posts to a set named "a-set-name-examp } ``` -**2) Add a `n` tag to a "Set Item Reference" event that references the item to be added:** -You SHOULD use a list of pre-defined event kinds to tag existing events, public keys, or other references into sets. +## Tagging into Event Sets -The kind and `d` tag value will vary depending on the type of item being referenced. +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. -Other indexable tags may be added to further assist with filtering. +**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**: Note that `obfuscate()` is representing a step taken to hash the `d` tag value when building private "Set Item Reference" events, @@ -57,21 +53,13 @@ explained on the next section. | Type | Kind | d-tag | other required tags | |-|-|-|-| | **pubkey** | 30382 | `` | | -| **pubkey** (private) | 31382 | obfuscate(``) | | | **event** | 30383 | `:` | `["k", ""]` | -| **event** (private) | 31383 | obfuscate(`:`) | `["k", ""]` | | **(parameterized) replaceable event** | 30384 | `::` | `["k", ""]` | -| **(parameterized) replaceable event** (private) | 31384 | obfuscate(`::`) | `["k", ""]` | | **hashtag** | 30385 | `` | | -| **hashtag** (private) | 31385 | obfuscate(``) | | | **url** | 30386 | `` | | -| **url** (private) | 31386 | obfuscate(``) | | | **relay** | 30387 | `` | | -| **relay** (private) | 31387 | obfuscate(`` | | | **emoji** | 30388 | ``) | `["emoji", ""]` | -| **emoji** (private) | 31388 | obfuscate(``) | `["emoji", ""]` | | **word** | 30389 | `` | | -| **word** (private) | 31389 | obfuscate(``) | | 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 @@ -100,7 +88,7 @@ Example of 1 item (a pubkey) that is simultaneously part of 3 event sets: } ``` -**Private "Set Item Reference" Event:** +### 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`. @@ -109,6 +97,20 @@ To obfuscate a value, it is deterministically hashed by generating an auxiliary with the [NIP-44](44.md) 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()` +is representing the step taken to hash the `d` tag value explained above. + +| Type | Kind | d-tag | other required tags | +|-|-|-|-| +| **pubkey** (private) | 31382 | obfuscate(``) | | +| **event** (private) | 31383 | obfuscate(`:`) | `["k", ""]` | +| **(parameterized) replaceable event** (private) | 31384 | obfuscate(`::`) | `["k", ""]` | +| **hashtag** (private) | 31385 | obfuscate(``) | | +| **url** (private) | 31386 | obfuscate(``) | | +| **relay** (private) | 31387 | obfuscate(`` | | +| **emoji** (private) | 31388 | obfuscate(``) | `["emoji", ""]` | +| **word** (private) | 31389 | obfuscate(``) | | + Example event: ```js @@ -148,45 +150,46 @@ The convention is to prefer lowercase English words in singular form with dash s ### Custom -To **keep track of the custom set names**, a "Custom Set" `kind:30061` event is published for each of them. -The `d` tag is the name. Example: +To **keep track of the custom set names**, the encrypted parameterized replaceable "Custom Sets" `kind:30061` event is used. -```js -{ - kind: 30061, - tags: [ - ["d", "Good Fellows"] - ] - // other fields -} -``` +Such event with `d-tag=""` lists custom set names with no expected special treatment by clients +(these sets effectively work like labels). -**A custom set may be grouped in other sets to make them related by adding an `n` tag**. -The below example shows how clients can fetch `kind:30061` events with `n-tag=follow` -to discover custom follow-like set names: +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: ```js { - kind: 30061, - tags: [ - ["d", "Best Friends Forever"], - ["n", "follow"] + "kind": 30061, + "tags": [ + ["d", ""] ] - // other fields + "content": nip44Encrypt(JSON.stringify([ + ["map", "", ""], + ["map", "Good Fellow", "Good Fellow"], + ["map", "6064460175057025", "Debtor"] + ])), + // ...other fields } ``` -**For names that are secret**, an encrypted `map` tag maps the obfuscated set name to its real name. -Creating a private directory name example: - ```js { - kind: 30061, - tags: [ - ["d", "14pqug65sgl"], // obfuscated set name (random and unique) - ["n", "file"] // to hint to clients it is a directory-like custom set - ["map", nip44Encrypt("/sub/directory")] // the real set name is encrypted + "kind": 30061, + "tags": [ + ["d", "file"] ] + "content": nip44Encrypt(JSON.stringify([ + ["map", "4234649720408324", "/sub/directory"], + ["map", "/home", "/home"] + ])) // other fields } ``` From b25960808d819e22031b501dfe9ff3201adb03c5 Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Tue, 28 May 2024 10:03:10 -0300 Subject: [PATCH 31/36] Remove orphaned sentence --- 61.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/61.md b/61.md index d83ddd668..cf882f1a0 100644 --- a/61.md +++ b/61.md @@ -46,9 +46,7 @@ The kind and `d` tag value will vary depending on the type of item being referen **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**: Note that `obfuscate()` -is representing a step taken to hash the `d` tag value when building private "Set Item Reference" events, -explained on the next section. +**Table of "Set Item Reference" Event Kinds and Structure by Referenced Item Type**: | Type | Kind | d-tag | other required tags | |-|-|-|-| From dc0d92c07579015be666dc06d341e62525bb47b3 Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Sun, 9 Jun 2024 15:46:45 -0300 Subject: [PATCH 32/36] Add p tag to 30383 and 31383 --- 61.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/61.md b/61.md index cf882f1a0..d0ec941ff 100644 --- a/61.md +++ b/61.md @@ -51,7 +51,7 @@ The kind and `d` tag value will vary depending on the type of item being referen | Type | Kind | d-tag | other required tags | |-|-|-|-| | **pubkey** | 30382 | `` | | -| **event** | 30383 | `:` | `["k", ""]` | +| **event** | 30383 | `` | `["k", ""]`, `["p", ""]` | | **(parameterized) replaceable event** | 30384 | `::` | `["k", ""]` | | **hashtag** | 30385 | `` | | | **url** | 30386 | `` | | @@ -101,7 +101,7 @@ is representing the step taken to hash the `d` tag value explained above. | Type | Kind | d-tag | other required tags | |-|-|-|-| | **pubkey** (private) | 31382 | obfuscate(``) | | -| **event** (private) | 31383 | obfuscate(`:`) | `["k", ""]` | +| **event** (private) | 31383 | obfuscate(``) | `["k", ""]`, `["p", obfuscate("")]` | | **(parameterized) replaceable event** (private) | 31384 | obfuscate(`::`) | `["k", ""]` | | **hashtag** (private) | 31385 | obfuscate(``) | | | **url** (private) | 31386 | obfuscate(``) | | From fa9ec29e025d4e33f38f8eacf743db501435e91d Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Sun, 9 Jun 2024 15:56:57 -0300 Subject: [PATCH 33/36] Add notification and upload set names --- 61.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/61.md b/61.md index d0ec941ff..48265dd98 100644 --- a/61.md +++ b/61.md @@ -144,7 +144,9 @@ The convention is to prefer lowercase English words in singular form with dash s | 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 From 1f06fb10741d8e1ab22d5de5f9d80b46a675c7a0 Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Fri, 14 Jun 2024 18:24:53 -0300 Subject: [PATCH 34/36] hide private tags --- 61.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/61.md b/61.md index 48265dd98..b2c175081 100644 --- a/61.md +++ b/61.md @@ -101,12 +101,12 @@ is representing the step taken to hash the `d` tag value explained above. | Type | Kind | d-tag | other required tags | |-|-|-|-| | **pubkey** (private) | 31382 | obfuscate(``) | | -| **event** (private) | 31383 | obfuscate(``) | `["k", ""]`, `["p", obfuscate("")]` | -| **(parameterized) replaceable event** (private) | 31384 | obfuscate(`::`) | `["k", ""]` | +| **event** (private) | 31383 | obfuscate(``) | `["k", obfuscate("")]`, `["p", obfuscate("")]` | +| **(parameterized) replaceable event** (private) | 31384 | obfuscate(`::`) | `["k", obfuscate("")]` | | **hashtag** (private) | 31385 | obfuscate(``) | | | **url** (private) | 31386 | obfuscate(``) | | | **relay** (private) | 31387 | obfuscate(`` | | -| **emoji** (private) | 31388 | obfuscate(``) | `["emoji", ""]` | +| **emoji** (private) | 31388 | obfuscate(``) | `addToEncryptedContent(["emoji", ""])` | | **word** (private) | 31389 | obfuscate(``) | | Example event: From c339d5d9326f9f333ade50188abb7b69b736740c Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Thu, 20 Jun 2024 17:00:45 -0300 Subject: [PATCH 35/36] Remove set names related to NIP-51 --- 61.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/61.md b/61.md index b2c175081..5aa7e2f4d 100644 --- a/61.md +++ b/61.md @@ -71,7 +71,7 @@ Example of 1 item (a pubkey) that is simultaneously part of 3 event sets: "pubkey": "", "tags": [ ["d", ""], - ["n", "follow"], + ["n", "contact"], ["n", "friend"], ["n", "Best Friends Forever"] // ...other metadata @@ -138,14 +138,10 @@ The convention is to prefer lowercase English words in singular form with dash s | 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 @@ -156,8 +152,8 @@ Such event with `d-tag=""` lists custom set names with no expected special treat (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. +the corresponding **standard** set. For example, sets listed within a `kind:30061` with `d-tag="file"` are treated +by clients the same way as the "file" set, i.e., they could be presented as file system directories. 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 From fdb6444e8a0fdfb20769e734649eef79a9886e44 Mon Sep 17 00:00:00 2001 From: arthurfranca Date: Thu, 20 Jun 2024 18:37:27 -0300 Subject: [PATCH 36/36] Remove set item reference events --- 61.md | 89 ----------------------------------------------------------- 1 file changed, 89 deletions(-) diff --git a/61.md b/61.md index 5aa7e2f4d..c14b27061 100644 --- a/61.md +++ b/61.md @@ -38,95 +38,6 @@ Just add an `n` tag to your event. For example, adding one of your long-form pos } ``` -## 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 | `` | | -| **event** | 30383 | `` | `["k", ""]`, `["p", ""]` | -| **(parameterized) replaceable event** | 30384 | `::` | `["k", ""]` | -| **hashtag** | 30385 | `` | | -| **url** | 30386 | `` | | -| **relay** | 30387 | `` | | -| **emoji** | 30388 | ``) | `["emoji", ""]` | -| **word** | 30389 | `` | | - -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: - -```js -{ - "kind": 30382, - "pubkey": "", - "tags": [ - ["d", ""], - ["n", "contact"], - ["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](44.md) 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()` -is representing the step taken to hash the `d` tag value explained above. - -| Type | Kind | d-tag | other required tags | -|-|-|-|-| -| **pubkey** (private) | 31382 | obfuscate(``) | | -| **event** (private) | 31383 | obfuscate(``) | `["k", obfuscate("")]`, `["p", obfuscate("")]` | -| **(parameterized) replaceable event** (private) | 31384 | obfuscate(`::`) | `["k", obfuscate("")]` | -| **hashtag** (private) | 31385 | obfuscate(``) | | -| **url** (private) | 31386 | obfuscate(``) | | -| **relay** (private) | 31387 | obfuscate(`` | | -| **emoji** (private) | 31388 | obfuscate(``) | `addToEncryptedContent(["emoji", ""])` | -| **word** (private) | 31389 | obfuscate(``) | | - -Example event: - -```js -{ - "kind": 31382, - "pubkey": "", - "tags": [ - ["d", toHex(sha256(hkdf("", salt: "nip61") || ""))] - ["n", "example-set-name"] - ], - "content": nip44Encrypt(JSON.stringify([ - ["d", ""] - // ...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).