-
Notifications
You must be signed in to change notification settings - Fork 578
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2313dbc
commit 30fe94f
Showing
1 changed file
with
39 additions
and
102 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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` (name) 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>:<n tag value>", "<recommended relay URL, optional>"]` | ||
|
||
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": "<NIP-44 encrypted Stringified TAG-List([ | ||
["p", "91cf9..4e5ca", "wss://alicerelay.com/"] | ||
])>", | ||
// ...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": "<me>", | ||
"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", "<another-user-pubkey>"], | ||
["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": "<NIP-44 encrypted Stringified TAG-List([ | ||
// This has multiple "p" tags because it is a NIP-51 Categorized People list | ||
["p", "14aeb..8dad4", "wss://bobrelay.com/nostr"], | ||
["p", "612ae..e610f", "ws://carolrelay.com/ws"] | ||
])>", | ||
"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", "<random string mapped to 'Scammer' list>"], | ||
["relay", "<recommended relay>"], | ||
], | ||
"content": "<NIP-44 encrypted Stringified TAG-List([ | ||
["nickname", "Big Joe"], | ||
["summary", "<summary of the relationship>"], | ||
["email", "[email protected]"] | ||
])>", | ||
// ...other fields | ||
} | ||
{ | ||
"kind": 10003, | ||
"content": "<NIP-44 encrypted Stringified TAG-List([ | ||
["status", "Scammer", "3737815743613957"], | ||
["status", "Great Friend", "9369453848773155"], | ||
["status", "Ex-Girlfriend", "17740745702992977"] | ||
])>", | ||
// ...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. |