upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--01.md16
-rw-r--r--02.md20
-rw-r--r--07.md1
-rw-r--r--09.md2
-rw-r--r--10.md2
-rw-r--r--11.md11
-rw-r--r--15.md2
-rw-r--r--22.md45
-rw-r--r--42.md71
-rw-r--r--45.md11
-rw-r--r--47.md2
-rw-r--r--51.md189
-rw-r--r--53.md2
-rw-r--r--57.md4
-rw-r--r--58.md2
-rw-r--r--75.md4
-rw-r--r--89.md8
-rw-r--r--90.md2
-rw-r--r--README.md144
19 files changed, 256 insertions, 282 deletions
diff --git a/01.md b/01.md
index dafea1d..99c991a 100644
--- a/01.md
+++ b/01.md
@@ -96,10 +96,6 @@ These are just conventions and relay implementations may differ.
96 96
97Relays expose a websocket endpoint to which clients can connect. Clients SHOULD open a single websocket connection to each relay and use it for all their subscriptions. Relays MAY limit number of connections from specific IP/client/etc. 97Relays expose a websocket endpoint to which clients can connect. Clients SHOULD open a single websocket connection to each relay and use it for all their subscriptions. Relays MAY limit number of connections from specific IP/client/etc.
98 98
99### Meaning of WebSocket status codes
100
101- When a websocket is closed by the relay with a status code `4000` that means the client shouldn't try to connect again.
102
103### From client to relay: sending events and creating subscriptions 99### From client to relay: sending events and creating subscriptions
104 100
105Clients can send 3 types of messages, which must be JSON arrays, according to the following patterns: 101Clients can send 3 types of messages, which must be JSON arrays, according to the following patterns:
@@ -145,19 +141,25 @@ Relays can send 4 types of messages, which must also be JSON arrays, according t
145 * `["EVENT", <subscription_id>, <event JSON as defined above>]`, used to send events requested by clients. 141 * `["EVENT", <subscription_id>, <event JSON as defined above>]`, used to send events requested by clients.
146 * `["OK", <event_id>, <true|false>, <message>]`, used to indicate acceptance or denial of an `EVENT` message. 142 * `["OK", <event_id>, <true|false>, <message>]`, used to indicate acceptance or denial of an `EVENT` message.
147 * `["EOSE", <subscription_id>]`, used to indicate the _end of stored events_ and the beginning of events newly received in real-time. 143 * `["EOSE", <subscription_id>]`, used to indicate the _end of stored events_ and the beginning of events newly received in real-time.
144 * `["CLOSED", <subscription_id>, <message>]`, used to indicate that a subscription was ended on the server side.
148 * `["NOTICE", <message>]`, used to send human-readable error messages or other things to clients. 145 * `["NOTICE", <message>]`, used to send human-readable error messages or other things to clients.
149 146
150This NIP defines no rules for how `NOTICE` messages should be sent or treated. 147This NIP defines no rules for how `NOTICE` messages should be sent or treated.
151 148
152- `EVENT` messages MUST be sent only with a subscription ID related to a subscription previously initiated by the client (using the `REQ` message above). 149- `EVENT` messages MUST be sent only with a subscription ID related to a subscription previously initiated by the client (using the `REQ` message above).
153- `OK` messages MUST be sent in response to `EVENT` messages received from clients, they must have the 3rd parameter set to `true` when an event has been accepted by the relay, `false` otherwise. The 4th parameter MUST always be present, but MAY be an empty string when the 3rd is `true`, otherwise it MUST be a string formed by a machine-readable single-word prefix followed by a `:` and then a human-readable message. The standardized machine-readable prefixes are: `duplicate`, `pow`, `blocked`, `rate-limited`, `invalid`, and `error` for when none of that fits. Some examples: 150- `OK` messages MUST be sent in response to `EVENT` messages received from clients, they must have the 3rd parameter set to `true` when an event has been accepted by the relay, `false` otherwise. The 4th parameter MUST always be present, but MAY be an empty string when the 3rd is `true`, otherwise it MUST be a string formed by a machine-readable single-word prefix followed by a `:` and then a human-readable message. Some examples:
154
155 * `["OK", "b1a649ebe8...", true, ""]` 151 * `["OK", "b1a649ebe8...", true, ""]`
156 * `["OK", "b1a649ebe8...", true, "pow: difficulty 25>=24"]` 152 * `["OK", "b1a649ebe8...", true, "pow: difficulty 25>=24"]`
157 * `["OK", "b1a649ebe8...", true, "duplicate: already have this event"]` 153 * `["OK", "b1a649ebe8...", true, "duplicate: already have this event"]`
158 * `["OK", "b1a649ebe8...", false, "blocked: you are banned from posting here"]` 154 * `["OK", "b1a649ebe8...", false, "blocked: you are banned from posting here"]`
159 * `["OK", "b1a649ebe8...", false, "blocked: please register your pubkey at https://my-expensive-relay.example.com"]` 155 * `["OK", "b1a649ebe8...", false, "blocked: please register your pubkey at https://my-expensive-relay.example.com"]`
160 * `["OK", "b1a649ebe8...", false, "rate-limited: slow down there chief"]` 156 * `["OK", "b1a649ebe8...", false, "rate-limited: slow down there chief"]`
161 * `["OK", "b1a649ebe8...", false, "invalid: event creation date is too far off from the current time. Is your system clock in sync?"]` 157 * `["OK", "b1a649ebe8...", false, "invalid: event creation date is too far off from the current time"]`
162 * `["OK", "b1a649ebe8...", false, "pow: difficulty 26 is less than 30"]` 158 * `["OK", "b1a649ebe8...", false, "pow: difficulty 26 is less than 30"]`
163 * `["OK", "b1a649ebe8...", false, "error: could not connect to the database"]` 159 * `["OK", "b1a649ebe8...", false, "error: could not connect to the database"]`
160- `CLOSED` messages MUST be sent in response to a `REQ` when the relay refuses to fulfill it. It can also be sent when a relay decides to kill a subscription on its side before a client has disconnected or sent a `CLOSE`. This message uses the same pattern of `OK` messages with the machine-readable prefix and human-readable message. Some examples:
161 * `["CLOSED", "sub1", "duplicate: sub1 already opened"]`
162 * `["CLOSED", "sub1", "unsupported: filter contains unknown elements"]`
163 * `["CLOSED", "sub1", "error: could not connect to the database"]`
164 * `["CLOSED", "sub1", "error: shutting down idle subscription"]`
165- The standardized machine-readable prefixes for `OK` and `CLOSED` are: `duplicate`, `pow`, `blocked`, `rate-limited`, `invalid`, and `error` for when none of that fits.
diff --git a/02.md b/02.md
index 0653d06..8c47a5f 100644
--- a/02.md
+++ b/02.md
@@ -1,12 +1,12 @@
1NIP-02 1NIP-02
2====== 2======
3 3
4Contact List and Petnames 4Follow List
5------------------------- 5-----------
6 6
7`final` `optional` 7`final` `optional`
8 8
9A special event with kind `3`, meaning "contact list" is defined as having a list of `p` tags, one for each of the followed/known profiles one is following. 9A special event with kind `3`, meaning "follow list" is defined as having a list of `p` tags, one for each of the followed/known profiles one is following.
10 10
11Each tag entry should contain the key for the profile, a relay URL where events from that key can be found (can be set to an empty string if not needed), and a local name (or "petname") for that profile (can also be set to an empty string or not provided), i.e., `["p", <32-bytes hex key>, <main relay URL>, <petname>]`. The `content` can be anything and should be ignored. 11Each tag entry should contain the key for the profile, a relay URL where events from that key can be found (can be set to an empty string if not needed), and a local name (or "petname") for that profile (can also be set to an empty string or not provided), i.e., `["p", <32-bytes hex key>, <main relay URL>, <petname>]`. The `content` can be anything and should be ignored.
12 12
@@ -25,27 +25,27 @@ For example:
25} 25}
26``` 26```
27 27
28Every new contact list that gets published overwrites the past ones, so it should contain all entries. Relays and clients SHOULD delete past contact lists as soon as they receive a new one. 28Every new following list that gets published overwrites the past ones, so it should contain all entries. Relays and clients SHOULD delete past following lists as soon as they receive a new one.
29 29
30## Uses 30## Uses
31 31
32### Contact list backup 32### Follow list backup
33 33
34If one believes a relay will store their events for sufficient time, they can use this kind-3 event to backup their following list and recover on a different device. 34If one believes a relay will store their events for sufficient time, they can use this kind-3 event to backup their following list and recover on a different device.
35 35
36### Profile discovery and context augmentation 36### Profile discovery and context augmentation
37 37
38A client may rely on the kind-3 event to display a list of followed people by profiles one is browsing; make lists of suggestions on who to follow based on the contact lists of other people one might be following or browsing; or show the data in other contexts. 38A client may rely on the kind-3 event to display a list of followed people by profiles one is browsing; make lists of suggestions on who to follow based on the follow lists of other people one might be following or browsing; or show the data in other contexts.
39 39
40### Relay sharing 40### Relay sharing
41 41
42A client may publish a full list of contacts with good relays for each of their contacts so other clients may use these to update their internal relay lists if needed, increasing censorship-resistance. 42A client may publish a follow list with good relays for each of their follows so other clients may use these to update their internal relay lists if needed, increasing censorship-resistance.
43 43
44### Petname scheme 44### Petname scheme
45 45
46The data from these contact lists can be used by clients to construct local ["petname"](http://www.skyhunter.com/marcs/petnames/IntroPetNames.html) tables derived from other people's contact lists. This alleviates the need for global human-readable names. For example: 46The data from these follow lists can be used by clients to construct local ["petname"](http://www.skyhunter.com/marcs/petnames/IntroPetNames.html) tables derived from other people's follow lists. This alleviates the need for global human-readable names. For example:
47 47
48A user has an internal contact list that says 48A user has an internal follow list that says
49 49
50```json 50```json
51[ 51[
@@ -53,7 +53,7 @@ A user has an internal contact list that says
53] 53]
54``` 54```
55 55
56And receives two contact lists, one from `21df6d143fb96c2ec9d63726bf9edc71` that says 56And receives two follow lists, one from `21df6d143fb96c2ec9d63726bf9edc71` that says
57 57
58```json 58```json
59[ 59[
diff --git a/07.md b/07.md
index 01af6f4..aa0a5f4 100644
--- a/07.md
+++ b/07.md
@@ -36,3 +36,4 @@ async window.nostr.nip04.decrypt(pubkey, ciphertext): string // takes ciphertext
36- [Spring Browser](https://spring.site) (Android) 36- [Spring Browser](https://spring.site) (Android)
37- [nodestr](https://github.com/lightning-digital-entertainment/nodestr) (NodeJS polyfill) 37- [nodestr](https://github.com/lightning-digital-entertainment/nodestr) (NodeJS polyfill)
38- [Nostore](https://apps.apple.com/us/app/nostore/id1666553677) (Safari on iOS/MacOS) 38- [Nostore](https://apps.apple.com/us/app/nostore/id1666553677) (Safari on iOS/MacOS)
39- [OneKey](https://onekey.so/) (Android, IOS, Chrome and derivatives)
diff --git a/09.md b/09.md
index f92410f..fbbd6e1 100644
--- a/09.md
+++ b/09.md
@@ -8,7 +8,7 @@ Event Deletion
8 8
9A special event with kind `5`, meaning "deletion" is defined as having a list of one or more `e` tags, each referencing an event the author is requesting to be deleted. 9A special event with kind `5`, meaning "deletion" is defined as having a list of one or more `e` tags, each referencing an event the author is requesting to be deleted.
10 10
11Each tag entry must contain an "e" event id and/or NIP-33 `a` tags intended for deletion. 11Each tag entry must contain an "e" event id and/or `a` tags intended for deletion.
12 12
13The event's `content` field MAY contain a text note describing the reason for the deletion. 13The event's `content` field MAY contain a text note describing the reason for the deletion.
14 14
diff --git a/10.md b/10.md
index 5b19fbd..a434ea0 100644
--- a/10.md
+++ b/10.md
@@ -33,7 +33,7 @@ Where:
33 33
34 * Many "e" tags: `["e", <root-id>]` `["e", <mention-id>]`, ..., `["e", <reply-id>]`<br> 34 * Many "e" tags: `["e", <root-id>]` `["e", <mention-id>]`, ..., `["e", <reply-id>]`<br>
35There may be any number of `<mention-ids>`. These are the ids of events which may, or may not be in the reply chain. 35There may be any number of `<mention-ids>`. These are the ids of events which may, or may not be in the reply chain.
36They are citings from this event. `root-id` and `reply-id` are as above. 36They are citing from this event. `root-id` and `reply-id` are as above.
37 37
38>This scheme is deprecated because it creates ambiguities that are difficult, or impossible to resolve when an event references another but is not a reply. 38>This scheme is deprecated because it creates ambiguities that are difficult, or impossible to resolve when an event references another but is not a reply.
39 39
diff --git a/11.md b/11.md
index ab05f31..45102d7 100644
--- a/11.md
+++ b/11.md
@@ -79,6 +79,7 @@ are rejected or fail immediately.
79 "min_pow_difficulty": 30, 79 "min_pow_difficulty": 30,
80 "auth_required": true, 80 "auth_required": true,
81 "payment_required": true, 81 "payment_required": true,
82 "restricted_writes": true,
82 "created_at_lower_limit": 31536000, 83 "created_at_lower_limit": 31536000,
83 "created_at_upper_limit": 3 84 "created_at_upper_limit": 3
84 }, 85 },
@@ -124,9 +125,15 @@ Even if set to False, authentication may be required for specific actions.
124 125
125- `payment_required`: this relay requires payment before a new connection may perform any action. 126- `payment_required`: this relay requires payment before a new connection may perform any action.
126 127
127- `created_at_lower_limit`: 'created_at' lower limit as defined in [NIP-22](22.md) 128- `restricted_writes`: this relay requires some kind of condition to be fulfilled in order to
129accept events (not necessarily, but including `payment_required` and `min_pow_difficulty`).
130This should only be set to `true` when users are expected to know the relay policy before trying
131to write to it -- like belonging to a special pubkey-based whitelist or writing only events of
132a specific niche kind or content. Normal anti-spam heuristics, for example, do not qualify.
128 133
129- `created_at_upper_limit`: 'created_at' upper limit as defined in [NIP-22](22.md) 134- `created_at_lower_limit`: 'created_at' lower limit
135
136- `created_at_upper_limit`: 'created_at' upper limit
130 137
131### Event Retention 138### Event Retention
132 139
diff --git a/15.md b/15.md
index 51b7792..1c3154a 100644
--- a/15.md
+++ b/15.md
@@ -108,7 +108,7 @@ Fields that are not self-explanatory:
108``` 108```
109 109
110Fields that are not self-explanatory: 110Fields that are not self-explanatory:
111 - `quantity` can be null in the case of items with unlimited abailability, like digital items, or services 111 - `quantity` can be null in the case of items with unlimited availability, like digital items, or services
112 - `specs`: 112 - `specs`:
113 - an optional array of key pair values. It allows for the Customer UI to present product specifications in a structure mode. It also allows comparison between products 113 - an optional array of key pair values. It allows for the Customer UI to present product specifications in a structure mode. It also allows comparison between products
114 - eg: `[["operating_system", "Android 12.0"], ["screen_size", "6.4 inches"], ["connector_type", "USB Type C"]]` 114 - eg: `[["operating_system", "Android 12.0"], ["screen_size", "6.4 inches"], ["connector_type", "USB Type C"]]`
diff --git a/22.md b/22.md
deleted file mode 100644
index 06af493..0000000
--- a/22.md
+++ /dev/null
@@ -1,45 +0,0 @@
1NIP-22
2======
3
4Event `created_at` Limits
5-------------------------
6
7`draft` `optional`
8
9Relays may define both upper and lower limits within which they will consider an event's `created_at` to be acceptable. Both the upper and lower limits MUST be unix timestamps in seconds as defined in [NIP-01](01.md).
10
11If a relay supports this NIP, the relay SHOULD send the client an `OK` result saying the event was not stored for the `created_at` timestamp not being within the permitted limits.
12
13Client Behavior
14---------------
15
16Clients SHOULD use the [NIP-11](11.md) `supported_nips` field to learn if a relay uses event `created_at` time limits as defined by this NIP.
17
18Motivation
19----------
20
21This NIP formalizes restrictions on event timestamps as accepted by a relay and allows clients to be aware of relays that have these restrictions.
22
23The event `created_at` field is just a unix timestamp and can be set to a time in the past or future. Relays accept and share events dated to 20 years ago or 50,000 years in the future. This NIP aims to define a way for relays that do not want to store events with *any* timestamp to set their own restrictions.
24
25_Replaceable events_ can behave rather unexpectedly if the user wrote them - or tried to write them - with a wrong system clock. Persisting an update with a backdated system now would result in the update not getting persisted without a notification and if they did the last update with a forward dated system, they will again fail to do another update with the now correct time.
26
27A wide adoption of this NIP could create a better user experience as it would decrease the amount of events that appear wildly out of order or even from impossible dates in the distant past or future.
28
29Keep in mind that there is a use case where a user migrates their old posts onto a new relay. If a relay rejects events that were not recently created, it cannot serve this use case.
30
31
32Python (pseudocode) Example
33---------------------------
34
35```python
36import time
37
38TIME = int(time.time())
39LOWER_LIMIT = TIME - (60 * 60 * 24) # Define lower limit as 1 day into the past
40UPPER_LIMIT = TIME + (60 * 15) # Define upper limit as 15 minutes into the future
41
42if event.created_at not in range(LOWER_LIMIT, UPPER_LIMIT):
43 ws.send('["OK", event.id, False, "invalid: the event created_at field is out of the acceptable range (-24h, +15min) for this relay"]')
44```
45Note: These are just example limits, the relay operator can choose whatever limits they want.
diff --git a/42.md b/42.md
index e380e89..8c70de4 100644
--- a/42.md
+++ b/42.md
@@ -12,32 +12,31 @@ This NIP defines a way for clients to authenticate to relays by signing an ephem
12 12
13A relay may want to require clients to authenticate to access restricted resources. For example, 13A relay may want to require clients to authenticate to access restricted resources. For example,
14 14
15 - A relay may request payment or other forms of whitelisting to publish events -- this can naïvely be achieved by limiting publication 15 - A relay may request payment or other forms of whitelisting to publish events -- this can naïvely be achieved by limiting publication to events signed by the whitelisted key, but with this NIP they may choose to accept any events as long as they are published from an authenticated user;
16 to events signed by the whitelisted key, but with this NIP they may choose to accept any events as long as they are published from an 16 - A relay may limit access to `kind: 4` DMs to only the parties involved in the chat exchange, and for that it may require authentication before clients can query for that kind.
17 authenticated user;
18 - A relay may limit access to `kind: 4` DMs to only the parties involved in the chat exchange, and for that it may require authentication
19 before clients can query for that kind.
20 - A relay may limit subscriptions of any kind to paying users or users whitelisted through any other means, and require authentication. 17 - A relay may limit subscriptions of any kind to paying users or users whitelisted through any other means, and require authentication.
21 18
22## Definitions 19## Definitions
23 20
24This NIP defines a new message, `AUTH`, which relays can send when they support authentication and clients can send to relays when they want 21### New client-relay protocol messages
25to authenticate. When sent by relays, the message is of the following form: 22
23This NIP defines a new message, `AUTH`, which relays CAN send when they support authentication and clients can send to relays when they want to authenticate. When sent by relays the message has the following form:
26 24
27```json 25```json
28["AUTH", <challenge-string>] 26["AUTH", <challenge-string>]
29``` 27```
30 28
31And, when sent by clients, of the following form: 29And, when sent by clients, the following form:
32 30
33```json 31```json
34["AUTH", <signed-event-json>] 32["AUTH", <signed-event-json>]
35``` 33```
36 34
37The signed event is an ephemeral event not meant to be published or queried, it must be of `kind: 22242` and it should have at least two tags, 35`AUTH` messages sent by clients MUST be answered with an `OK` message, like any `EVENT` message.
38one for the relay URL and one for the challenge string as received from the relay. 36
39Relays MUST exclude `kind: 22242` events from being broadcasted to any client. 37### Canonical authentication event
40`created_at` should be the current time. Example: 38
39The signed event is an ephemeral event not meant to be published or queried, it must be of `kind: 22242` and it should have at least two tags, one for the relay URL and one for the challenge string as received from the relay. Relays MUST exclude `kind: 22242` events from being broadcasted to any client. `created_at` should be the current time. Example:
41 40
42```json 41```json
43{ 42{
@@ -50,27 +49,49 @@ Relays MUST exclude `kind: 22242` events from being broadcasted to any client.
50} 49}
51``` 50```
52 51
52### `OK` and `CLOSED` machine-readable prefixes
53
54This NIP defines two new prefixes that can be used in `OK` (in response to event writes by clients) and `CLOSED` (in response to rejected subscriptions by clients):
55
56- `"auth-required: "` - for when a client has not performed `AUTH` and the relay requires that to fulfill the query or write the event.
57- `"restricted: "` - for when a client has already performed `AUTH` but the key used to perform it is still not allowed by the relay or is exceeding its authorization.
58
53## Protocol flow 59## Protocol flow
54 60
55At any moment the relay may send an `AUTH` message to the client containing a challenge. After receiving that the client may decide to 61At any moment the relay may send an `AUTH` message to the client containing a challenge. The challenge is valid for the duration of the connection or until another challenge is sent by the relay. The client MAY decide to send its `AUTH` event at any point and the authenticated session is valid afterwards for the duration of the connection.
56authenticate itself or not. The challenge is expected to be valid for the duration of the connection or until a next challenge is sent by
57the relay.
58 62
59The client may send an auth message right before performing an action for which it knows authentication will be required -- for example, right 63### `auth-required` in response to a `REQ` message
60before requesting `kind: 4` chat messages --, or it may do right on connection start or at some other moment it deems best. The authentication
61is expected to last for the duration of the WebSocket connection.
62 64
63Upon receiving a message from an unauthenticated user it can't fulfill without authentication, a relay may choose to notify the client. For 65Given that a relay is likely to require clients to perform authentication only for certain jobs, like answering a `REQ` or accepting an `EVENT` write, these are some expected common flows:
64that it can use a `NOTICE` or `OK` message with a standard prefix `"restricted: "` that is readable both by humans and machines, for example:
65 66
66```json 67```
67["NOTICE", "restricted: we can't serve DMs to unauthenticated users, does your client implement NIP-42?"] 68relay: ["AUTH", "<challenge>"]
69client: ["REQ", "sub_1", {"kinds": [4]}]
70relay: ["CLOSED", "sub_1", "auth-required: we can't serve DMs to unauthenticated users"]
71client: ["AUTH", {"id": "abcdef...", ...}]
72relay: ["OK", "abcdef...", true, ""]
73client: ["REQ", "sub_1", {"kinds": [4]}]
74relay: ["EVENT", "sub_1", {...}]
75relay: ["EVENT", "sub_1", {...}]
76relay: ["EVENT", "sub_1", {...}]
77relay: ["EVENT", "sub_1", {...}]
78...
68``` 79```
69 80
70or it can return an `OK` message noting the reason an event was not written using the same prefix: 81In this case, the `AUTH` message from the relay could be sent right as the client connects or it can be sent immediately before the `CLOSED` is sent. The only requirement is that _the client must have a stored challenge associated with that relay_ so it can act upon that in response to the `auth-required` `CLOSED` message.
71 82
72```json 83### `auth-required` in response to an `EVENT` message
73["OK", <event-id>, false, "restricted: we do not accept events from unauthenticated users, please sign up at https://example.com/"] 84
85The same flow is valid for when a client wants to write an `EVENT` to the relay, except now the relay sends back an `OK` message instead of a `CLOSED` message:
86
87```
88relay: ["AUTH", "<challenge>"]
89client: ["EVENT", {"id": "012345...", ...}]
90relay: ["OK", "012345...", false, "auth-required: we only accept events from registered users"]
91client: ["AUTH", {"id": "abcdef...", ...}]
92relay: ["OK", "abcdef...", true, ""]
93client: ["EVENT", {"id": "012345...", ...}]
94relay: ["OK", "012345...", true, ""]
74``` 95```
75 96
76## Signed Event Verification 97## Signed Event Verification
diff --git a/45.md b/45.md
index 998b952..780dfb6 100644
--- a/45.md
+++ b/45.md
@@ -27,7 +27,9 @@ In case a relay uses probabilistic counts, it MAY indicate it in the response wi
27["COUNT", <subscription_id>, {"count": <integer>}] 27["COUNT", <subscription_id>, {"count": <integer>}]
28``` 28```
29 29
30## Examples: 30Whenever the relay decides to refuse to fulfill the `COUNT` request, it MUST return a `CLOSED` message.
31
32## Examples
31 33
32### Followers count 34### Followers count
33 35
@@ -49,3 +51,10 @@ In case a relay uses probabilistic counts, it MAY indicate it in the response wi
49["COUNT", <subscription_id>, {"kinds": [1]}] 51["COUNT", <subscription_id>, {"kinds": [1]}]
50["COUNT", <subscription_id>, {"count": 93412452, "approximate": true}] 52["COUNT", <subscription_id>, {"count": 93412452, "approximate": true}]
51``` 53```
54
55### Relay refuses to count
56
57```
58["COUNT", <subscription_id>, {"kinds": [4], "authors": [<pubkey>], "#p": [<pubkey>]}]
59["CLOSED", <subscription_id>, "auth-required: cannot count other people's DMs"]
60```
diff --git a/47.md b/47.md
index d4b7c1f..c6540d5 100644
--- a/47.md
+++ b/47.md
@@ -129,7 +129,7 @@ Errors:
129## Example pay invoice flow 129## Example pay invoice flow
130 130
1310. The user scans the QR code generated by the **wallet service** with their **client** application, they follow a `nostr+walletconnect:` deeplink or configure the connection details manually. 1310. The user scans the QR code generated by the **wallet service** with their **client** application, they follow a `nostr+walletconnect:` deeplink or configure the connection details manually.
1321. **client** sends an event to the **wallet service** service with kind `23194`. The content is a `pay_invoice` request. The private key is the secret from the connection string above. 1321. **client** sends an event to the **wallet service** with kind `23194`. The content is a `pay_invoice` request. The private key is the secret from the connection string above.
1332. **wallet service** verifies that the author's key is authorized to perform the payment, decrypts the payload and sends the payment. 1332. **wallet service** verifies that the author's key is authorized to perform the payment, decrypts the payload and sends the payment.
1343. **wallet service** responds to the event by sending an event with kind `23195` and content being a response either containing an error message or a preimage. 1343. **wallet service** responds to the event by sending an event with kind `23195` and content being a response either containing an error message or a preimage.
135 135
diff --git a/51.md b/51.md
index a8a8e95..f5a9a74 100644
--- a/51.md
+++ b/51.md
@@ -6,148 +6,107 @@ Lists
6 6
7`draft` `optional` 7`draft` `optional`
8 8
9A "list" event is defined as having a list of public and/or private tags. Public tags will be listed in the event `tags`. Private tags will be encrypted in the event `content`. Encryption for private tags will use [NIP-04 - Encrypted Direct Message](04.md) encryption, using the list author's private and public key for the shared secret. A distinct event kind should be used for each list type created. 9This NIP defines lists of things that users can create. Lists can contain references to anything, and these references can be **public** or **private**.
10 10
11If a list should only be defined once per user (like the "mute" list) the list is declared as a _replaceable event_. These lists may be referred to as "replaceable lists". Otherwise, the list is a _parameterized replaceable event_ and the list name will be used as the `d` tag. These lists may be referred to as "parameterized replaceable lists". 11Public items in a list are specified in the event `tags` array, while private items are specified in a JSON array that mimics the structure of the event `tags` array, but stringified and encrypted using the same scheme from [NIP-04](04.md) (the shared key is computed using the author's public and private key) and stored in the `.content`.
12 12
13## Replaceable List Event Example 13## Types of lists
14 14
15Lets say a user wants to create a 'Mute' list and has keys: 15## Standard lists
16```
17priv: fb505c65d4df950f5d28c9e4d285ee12ffaf315deef1fc24e3c7cd1e7e35f2b1
18pub: b1a5c93edcc8d586566fde53a20bdb50049a97b15483cb763854e57016e0fa3d
19```
20The user wants to publicly include these users:
21 16
22```json 17Standard lists use non-parameterized replaceable events, meaning users may only have a single list of each kind. They have special meaning and clients may rely on them to augment a user's profile or browsing experience.
23["p", "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"],
24["p", "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245"]
25```
26and privately include these users (below is the JSON that would be encrypted and placed in the event content):
27 18
28```json 19For example, _mute lists_ can contain the public keys of spammers and bad actors users don't want to see in their feeds or receive annoying notifications from.
29[
30 ["p", "9ec7a778167afb1d30c4833de9322da0c08ba71a69e1911d5578d3144bb56437"],
31 ["p", "8c0da4862130283ff9e67d889df264177a508974e2feb96de139804ea66d6168"]
32]
33```
34 20
35Then the user would create a 'Mute' list event like below: 21| name | kind | description | expected tag items |
22| --- | --- | --- | --- |
23| Mute list | 10000 | things the user doesn't want to see in their feeds | `"p"` (pubkeys), `"t"` (hashtags), `"word"` (lowercase string), `"e"` (threads) |
24| Pinned notes | 10001 | events the user intends to showcase in their profile page | `"e"` (kind:1 notes) |
25| Bookmarks | 10003 | uncategorized, "global" list of things a user wants to save | `"e"` (kind:1 notes), `"a"` (kind:30023 articles), `"t"` (hashtags), `"r" (URLs)` |
26| Communities | 10004 | [NIP-72](72.md) communities the user belongs to | `"a"` (kind:34550 community definitions) |
27| Public chats | 10005 | [NIP-28](28.md) chat channels the user is in | `"e"` (kind:40 channel definitions) |
28| Blocked relays | 10006 | relays clients should never connect to | `"relay"` (relay URLs) |
29| Search relays | 10007 | relays clients should use when performing search queries | `"relay"` (relay URLs) |
30| Interests | 10015 | topics a user may be interested in and pointers | `"t"` (hashtags) and `"a" (kind:30015 interest set)` |
31| Emojis | 10030 | user preferred emojis and pointers to emoji sets | `"emoji"` (see [NIP-30](30.md)) and `"a"` (kind:30030 emoji set) |
36 32
37```json 33## Sets
38{
39 "kind": 10000,
40 "tags": [
41 ["p", "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"],
42 ["p", "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245"],
43 ],
44 "content": "VezuSvWak++ASjFMRqBPWS3mK5pZ0vRLL325iuIL4S+r8n9z+DuMau5vMElz1tGC/UqCDmbzE2kwplafaFo/FnIZMdEj4pdxgptyBV1ifZpH3TEF6OMjEtqbYRRqnxgIXsuOSXaerWgpi0pm+raHQPseoELQI/SZ1cvtFqEUCXdXpa5AYaSd+quEuthAEw7V1jP+5TDRCEC8jiLosBVhCtaPpLcrm8HydMYJ2XB6Ixs=?iv=/rtV49RFm0XyFEwG62Eo9A==",
45 ...other fields
46}
47```
48 34
35Sets are lists with well-defined meaning that can enhance the functionality and the UI of clients that rely on them. Unlike standard lists, users are expected to have more than one set of each kind, therefore each of them must be assigned a different `"d"` identifier.
49 36
50## Parameterized Replaceable List Event Example 37For example, _relay sets_ can be displayed in a dropdown UI to give users the option to switch to which relays they will publish an event or from which relays they will read the replies to an event; _curation sets_ can be used by apps to showcase curations made by others tagged to different topics.
51 38
52Lets say a user wants to create a 'Categorized People' list of `nostr` people and has keys: 39Aside from their main identifier, the `"d"` tag, sets can optionally have a `"title"`, an `"image"` and a `"description"` tags that can be used to enhance their UI.
53```
54priv: fb505c65d4df950f5d28c9e4d285ee12ffaf315deef1fc24e3c7cd1e7e35f2b1
55pub: b1a5c93edcc8d586566fde53a20bdb50049a97b15483cb763854e57016e0fa3d
56```
57The user wants to publicly include these users:
58 40
59```json 41| name | kind | description | expected tag items |
60["p", "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"], 42| --- | --- | --- | --- |
61["p", "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245"] 43| Follow sets | 30000 | categorized groups of users a client may choose to check out in different circumstances | `"p"` (pubkeys) |
62``` 44| Relay sets | 30002 | user-defined relay groups the user can easily pick and choose from during various operations | `"relay"` (relay URLs) |
63and privately include these users (below is the JSON that would be encrypted and placed in the event content): 45| Bookmark sets | 30003 | user-defined bookmarks categories , for when bookmarks must be in labeled separate groups | `"e"` (kind:1 notes), `"a"` (kind:30023 articles), `"t"` (hashtags), `"r" (URLs)` |
46| Curation sets | 30004 | groups of articles picked by users as interesting and/or belonging to the same category | `"a"` (kind:30023 articles), `"e"` (kind:1 notes) |
47| Interest sets | 30015 | interest topics represented by a bunch of "hashtags" | `"t"` (hashtags) |
48| Emoji sets | 30030 | categorized emoji groups | `"emoji"` (see [NIP-30](30.md)) |
64 49
65```json 50## Deprecated standard lists
66[ 51
67 ["p", "9ec7a778167afb1d30c4833de9322da0c08ba71a69e1911d5578d3144bb56437"], 52Some clients have used these lists in the past, but they should work on transitioning to the [standard formats](#standard-lists) above.
68 ["p", "8c0da4862130283ff9e67d889df264177a508974e2feb96de139804ea66d6168"] 53
69] 54| kind | "d" tag | use instead |
70``` 55| --- | --- | --- |
56| 30000 | `"mute"` | kind 10000 _mute list_ |
57| 30001 | `"pin"` | kind 10001 _pin list_ |
58| 30001 | `"bookmark"` | kind 10003 _bookmarks list_ |
59| 30001 | `"communities"` | kind 10004 _communities list_ |
60
61## Examples
71 62
72Then the user would create a 'Categorized People' list event like below: 63### A _mute list_ with some public items and some encrypted items
73 64
74```json 65```json
75{ 66{
76 "kind": 30000, 67 "id": "a92a316b75e44cfdc19986c634049158d4206fcc0b7b9c7ccbcdabe28beebcd0",
68 "pubkey": "854043ae8f1f97430ca8c1f1a090bdde6488bd5115c7a45307a2a212750ae4cb",
69 "created_at": 1699597889,
70 "kind": 10000,
77 "tags": [ 71 "tags": [
78 ["d", "nostr"], 72 ["p", "07caba282f76441955b695551c3c5c742e5b9202a3784780f8086fdcdc1da3a9"],
79 ["p", "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"], 73 ["p", "a55c15f5e41d5aebd236eca5e0142789c5385703f1a7485aa4b38d94fd18dcc4"]
80 ["p", "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245"],
81 ], 74 ],
82 "content": "VezuSvWak++ASjFMRqBPWS3mK5pZ0vRLL325iuIL4S+r8n9z+DuMau5vMElz1tGC/UqCDmbzE2kwplafaFo/FnIZMdEj4pdxgptyBV1ifZpH3TEF6OMjEtqbYRRqnxgIXsuOSXaerWgpi0pm+raHQPseoELQI/SZ1cvtFqEUCXdXpa5AYaSd+quEuthAEw7V1jP+5TDRCEC8jiLosBVhCtaPpLcrm8HydMYJ2XB6Ixs=?iv=/rtV49RFm0XyFEwG62Eo9A==", 75 "content": "TJob1dQrf2ndsmdbeGU+05HT5GMnBSx3fx8QdDY/g3NvCa7klfzgaQCmRZuo1d3WQjHDOjzSY1+MgTK5WjewFFumCcOZniWtOMSga9tJk1ky00tLoUUzyLnb1v9x95h/iT/KpkICJyAwUZ+LoJBUzLrK52wNTMt8M5jSLvCkRx8C0BmEwA/00pjOp4eRndy19H4WUUehhjfV2/VV/k4hMAjJ7Bb5Hp9xdmzmCLX9+64+MyeIQQjQAHPj8dkSsRahP7KS3MgMpjaF8nL48Bg5suZMxJayXGVp3BLtgRZx5z5nOk9xyrYk+71e2tnP9IDvSMkiSe76BcMct+m7kGVrRcavDI4n62goNNh25IpghT+a1OjjkpXt9me5wmaL7fxffV1pchdm+A7KJKIUU3kLC7QbUifF22EucRA9xiEyxETusNludBXN24O3llTbOy4vYFsq35BeZl4v1Cse7n2htZicVkItMz3wjzj1q1I1VqbnorNXFgllkRZn4/YXfTG/RMnoK/bDogRapOV+XToZ+IvsN0BqwKSUDx+ydKpci6htDRF2WDRkU+VQMqwM0CoLzy2H6A2cqyMMMD9SLRRzBg==?iv=S3rFeFr1gsYqmQA7bNnNTQ==",
83 ...other fields 76 "sig": "1173822c53261f8cffe7efbf43ba4a97a9198b3e402c2a1df130f42a8985a2d0d3430f4de350db184141e45ca844ab4e5364ea80f11d720e36357e1853dba6ca"
84} 77}
85``` 78```
86 79
87Lets say a user wants to create a 'Categorized Bookmarks' list of `bookmarks` and has keys: 80### A _curation set_ of articles and notes about yaks
88```
89priv: fb505c65d4df950f5d28c9e4d285ee12ffaf315deef1fc24e3c7cd1e7e35f2b1
90pub: b1a5c93edcc8d586566fde53a20bdb50049a97b15483cb763854e57016e0fa3d
91```
92The user wants to publicly include these bookmarks:
93
94```json
95["e", "5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36", "wss://nostr.example.com"],
96["a", "30023:f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca:abcd", "wss://nostr.example.com"],
97["r", "https://github.com/nostr-protocol/nostr", "Nostr repository"],
98```
99and privately include these bookmarks (below is the JSON that would be encrypted and placed in the event content):
100 81
101```json
102[
103 ["r", "https://my-private.bookmark", "My private bookmark"],
104 ["a", "30001:f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca:abcd", "wss://nostr.example.com"],
105]
106``` 82```
107
108Then the user would create a 'Categorized Bookmarks' list event like below:
109
110```json
111{ 83{
112 "kind": 30001, 84 "id": "567b41fc9060c758c4216fe5f8d3df7c57daad7ae757fa4606f0c39d4dd220ef",
85 "pubkey": "d6dc95542e18b8b7aec2f14610f55c335abebec76f3db9e58c254661d0593a0c",
86 "created_at": 1695327657,
87 "kind": 30004,
113 "tags": [ 88 "tags": [
114 ["d", "bookmarks"], 89 ["d", "jvdy9i4"],
115 ["e", "5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36", "wss://nostr.example.com"], 90 ["name", "Yaks"],
116 ["a", "30023:f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca:abcd", "wss://nostr.example.com"], 91 ["picture", "https://cdn.britannica.com/40/188540-050-9AC748DE/Yak-Himalayas-Nepal.jpg"],
117 ["r", "https://github.com/nostr-protocol/nostr", "Nostr repository"], 92 ["about", "The domestic yak, also known as the Tartary ox, grunting ox, or hairy cattle, is a species of long-haired domesticated cattle found throughout the Himalayan region of the Indian subcontinent, the Tibetan Plateau, Gilgit-Baltistan, Tajikistan and as far north as Mongolia and Siberia."],
93 ["a", "30023:26dc95542e18b8b7aec2f14610f55c335abebec76f3db9e58c254661d0593a0c:95ODQzw3ajNoZ8SyMDOzQ"],
94 ["a", "30023:54af95542e18b8b7aec2f14610f55c335abebec76f3db9e58c254661d0593a0c:1-MYP8dAhramH9J5gJWKx"],
95 ["a", "30023:f8fe95542e18b8b7aec2f14610f55c335abebec76f3db9e58c254661d0593a0c:D2Tbd38bGrFvU0bIbvSMt"],
96 ["e", "d78ba0d5dce22bfff9db0a9e996c9ef27e2c91051de0c4e1da340e0326b4941e"]
118 ], 97 ],
119 "content": "y3AyaLJfnmYr9x9Od9o4aYrmL9+Ynmsim5y2ONrU0urOTq+V81CyAthQ2mUOWE9xwGgrizhY7ILdQwWhy6FK0sA33GHtC0egUJw1zIdknPe7BZjznD570yk/8RXYgGyDKdexME+RMYykrnYFxq1+y/h00kmJg4u+Gpn+ZjmVhNYxl9b+TiBOAXG9UxnK/H0AmUqDpcldn6+j1/AiStwYZhD1UZ3jzDIk2qcCDy7MlGnYhSP+kNmG+2b0T/D1L0Z7?iv=PGJJfPE84gacAh7T0e6duQ==", 98 "content": "",
120 ...other fields 99 "sig": "a9a4e2192eede77e6c9d24ddfab95ba3ff7c03fbd07ad011fff245abea431fb4d3787c2d04aad001cb039cb8de91d83ce30e9a94f82ac3c5a2372aa1294a96bd"
121} 100}
122``` 101```
123 102
124## List Event Kinds 103## Encryption process pseudocode
125
126| kind | list type |
127| ------ | ----------------------- |
128| 10000 | Mute |
129| 10001 | Pin |
130| 30000 | Categorized People |
131| 30001 | Categorized Bookmarks |
132| 30002 | Categorized Relay Sets |
133 104
134 105```scala
135### Mute List 106val private_items = [
136 107 ["p", "07caba282f76441955b695551c3c5c742e5b9202a3784780f8086fdcdc1da3a9"],
137An event with kind `10000` is defined as a replaceable list event for listing content a user wants to mute. Any standardized tag can be included in a Mute List. 108 ["a", "a55c15f5e41d5aebd236eca5e0142789c5385703f1a7485aa4b38d94fd18dcc4"],
138 109]
139### Pin List 110val base64blob = nip04.encrypt(json.encode_to_string(private_items))
140 111event.content = base64blob
141An event with kind `10001` is defined as a replaceable list event for listing content a user wants to pin. Any standardized tag can be included in a Pin List. 112```
142
143### Categorized People List
144
145An event with kind `30000` is defined as a parameterized replaceable list event for categorizing people. The 'd' parameter for this event holds the category name of the list. The tags included in these lists MUST follow the format of kind 3 events as defined in [NIP-02 - Contact List and Petnames](02.md).
146
147### Categorized Bookmarks List
148
149An event of kind `30001` is defined as a parameterized replaceable list event for categorizing bookmarks. The 'd' parameter for this event holds the category name of the list. The bookmark lists may contain metadata tags such as 'title', 'image', 'summary' as defined in [NIP-23 - Long-form Content](23.md). Any standardized tag can be included in a Categorized Bookmark List.
150
151### Categorized Relay Set
152
153An event of kind `30002` is defined as a parameterized replaceable list event for categorizing relays. The 'd' parameter for this event holds the category name of the list. The relays lists may contain metadata tags such as 'title', 'image', 'summary' as defined in [NIP-23 - Long-form Content](23.md). These sets can be used by clients in order to determine which relays to query in different scenarios.
diff --git a/53.md b/53.md
index d3cc0af..e17f965 100644
--- a/53.md
+++ b/53.md
@@ -6,7 +6,7 @@ Live Activities
6 6
7`draft` `optional` 7`draft` `optional`
8 8
9Service providers want to offer live activities to the Nostr network in such a way that participants can easily logged and queried by clients. This NIP describes a general framework to advertise the involvement of pubkeys in such live activities. 9Service providers want to offer live activities to the Nostr network in such a way that participants can easily log and query by clients. This NIP describes a general framework to advertise the involvement of pubkeys in such live activities.
10 10
11## Concepts 11## Concepts
12 12
diff --git a/57.md b/57.md
index 2b2c97b..759e203 100644
--- a/57.md
+++ b/57.md
@@ -36,7 +36,7 @@ A `zap request` is an event of kind `9734` that is _not_ published to relays, bu
36In addition, the event MAY include the following tags: 36In addition, the event MAY include the following tags:
37 37
38- `e` is an optional hex-encoded event id. Clients MUST include this if zapping an event rather than a person. 38- `e` is an optional hex-encoded event id. Clients MUST include this if zapping an event rather than a person.
39- `a` is an optional NIP-33 event coordinate that allows tipping parameterized replaceable events such as NIP-23 long-form notes. 39- `a` is an optional event coordinate that allows tipping parameterized replaceable events such as NIP-23 long-form notes.
40 40
41Example: 41Example:
42 42
@@ -110,7 +110,7 @@ When a client sends a `zap request` event to a server's lnurl-pay callback URL,
1104. It MUST have 0 or 1 `e` tags 1104. It MUST have 0 or 1 `e` tags
1115. There should be a `relays` tag with the relays to send the `zap receipt` to. 1115. There should be a `relays` tag with the relays to send the `zap receipt` to.
1126. If there is an `amount` tag, it MUST be equal to the `amount` query parameter. 1126. If there is an `amount` tag, it MUST be equal to the `amount` query parameter.
1137. If there is an `a` tag, it MUST be a valid NIP-33 event coordinate 1137. If there is an `a` tag, it MUST be a valid event coordinate
114 114
115The event MUST then be stored for use later, when the invoice is paid. 115The event MUST then be stored for use later, when the invoice is paid.
116 116
diff --git a/58.md b/58.md
index 9725c82..e2a9f20 100644
--- a/58.md
+++ b/58.md
@@ -62,8 +62,6 @@ Users MAY choose to decorate their profiles with badges for fame, notoriety, rec
62 62
63### Recommendations 63### Recommendations
64 64
65Badge issuers MAY include some Proof of Work as per [NIP-13](13.md) when minting Badge Definitions or Badge Awards to embed them with a combined energy cost, arguably making them more special and valuable for users that wish to collect them.
66
67Clients MAY whitelist badge issuers (pubkeys) for the purpose of ensuring they retain a valuable/special factor for their users. 65Clients MAY whitelist badge issuers (pubkeys) for the purpose of ensuring they retain a valuable/special factor for their users.
68 66
69Badge image recommended aspect ratio is 1:1 with a high-res size of 1024x1024 pixels. 67Badge image recommended aspect ratio is 1:1 with a high-res size of 1024x1024 pixels.
diff --git a/75.md b/75.md
index f3cf5d0..c16436a 100644
--- a/75.md
+++ b/75.md
@@ -35,6 +35,8 @@ Example event:
35The following tags are OPTIONAL. 35The following tags are OPTIONAL.
36 36
37- `closed_at` - timestamp for determining which zaps are included in the tally. Zap receipts published after the `closed_at` timestamp SHOULD NOT count towards the goal progress. 37- `closed_at` - timestamp for determining which zaps are included in the tally. Zap receipts published after the `closed_at` timestamp SHOULD NOT count towards the goal progress.
38- `image` - an image for the goal
39- `summary` - a brief description
38 40
39```json 41```json
40{ 42{
@@ -43,6 +45,8 @@ The following tags are OPTIONAL.
43 ["relays", "wss://alicerelay.example.com", "wss://bobrelay.example.com", ...], 45 ["relays", "wss://alicerelay.example.com", "wss://bobrelay.example.com", ...],
44 ["amount", "210000"], 46 ["amount", "210000"],
45 ["closed_at", "<unix timestamp in seconds>"], 47 ["closed_at", "<unix timestamp in seconds>"],
48 ["image", "<image URL>"],
49 ["summary", "<description of the goal>"],
46 ], 50 ],
47 "content": "Nostrasia travel expenses", 51 "content": "Nostrasia travel expenses",
48 ... 52 ...
diff --git a/89.md b/89.md
index be3d075..43d197f 100644
--- a/89.md
+++ b/89.md
@@ -65,7 +65,7 @@ The third value of the tag SHOULD be the platform where this recommendation migh
65 65
66* `content` is an optional `metadata`-like stringified JSON object, as described in NIP-01. This content is useful when the pubkey creating the `kind:31990` is not an application. If `content` is empty, the `kind:0` of the pubkey should be used to display application information (e.g. name, picture, web, LUD16, etc.) 66* `content` is an optional `metadata`-like stringified JSON object, as described in NIP-01. This content is useful when the pubkey creating the `kind:31990` is not an application. If `content` is empty, the `kind:0` of the pubkey should be used to display application information (e.g. name, picture, web, LUD16, etc.)
67* `k` tags' value is the event kind that is supported by this `kind:31990`. 67* `k` tags' value is the event kind that is supported by this `kind:31990`.
68Using a `k` tag(s) (instead of having the kind onf the NIP-33 `d` tag) provides: 68Using a `k` tag(s) (instead of having the kind of the `d` tag) provides:
69 * Multiple `k` tags can exist in the same event if the application supports more than one event kind and their handler URLs are the same. 69 * Multiple `k` tags can exist in the same event if the application supports more than one event kind and their handler URLs are the same.
70 * The same pubkey can have multiple events with different apps that handle the same event kind. 70 * The same pubkey can have multiple events with different apps that handle the same event kind.
71* `bech32` in a URL MUST be replaced by clients with the NIP-19-encoded entity that should be loaded by the application. 71* `bech32` in a URL MUST be replaced by clients with the NIP-19-encoded entity that should be loaded by the application.
@@ -74,14 +74,14 @@ Multiple tags might be registered by the app, following NIP-19 nomenclature as t
74 74
75A tag without a second value in the array SHOULD be considered a generic handler for any NIP-19 entity that is not handled by a different tag. 75A tag without a second value in the array SHOULD be considered a generic handler for any NIP-19 entity that is not handled by a different tag.
76 76
77## Client tag 77# Client tag
78When publishing events, clients MAY include a `client` tag in the same format as the recommendation event's `a` tags. This has privacy implications for users, so clients SHOULD allow users to opt-out of using this tag. 78When publishing events, clients MAY include a `client` tag. Identifying the client that published the note. This tag is a tuple of `name`, `address` identifying a handler event and, a relay `hint` for finding the handler event. This has privacy implications for users, so clients SHOULD allow users to opt-out of using this tag.
79 79
80```json 80```json
81{ 81{
82 "kind": 1, 82 "kind": 1,
83 "tags": [ 83 "tags": [
84 ["client", "31990:app1-pubkey:<d-identifier>", "wss://relay1", "ios"] 84 ["client", "My Client", "31990:app1-pubkey:<d-identifier>", "wss://relay1"]
85 ] 85 ]
86 ... 86 ...
87} 87}
diff --git a/90.md b/90.md
index 6017c98..241eb38 100644
--- a/90.md
+++ b/90.md
@@ -34,7 +34,7 @@ There are two actors in the workflow described in this NIP:
34* Service providers (npubs who fulfill jobs) 34* Service providers (npubs who fulfill jobs)
35 35
36## Job request (`kind:5000-5999`) 36## Job request (`kind:5000-5999`)
37A request to process data, published by a customer. This event signals that an customer is interested in receiving the result of some kind of compute. 37A request to process data, published by a customer. This event signals that a customer is interested in receiving the result of some kind of compute.
38 38
39```json 39```json
40{ 40{
diff --git a/README.md b/README.md
index 8e970ea..6b83490 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
22## List 22## List
23 23
24- [NIP-01: Basic protocol flow description](01.md) 24- [NIP-01: Basic protocol flow description](01.md)
25- [NIP-02: Contact List and Petnames](02.md) 25- [NIP-02: Follow List](02.md)
26- [NIP-03: OpenTimestamps Attestations for Events](03.md) 26- [NIP-03: OpenTimestamps Attestations for Events](03.md)
27- [NIP-04: Encrypted Direct Message](04.md) 27- [NIP-04: Encrypted Direct Message](04.md)
28- [NIP-05: Mapping Nostr keys to DNS-based internet identifiers](05.md) 28- [NIP-05: Mapping Nostr keys to DNS-based internet identifiers](05.md)
@@ -38,7 +38,6 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
38- [NIP-18: Reposts](18.md) 38- [NIP-18: Reposts](18.md)
39- [NIP-19: bech32-encoded entities](19.md) 39- [NIP-19: bech32-encoded entities](19.md)
40- [NIP-21: `nostr:` URI scheme](21.md) 40- [NIP-21: `nostr:` URI scheme](21.md)
41- [NIP-22: Event `created_at` Limits](22.md)
42- [NIP-23: Long-form Content](23.md) 41- [NIP-23: Long-form Content](23.md)
43- [NIP-24: Extra metadata fields and tags](24.md) 42- [NIP-24: Extra metadata fields and tags](24.md)
44- [NIP-25: Reactions](25.md) 43- [NIP-25: Reactions](25.md)
@@ -76,66 +75,82 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
76- [NIP-99: Classified Listings](99.md) 75- [NIP-99: Classified Listings](99.md)
77 76
78## Event Kinds 77## Event Kinds
79| kind | description | NIP | 78| kind | description | NIP |
80| ------------- | -------------------------- | ----------- | 79| ------------- | -------------------------- | ----------- |
81| `0` | Metadata | [1](01.md) | 80| `0` | Metadata | [1](01.md) |
82| `1` | Short Text Note | [1](01.md) | 81| `1` | Short Text Note | [1](01.md) |
83| `2` | Recommend Relay | | 82| `2` | Recommend Relay | |
84| `3` | Contacts | [2](02.md) | 83| `3` | Follows | [2](02.md) |
85| `4` | Encrypted Direct Messages | [4](04.md) | 84| `4` | Encrypted Direct Messages | [4](04.md) |
86| `5` | Event Deletion | [9](09.md) | 85| `5` | Event Deletion | [9](09.md) |
87| `6` | Repost | [18](18.md) | 86| `6` | Repost | [18](18.md) |
88| `7` | Reaction | [25](25.md) | 87| `7` | Reaction | [25](25.md) |
89| `8` | Badge Award | [58](58.md) | 88| `8` | Badge Award | [58](58.md) |
90| `16` | Generic Repost | [18](18.md) | 89| `16` | Generic Repost | [18](18.md) |
91| `40` | Channel Creation | [28](28.md) | 90| `40` | Channel Creation | [28](28.md) |
92| `41` | Channel Metadata | [28](28.md) | 91| `41` | Channel Metadata | [28](28.md) |
93| `42` | Channel Message | [28](28.md) | 92| `42` | Channel Message | [28](28.md) |
94| `43` | Channel Hide Message | [28](28.md) | 93| `43` | Channel Hide Message | [28](28.md) |
95| `44` | Channel Mute User | [28](28.md) | 94| `44` | Channel Mute User | [28](28.md) |
96| `1063` | File Metadata | [94](94.md) | 95| `1040` | OpenTimestamps | [03](03.md) |
97| `1311` | Live Chat Message | [53](53.md) | 96| `1063` | File Metadata | [94](94.md) |
98| `1040` | OpenTimestamps | [03](03.md) | 97| `1311` | Live Chat Message | [53](53.md) |
99| `1971` | Problem Tracker | [1971](https://github.com/nostrocket/NIPS/blob/main/Problems.md) | 98| `1971` | Problem Tracker | [nostrocket][nostrocket] |
100| `1984` | Reporting | [56](56.md) | 99| `1984` | Reporting | [56](56.md) |
101| `1985` | Label | [32](32.md) | 100| `1985` | Label | [32](32.md) |
102| `4550` | Community Post Approval | [72](72.md) | 101| `4550` | Community Post Approval | [72](72.md) |
103| `5000`-`5999` | Job Request | [90](90.md) | 102| `5000`-`5999` | Job Request | [90](90.md) |
104| `6000`-`6999` | Job Result | [90](90.md) | 103| `6000`-`6999` | Job Result | [90](90.md) |
105| `7000` | Job Feedback | [90](90.md) | 104| `7000` | Job Feedback | [90](90.md) |
106| `9041` | Zap Goal | [75](75.md) | 105| `9041` | Zap Goal | [75](75.md) |
107| `9734` | Zap Request | [57](57.md) | 106| `9734` | Zap Request | [57](57.md) |
108| `9735` | Zap | [57](57.md) | 107| `9735` | Zap | [57](57.md) |
109| `9802` | Highlights | [84](84.md) | 108| `9802` | Highlights | [84](84.md) |
110| `10000` | Mute List | [51](51.md) | 109| `10000` | Mute list | [51](51.md) |
111| `10001` | Pin List | [51](51.md) | 110| `10001` | Pin list | [51](51.md) |
112| `10002` | Relay List Metadata | [65](65.md) | 111| `10002` | Relay List Metadata | [65](65.md) |
113| `13194` | Wallet Info | [47](47.md) | 112| `10003` | Bookmark list | [51](51.md) |
114| `22242` | Client Authentication | [42](42.md) | 113| `10004` | Communities list | [51](51.md) |
115| `23194` | Wallet Request | [47](47.md) | 114| `10005` | Public chats list | [51](51.md) |
116| `23195` | Wallet Response | [47](47.md) | 115| `10006` | Blocked relays list | [51](51.md) |
117| `24133` | Nostr Connect | [46](46.md) | 116| `10007` | Search relays list | [51](51.md) |
118| `27235` | HTTP Auth | [98](98.md) | 117| `10015` | Interests list | [51](51.md) |
119| `30000` | Categorized People List | [51](51.md) | 118| `10030` | User emoji list | [51](51.md) |
120| `30001` | Categorized Bookmark List | [51](51.md) | 119| `13194` | Wallet Info | [47](47.md) |
121| `30008` | Profile Badges | [58](58.md) | 120| `21000` | Lightning Pub RPC | [Lightning.Pub][lnpub] |
122| `30009` | Badge Definition | [58](58.md) | 121| `22242` | Client Authentication | [42](42.md) |
123| `30017` | Create or update a stall | [15](15.md) | 122| `23194` | Wallet Request | [47](47.md) |
124| `30018` | Create or update a product | [15](15.md) | 123| `23195` | Wallet Response | [47](47.md) |
125| `30023` | Long-form Content | [23](23.md) | 124| `24133` | Nostr Connect | [46](46.md) |
126| `30024` | Draft Long-form Content | [23](23.md) | 125| `27235` | HTTP Auth | [98](98.md) |
127| `30078` | Application-specific Data | [78](78.md) | 126| `30000` | Follow sets | [51](51.md) |
128| `30311` | Live Event | [53](53.md) | 127| `30001` | Generic lists | [51](51.md) |
129| `30315` | User Statuses | [38](38.md) | 128| `30002` | Relay sets | [51](51.md) |
130| `30402` | Classified Listing | [99](99.md) | 129| `30003` | Bookmark sets | [51](51.md) |
131| `30403` | Draft Classified Listing | [99](99.md) | 130| `30004` | Curation sets | [51](51.md) |
132| `31922` | Date-Based Calendar Event | [52](52.md) | 131| `30008` | Profile Badges | [58](58.md) |
133| `31923` | Time-Based Calendar Event | [52](52.md) | 132| `30009` | Badge Definition | [58](58.md) |
134| `31924` | Calendar | [52](52.md) | 133| `30015` | Interest sets | [51](51.md) |
135| `31925` | Calendar Event RSVP | [52](52.md) | 134| `30017` | Create or update a stall | [15](15.md) |
136| `31989` | Handler recommendation | [89](89.md) | 135| `30018` | Create or update a product | [15](15.md) |
137| `31990` | Handler information | [89](89.md) | 136| `30023` | Long-form Content | [23](23.md) |
138| `34550` | Community Definition | [72](72.md) | 137| `30024` | Draft Long-form Content | [23](23.md) |
138| `30030` | Emoji sets | [51](51.md) |
139| `30078` | Application-specific Data | [78](78.md) |
140| `30311` | Live Event | [53](53.md) |
141| `30315` | User Statuses | [38](38.md) |
142| `30402` | Classified Listing | [99](99.md) |
143| `30403` | Draft Classified Listing | [99](99.md) |
144| `31922` | Date-Based Calendar Event | [52](52.md) |
145| `31923` | Time-Based Calendar Event | [52](52.md) |
146| `31924` | Calendar | [52](52.md) |
147| `31925` | Calendar Event RSVP | [52](52.md) |
148| `31989` | Handler recommendation | [89](89.md) |
149| `31990` | Handler information | [89](89.md) |
150| `34550` | Community Definition | [72](72.md) |
151
152[nostrocket]: https://github.com/nostrocket/NIPS/blob/main/Problems.md
153[lnpub]: https://github.com/shocknet/Lightning.Pub/blob/master/proto/autogenerated/client.md
139 154
140## Message types 155## Message types
141 156
@@ -157,6 +172,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
157| `EVENT` | used to send events requested to clients | [01](01.md) | 172| `EVENT` | used to send events requested to clients | [01](01.md) |
158| `NOTICE` | used to send human-readable messages to clients | [01](01.md) | 173| `NOTICE` | used to send human-readable messages to clients | [01](01.md) |
159| `OK` | used to notify clients if an EVENT was successful | [01](01.md) | 174| `OK` | used to notify clients if an EVENT was successful | [01](01.md) |
175| `CLOSED` | used to notify clients that a REQ was ended and why | [01](01.md) |
160| `AUTH` | used to send authentication challenges | [42](42.md) | 176| `AUTH` | used to send authentication challenges | [42](42.md) |
161| `COUNT` | used to send requested event counts to clients | [45](45.md) | 177| `COUNT` | used to send requested event counts to clients | [45](45.md) |
162 178
@@ -170,7 +186,6 @@ Please update these lists when proposing NIPs introducing new event kinds.
170| `p` | pubkey (hex) | relay URL, petname | [01](01.md), [02](02.md) | 186| `p` | pubkey (hex) | relay URL, petname | [01](01.md), [02](02.md) |
171| `a` | coordinates to an event | relay URL | [01](01.md) | 187| `a` | coordinates to an event | relay URL | [01](01.md) |
172| `d` | identifier | -- | [01](01.md) | 188| `d` | identifier | -- | [01](01.md) |
173| `alt` | summary | -- | [31](31.md) |
174| `g` | geohash | -- | [52](52.md) | 189| `g` | geohash | -- | [52](52.md) |
175| `i` | identity | proof | [39](39.md) | 190| `i` | identity | proof | [39](39.md) |
176| `k` | kind number (string) | -- | [18](18.md), [25](25.md), [72](72.md) | 191| `k` | kind number (string) | -- | [18](18.md), [25](25.md), [72](72.md) |
@@ -180,13 +195,16 @@ Please update these lists when proposing NIPs introducing new event kinds.
180| `r` | a reference (URL, etc) | petname | | 195| `r` | a reference (URL, etc) | petname | |
181| `r` | relay url | marker | [65](65.md) | 196| `r` | relay url | marker | [65](65.md) |
182| `t` | hashtag | -- | | 197| `t` | hashtag | -- | |
198| `alt` | summary | -- | [31](31.md) |
183| `amount` | millisatoshis, stringified | -- | [57](57.md) | 199| `amount` | millisatoshis, stringified | -- | [57](57.md) |
184| `bolt11` | `bolt11` invoice | -- | [57](57.md) | 200| `bolt11` | `bolt11` invoice | -- | [57](57.md) |
185| `challenge` | challenge string | -- | [42](42.md) | 201| `challenge` | challenge string | -- | [42](42.md) |
202| `client` | name, address | relay URL | [89](89.md) |
186| `content-warning` | reason | -- | [36](36.md) | 203| `content-warning` | reason | -- | [36](36.md) |
187| `delegation` | pubkey, conditions, delegation token | -- | [26](26.md) | 204| `delegation` | pubkey, conditions, delegation token | -- | [26](26.md) |
188| `description` | invoice/badge description | -- | [57](57.md), [58](58.md) | 205| `description` | invoice/badge description | -- | [57](57.md), [58](58.md) |
189| `emoji` | shortcode, image URL | -- | [30](30.md) | 206| `emoji` | shortcode, image URL | -- | [30](30.md) |
207| `encrypted` | -- | -- | [90](90.md) |
190| `expiration` | unix timestamp (string) | -- | [40](40.md) | 208| `expiration` | unix timestamp (string) | -- | [40](40.md) |
191| `goal` | event id (hex) | relay URL | [75](75.md) | 209| `goal` | event id (hex) | relay URL | [75](75.md) |
192| `image` | image URL | dimensions in pixels | [23](23.md), [58](58.md) | 210| `image` | image URL | dimensions in pixels | [23](23.md), [58](58.md) |