From b8aec7dad561a8b27e22a91638dd04f2851a0c5c Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Fri, 5 May 2023 09:18:02 -0300 Subject: [PATCH 01/14] nip-31: dealing with custom unknown events. --- 31.md | 13 +++++++++++++ README.md | 1 + 2 files changed, 14 insertions(+) create mode 100644 31.md diff --git a/31.md b/31.md new file mode 100644 index 00000000..675c2496 --- /dev/null +++ b/31.md @@ -0,0 +1,13 @@ +NIP-31 +====== + +Dealing with unknown event kinds +-------------------------------- + +`draft` `optional` `author:pablof7z` `author:fiatjaf` + +When creating a new custom event kind that is part of a custom protocol and isn't meant to be read as text (like `kind:1`), clients should use the `tags` field to store all their custom data related to their protocol, and use the `content` field to write a short human-readable plaintext summary of what that event is about. + +The intent is that social clients, used to display only `kind:1` notes, can still show something in case a custom event pops up in their timelines. + +These clients that only know `kind:1` are not expected to ask relays for events of different kinds, but users could still reference these weird events on their notes, and without proper context these could be nonsensical notes. Having the fallback text makes that situation much better -- even if only for making the user aware that they should try to view that custom event elsewhere. diff --git a/README.md b/README.md index a4a63a4a..f3ae5016 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/fia - [NIP-26: Delegated Event Signing](26.md) - [NIP-27: Text Note References](27.md) - [NIP-28: Public Chat](28.md) +- [NIP-31: Dealing with Unknown Events](31.md) - [NIP-33: Parameterized Replaceable Events](33.md) - [NIP-36: Sensitive Content](36.md) - [NIP-39: External Identities in Profiles](39.md) From a56d1c2877e5c40640350fe0b21748642258baaf Mon Sep 17 00:00:00 2001 From: Asai Toshiya Date: Fri, 26 May 2023 17:28:10 +0900 Subject: [PATCH 02/14] =?UTF-8?q?Add=20description=20for=20d=C2=A0tag=20va?= =?UTF-8?q?lue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 33.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/33.md b/33.md index 10681fac..c93c36e7 100644 --- a/33.md +++ b/33.md @@ -10,7 +10,7 @@ This NIP adds a new event range that allows for replacement of events that have Implementation -------------- -The value of a tag is defined as the first parameter of a tag after the tag name. +The value of a tag can be any string and is defined as the first parameter of a tag after the tag name. A *parameterized replaceable event* is defined as an event with a kind `30000 <= n < 40000`. Upon a parameterized replaceable event with a newer timestamp than the currently known latest From 4f04de2afda831ef339ad225e4e08a5b1d075e3c Mon Sep 17 00:00:00 2001 From: Akiomi Kamakura Date: Sat, 27 May 2023 08:44:19 +0900 Subject: [PATCH 03/14] Update 07.md --- 07.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/07.md b/07.md index 71123663..a0b5bdc1 100644 --- a/07.md +++ b/07.md @@ -26,7 +26,7 @@ async window.nostr.nip04.decrypt(pubkey, ciphertext): string // takes ciphertext - [horse](https://github.com/fiatjaf/horse) (Chrome and derivatives) - [nos2x](https://github.com/fiatjaf/nos2x) (Chrome and derivatives) -- [Alby](https://getalby.com) (Chrome and derivatives, Firefox, Safari) +- [Alby](https://getalby.com) (Chrome and derivatives, Firefox) - [Blockcore](https://www.blockcore.net/wallet) (Chrome and derivatives) - [nos2x-fox](https://diegogurpegui.com/nos2x-fox/) (Firefox) - [Flamingo](https://www.getflamingo.org/) (Chrome and derivatives) From b12c93c452814ffa5f06aef95b60775bc86eaf58 Mon Sep 17 00:00:00 2001 From: Jose Mateo Date: Sun, 28 May 2023 05:58:48 -0400 Subject: [PATCH 04/14] Fix nip-57 typo --- 57.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/57.md b/57.md index cb1f126c..438a0f87 100644 --- a/57.md +++ b/57.md @@ -168,7 +168,7 @@ A client can retrieve `zap receipt`s on events and pubkeys using a NIP-01 filter ### Appendix G: `zap` tag on zapped event -When an event includes a `zap` tag, clients SHOULD calculate the lnurl pay request based on it's value instead of the profile's field. An optional third argument on the tag specifies the type of value, either `lud06` or `lud16`. +When an event includes a `zap` tag, clients SHOULD calculate the lnurl pay request based on its value instead of the profile's field. An optional third argument on the tag specifies the type of value, either `lud06` or `lud16`. ```json { From 3a38583c068369f55249429ebefe6b09f3a243d5 Mon Sep 17 00:00:00 2001 From: Asai Toshiya Date: Wed, 31 May 2023 12:35:51 +0900 Subject: [PATCH 05/14] Fix link to NIP-10 --- 01.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/01.md b/01.md index e36f4f5d..33a10e70 100644 --- a/01.md +++ b/01.md @@ -107,6 +107,6 @@ A relay may choose to treat different message kinds differently, and it may or m ## Other Notes: - Clients should not open more than one websocket to each relay. One channel can support an unlimited number of subscriptions, so clients should do that. -- The `tags` array can store a tag identifier as the first element of each subarray, plus arbitrary information afterward (always as strings). This NIP defines `"p"` — meaning "pubkey", which points to a pubkey of someone that is referred to in the event —, and `"e"` — meaning "event", which points to the id of an event this event is quoting, replying to or referring to somehow. See [NIP-10](https://github.com/nostr-protocol/nips/blob/127d5518bfa9a4e4e7510490c0b8d95e342dfa4b/10.md) for a detailed description of "e" and "p" tags. +- The `tags` array can store a tag identifier as the first element of each subarray, plus arbitrary information afterward (always as strings). This NIP defines `"p"` — meaning "pubkey", which points to a pubkey of someone that is referred to in the event —, and `"e"` — meaning "event", which points to the id of an event this event is quoting, replying to or referring to somehow. See [NIP-10](10.md) for a detailed description of "e" and "p" tags. - The `` item present on the `"e"` and `"p"` tags is an optional (could be set to `""`) URL of a relay the client could attempt to connect to fetch the tagged event or other events from a tagged profile. It MAY be ignored, but it exists to increase censorship resistance and make the spread of relay addresses more seamless across clients. - Clients should use the created_at field to judge the age of a metadata event and completely replace older metadata events with newer metadata events regardless of the order in which they arrive. Clients should not merge any filled fields within older metadata events into empty fields of newer metadata events. From cabbaadb69ecf28c2a91ced63359e1bd15b14ea9 Mon Sep 17 00:00:00 2001 From: haorendashu <385321165@qq.com> Date: Mon, 29 May 2023 15:47:09 +0800 Subject: [PATCH 06/14] Update 07.md Implementation --- 07.md | 1 + 1 file changed, 1 insertion(+) diff --git a/07.md b/07.md index a0b5bdc1..ee4e3722 100644 --- a/07.md +++ b/07.md @@ -32,3 +32,4 @@ async window.nostr.nip04.decrypt(pubkey, ciphertext): string // takes ciphertext - [Flamingo](https://www.getflamingo.org/) (Chrome and derivatives) - [AKA Profiles](https://github.com/neilck/aka-extension) (Chrome, stores multiple keys) - [TokenPocket](https://www.tokenpocket.pro/) (Android, IOS, Chrome and derivatives) +- [Nostrmo](https://github.com/haorendashu/nostrmo_faq#download) (Android, IOS) From fe9ed69dc3aec54ae437ca09a6d61aa2ce175577 Mon Sep 17 00:00:00 2001 From: Doug Hoyte Date: Fri, 19 May 2023 00:54:44 -0400 Subject: [PATCH 07/14] Specify replacement behaviour when replaceable events have the same timestamp - This is so that relays can converge on a deterministic sets of events, no matter the order they were received - Otherwise, clients or relays that sync their sets of events could continually retransmit events they think are missing on the other side, wasting bandwidth --- 16.md | 2 ++ 33.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/16.md b/16.md index 4d9481d4..8ef4af4d 100644 --- a/16.md +++ b/16.md @@ -20,6 +20,8 @@ Upon a replaceable event with a newer timestamp than the currently known latest effectively replacing what gets returned when querying for `author:kind` tuples. +If two events have the same timestamp, the event with the lowest id (first in lexical order) SHOULD be retained, and the other discarded. + Ephemeral Events ---------------- An *ephemeral event* is defined as an event with a kind `20000 <= n < 30000`. diff --git a/33.md b/33.md index c93c36e7..5128bece 100644 --- a/33.md +++ b/33.md @@ -18,6 +18,8 @@ replaceable event with the same kind, author and first `d` tag value being recei SHOULD be discarded, effectively replacing what gets returned when querying for `author:kind:d-tag` tuples. +If two events have the same timestamp, the event with the lowest id (first in lexical order) SHOULD be retained, and the other discarded. + A missing or a `d` tag with no value should be interpreted equivalent to a `d` tag with the value as an empty string. Events from the same author with any of the following `tags` replace each other: From 867c8bb334b0d9bb22a6af5c16ce6d186852af5a Mon Sep 17 00:00:00 2001 From: Pablo Fernandez Date: Wed, 7 Jun 2023 21:56:17 +0200 Subject: [PATCH 08/14] NIP-89: Recommended Application Handlers (#530) --- 89.md | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 89.md diff --git a/89.md b/89.md new file mode 100644 index 00000000..5eee3b8e --- /dev/null +++ b/89.md @@ -0,0 +1,116 @@ +NIP-89 +====== + +Recommended Application Handlers +-------------------------------- + +`draft` `optional` `author:pablof7z` + +This NIP describes `kind:31989` and `kind:31990`: a way to discover applications that can handle unknown event-kinds. + +## Rationale +Nostr's discoverability and transparent event interaction is one of its most interesting/novel mechanics. +This NIP provides a simple way for clients to discover applications that handle events of a specific kind to ensure smooth cross-client and cross-kind interactions. + +### Parties involved +There are three actors to this workflow: + +* application that handles a specific event kind (note that an application doesn't necessarily need to be a distinct entity and it could just be the same pubkey as user A) + * Publishes `kind:31990`, detailing how apps should redirect to it +* user A, who recommends an app that handles a specific event kind + * Publishes `kind:31989` +* user B, who seeks a recommendation for an app that handles a specific event kind + * Queries for `kind:31989` and, based on results, queries for `kind:31990` + +# Events + +## Recommendation event +```json +{ + "kind": 31989, + "pubkey": , + "tags": [ + [ "d", ], + [ "a", "31990:app1-pubkey:", "wss://relay1", "ios" ], + [ "a", "31990:app2-pubkey:", "wss://relay2", "web" ] + ] +} +``` + +The `d` tag in `kind:31989` is the supported event kind this event is recommending. + +Multiple `a` tags can appear on the same `kind:31989`. + +The second value of the tag SHOULD be a relay hint. +The third value of the tag SHOULD be the platform where this recommendation might apply. + +## Handler information +```json +{ + "kind": 31990, + "pubkey": , + "content": "", + "tags": [ + [ "d", ], + [ "k", ], + [ "web", "https://..../a/", "nevent" ], + [ "web", "https://..../p/", "nprofile" ], + [ "web", "https://..../e/" ], + [ "ios", ".../" ] + ] +} +``` + +* `content` is an optional `set_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.) + +* `k` tags' value is the event kind that is supported by this `kind:31990`. +Using a `k` tag(s) (instead of having the kind onf the NIP-33 `d` tag) provides: + * 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. + * The same pubkey can have multiple events with different apps that handle the same event kind. + +* `bech32` in a URL MUST be replaced by clients with the NIP-19-encoded entity that should be loaded by the application. + +Multiple tags might be registered by the app, following NIP-19 nomenclature as the second value of the array. + +A 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. + +# User flow +A user A who uses a non-`kind:1`-centric nostr app could choose to announce/recommend a certain kind-handler application. + +When user B sees an unknown event kind, e.g. in a social-media centric nostr client, the client would allow user B to interact with the unknown-kind event (e.g. tapping on it). + +The client MIGHT query for the user's and the user's follows handler. + +# Example + +## User A recommends a `kind:31337`-handler +User A might be a user of Zapstr, a `kind:31337`-centric client (tracks). Using Zapstr, user A publishes an event recommending Zapstr as a `kind:31337`-handler. + +```json +{ + "kind": 31989, + "tags": [ + [ "d", "31337" ], + [ "a", "31990:1743058db7078661b94aaf4286429d97ee5257d14a86d6bfa54cb0482b876fb0:abcd", , "web" ] + ] +} +``` + +## User B interacts with a `kind:31337`-handler +User B might see in their timeline an event referring to a `kind:31337` event +(e.g. a `kind:1` tagging a `kind:31337`). + +User B's client, not knowing how to handle a `kind:31337` might display the event +using its `alt` tag (as described in NIP-31). When the user clicks on the event, +the application queries for a handler for this `kind`: + +`["REQ", , '[{ "kinds": [31989], "#d": ["31337"], 'authors': [, ] }]']` + +User B, who follows User A, sees that `kind:31989` event and fetches the `a`-tagged event for the app and handler information. + +User B's client sees the application's `kind:31990` which includes the information to redirect the user to the relevant URL with the desired entity replaced in the URL. + +## Alternative query bypassing `kind:31989` +Alternatively, users might choose to query directly for `kind:31990` for an event kind. Clients SHOULD be careful doing this and use spam-prevention mechanisms to avoid directing users to malicious handlers. + +`["REQ", , '[{ "kinds": [31990], "#k": [], 'authors': [...] }]']` \ No newline at end of file From c78856d281658ba5c795b5295418692aa2827d2e Mon Sep 17 00:00:00 2001 From: pablof7z Date: Wed, 7 Jun 2023 23:19:56 +0200 Subject: [PATCH 09/14] update readme with NIP-89 --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 963fd791..fbe43f9e 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos - [NIP-58: Badges](58.md) - [NIP-65: Relay List Metadata](65.md) - [NIP-78: Application-specific data](78.md) +- [NIP-89: Recommended Application Handlers](89.md) - [NIP-94: File Metadata](94.md) ## Event Kinds @@ -101,6 +102,8 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos | `30018` | Create or update a product | [15](15.md) | | `30023` | Long-form Content | [23](23.md) | | `30078` | Application-specific Data | [78](78.md) | +| `31989` | Handler recommendation | [89](89.md) | +| `31990` | Handler information | [89](89.md) | ### Event Kind Ranges From 0d962cbe74018c64cd040c6c756ed94b648eef4b Mon Sep 17 00:00:00 2001 From: Asai Toshiya Date: Thu, 8 Jun 2023 12:15:37 +0900 Subject: [PATCH 10/14] Minor JSON fix --- 09.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/09.md b/09.md index 89781fbf..a73e0ab1 100644 --- a/09.md +++ b/09.md @@ -20,7 +20,7 @@ For example: "pubkey": <32-bytes hex-encoded public key of the event creator>, "tags": [ ["e", "dcd59..464a2"], - ["e", "968c5..ad7a4"], + ["e", "968c5..ad7a4"] ], "content": "these posts were published by accident", ...other fields From 964bc5b5ce946ab66aae945084549f26ffdef70f Mon Sep 17 00:00:00 2001 From: pablof7z Date: Thu, 8 Jun 2023 22:27:00 +0200 Subject: [PATCH 11/14] update NIP to use alt tag --- 31.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/31.md b/31.md index 675c2496..e77ae341 100644 --- a/31.md +++ b/31.md @@ -6,8 +6,10 @@ Dealing with unknown event kinds `draft` `optional` `author:pablof7z` `author:fiatjaf` -When creating a new custom event kind that is part of a custom protocol and isn't meant to be read as text (like `kind:1`), clients should use the `tags` field to store all their custom data related to their protocol, and use the `content` field to write a short human-readable plaintext summary of what that event is about. +When creating a new custom event kind that is part of a custom protocol and isn't meant to be read as text (like `kind:1`), clients should use an `alt` tag to write a short human-readable plaintext summary of what that event is about. -The intent is that social clients, used to display only `kind:1` notes, can still show something in case a custom event pops up in their timelines. +The intent is that social clients, used to display only `kind:1` notes, can still show something in case a custom event pops up in their timelines. The content of the `alt` tag should provide enough context for a user that doesn't know anything about this event kind to understand what it is. These clients that only know `kind:1` are not expected to ask relays for events of different kinds, but users could still reference these weird events on their notes, and without proper context these could be nonsensical notes. Having the fallback text makes that situation much better -- even if only for making the user aware that they should try to view that custom event elsewhere. + +`kind:1`-centric clients can make interacting with these event kinds more functional by supporting [NIP-89](https://github.com/nostr-protocol/nips/blob/master/89.md). From d435ffc39cacf485662cea5c98aaa4af5af3b447 Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Fri, 9 Jun 2023 14:13:42 -0300 Subject: [PATCH 12/14] clarify kind:1 plaintextness. --- 01.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/01.md b/01.md index 33a10e70..717e58af 100644 --- a/01.md +++ b/01.md @@ -99,7 +99,7 @@ This NIP defines no rules for how `NOTICE` messages should be sent or treated. ## Basic Event Kinds - `0`: `set_metadata`: the `content` is set to a stringified JSON object `{name: , about: , picture: }` describing the user who created the event. A relay may delete past `set_metadata` events once it gets a new one for the same pubkey. - - `1`: `text_note`: the `content` is set to the plaintext content of a note (anything the user wants to say). Do not use Markdown! Clients should not have to guess how to interpret content like `[]()`. Use different event kinds for parsable content. + - `1`: `text_note`: the `content` is set to the **plaintext** content of a note (anything the user wants to say). Content that must be parsed, such as Markdown and HTML, should not be used. - `2`: `recommend_server`: the `content` is set to the URL (e.g., `wss://somerelay.com`) of a relay the event creator wants to recommend to its followers. A relay may choose to treat different message kinds differently, and it may or may not choose to have a default way to handle kinds it doesn't know about. From 3e03b4b67f3421c8b7604426a7217422cdd013ff Mon Sep 17 00:00:00 2001 From: Seth For Privacy Date: Fri, 9 Jun 2023 11:19:23 -0400 Subject: [PATCH 13/14] Add context for limiting `before` timestamp --- 26.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/26.md b/26.md index b8fa9028..91176991 100644 --- a/26.md +++ b/26.md @@ -52,7 +52,9 @@ For example, the following condition strings are valid: - `kind=0&kind=1&created_at>1675721813` - `kind=1&created_at>1674777689&created_at<1675721813` -For the vast majority of use-cases, it is advisable that query strings should include a `created_at` ***after*** condition reflecting the current time, to prevent the delegatee from publishing historic notes on the delegator's behalf. +For the vast majority of use-cases, it is advisable that: +1. Query strings should include a `created_at` ***after*** condition reflecting the current time, to prevent the delegatee from publishing historic notes on the delegator's behalf. +2. Query strings should include a `created_at` ***before*** condition that is not empty and is not some extremely distant time in the future. If delegations are not limited in time scope, they expose similar security risks to simply using the root key for authentication. #### Example @@ -105,4 +107,4 @@ Clients should display the delegated note as if it was published directly by the Relays should answer requests such as `["REQ", "", {"authors": ["A"]}]` by querying both the `pubkey` and delegation tags `[1]` value. -Relays SHOULD allow the delegator (8e0d3d3e) to delete the events published by the delegatee (477318cf). \ No newline at end of file +Relays SHOULD allow the delegator (8e0d3d3e) to delete the events published by the delegatee (477318cf). From 2e842b496a740f89ad80bf8257c37535d538ba54 Mon Sep 17 00:00:00 2001 From: Asai Toshiya Date: Sat, 10 Jun 2023 17:52:25 +0900 Subject: [PATCH 14/14] Add description for clients to kind 1 --- 01.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/01.md b/01.md index 717e58af..2700dab1 100644 --- a/01.md +++ b/01.md @@ -99,7 +99,7 @@ This NIP defines no rules for how `NOTICE` messages should be sent or treated. ## Basic Event Kinds - `0`: `set_metadata`: the `content` is set to a stringified JSON object `{name: , about: , picture: }` describing the user who created the event. A relay may delete past `set_metadata` events once it gets a new one for the same pubkey. - - `1`: `text_note`: the `content` is set to the **plaintext** content of a note (anything the user wants to say). Content that must be parsed, such as Markdown and HTML, should not be used. + - `1`: `text_note`: the `content` is set to the **plaintext** content of a note (anything the user wants to say). Content that must be parsed, such as Markdown and HTML, should not be used. Clients should also not parse content as those. - `2`: `recommend_server`: the `content` is set to the URL (e.g., `wss://somerelay.com`) of a relay the event creator wants to recommend to its followers. A relay may choose to treat different message kinds differently, and it may or may not choose to have a default way to handle kinds it doesn't know about.