NIP-89 ====== Recommended Application Handlers -------------------------------- `draft` `optional` 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 `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 of the `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. # Client tag When 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. ```json { "kind": 1, "tags": [ ["client", "My Client", "31990:app1-pubkey:", "wss://relay1"] ] ... } ``` ## 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`: ```json ["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 or querying high-quality restricted relays to avoid directing users to malicious handlers. ```json ["REQ", , '[{ "kinds": [31990], "#k": [], 'authors': [...] }]'] ``` ## Feature Support Signaling In order to facilitate deprecations of protocol features on nostr, a consensus must be reached _before_ support for old features is removed. New features might also benefit from a voting mechanism. Applications may signal their support of a protocol update using a `kind 36341` event with a `d` tag pointing to a url detailing the change, an `a` tag pointing to a `kind 31990` handler, and a `fork` tag. `content` MAY be an explanation of the deprecation support. Valid `fork` values are: - `hard` - the application fully supports all relevant new features, and has dropped support for deprecated features. - `soft` - the application fully supports all relevant new features, but has not dropped support for deprecations. - `none` - the application does not support new features, or relies on deprecated features. - `never` - the application does not intend to adopt the new standard. In order to be valid, this event MUST be published by the same key that published the referenced handler. ```json { "kind": 36341, "content": "I read and write relays to both kind 3 and kind 10002.", "tags": [ ["d", "https://github.com/nostrability/nostrability/issues/10"], ["a", "31990:1743058db7078661b94aaf4286429d97ee5257d14a86d6bfa54cb0482b876fb0:abcd", ""], ["fork", "soft"] ], } ```