Compare commits

..

1 Commits

Author SHA1 Message Date
fiatjaf
6b56a0b206 nip31: template-based "alt" tags for known kinds. 2025-03-05 13:35:43 -03:00
6 changed files with 63 additions and 249 deletions

14
17.md
View File

@@ -57,7 +57,7 @@ Kind `14`s MUST never be signed. If it is signed, the message might leak to rela
["file-type", "<file-mime-type>"],
["encryption-algorithm", "<encryption-algorithm>"],
["decryption-key", "<decryption-key>"],
["decryption-nonce", "<decryption-nonce>"],
["decryptiion-nonce", "<decryption-nonce>"],
["x", "<the SHA-256 hexencoded string of the file>"],
// rest of tags...
],
@@ -74,16 +74,16 @@ Kind 15 is used for sending encrypted file event messages:
- `content`: The URL of the file (`<file-url>`).
- `x` containing the SHA-256 hexencoded string of the file.
- `size` (optional) size of file in bytes
- `dim` (optional) size of the file in pixels in the form `<width>x<height>`
- `blurhash`(optional) the [blurhash](https://github.com/woltapp/blurhash) to show while the client is loading the file
- `thumb` (optional) URL of thumbnail with same aspect ratio (encrypted with the same key, nonce)
- `dim` (optional) size of file in pixels in the form `<width>x<height>`
- `blurhash`(optional) the [blurhash](https://github.com/woltapp/blurhash) to show while the file is being loaded by the client
- `thumb` (optional) url of thumbnail with same aspect ratio
- `fallback` (optional) zero or more fallback file sources in case `url` fails
Just like kind 14, kind `15`s MUST never be signed.
## Chat Rooms
The set of `pubkey` + `p` tags defines a chat room. If a new `p` tag is added or a current one is removed, a new room is created with a clean message history.
The set of `pubkey` + `p` tags defines a chat room. If a new `p` tag is added or a current one is removed, a new room is created with clean message history.
Clients SHOULD render messages of the same room in a continuous thread.
@@ -91,7 +91,7 @@ An optional `subject` tag defines the current name/topic of the conversation. An
## Encrypting
Following [NIP-59](59.md), the **unsigned** `kind:14` & `kind:15` chat messages must be sealed (`kind:13`) and then gift-wrapped (`kind:1059`) to each receiver and the sender individually.
Following [NIP-59](59.md), the **unsigned** `kind:14` & `kind:15` chat message must be sealed (`kind:13`) and then gift-wrapped (`kind:1059`) to each receiver and the sender individually.
```jsonc
{
@@ -173,7 +173,7 @@ The main limitation of this approach is having to send a separate encrypted even
Clients implementing this NIP should by default only connect to the set of relays found in their `kind:10050` list. From that they should be able to load all messages both sent and received as well as get new live updates, making it for a very simple and lightweight implementation that should be fast.
When sending a message to anyone, clients must then connect to the relays in the receiver's `kind:10050` and send the events there but can disconnect right after unless more messages are expected to be sent (e.g. the chat tab is still selected). Clients should also send a copy of their outgoing messages to their own `kind:10050` relay set.
When sending a message to anyone, clients must then connect to the relays in the receiver's `kind:10050` and send the events there, but can disconnect right after unless more messages are expected to be sent (e.g. the chat tab is still selected). Clients should also send a copy of their outgoing messages to their own `kind:10050` relay set.
## Examples

4
23.md
View File

@@ -60,7 +60,3 @@ References to other Nostr notes, articles or profiles must be made according to
"id": "..."
}
```
### Replies & Comments
Replies to `kind 30023` MUST use [NIP-22](./22.md) `kind 1111` comments.

41
31.md
View File

@@ -6,10 +6,43 @@ Dealing with unknown event kinds
`draft` `optional`
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.
When faced with an event of an unknown or unsupported kind, clients still have to display _something_ to the user.
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.
Besides indicating that the event kind is not supported and suggesting other clients to handle it (possibly using [NIP-89](89.md)) clients may try these two alternatives:
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.
1. Display text generated from a hardcoded or dynamic template;
2. Display the value of the event's `alt` tag;
`kind:1`-centric clients can make interacting with these event kinds more functional by supporting [NIP-89](89.md).
(Of course if both are unavailable then the client has to decide on something else, like displaying a generic error message or the raw JSON contents or something else.)
### Templates
Templates can be either hardcoded by application developers or downloaded at runtime (or downloaded at compile-time) from a trusted provider or from a library, anything.
They consist of a [Mustache](https://mustache.github.io/)-compatible template (with no loops or partials) that takes the following parameters:
- `kind`
- `created_at`
- `pubkey`
- `content`
- `tags`
In which each of these values corresponds to the attribute of the event with the same name, except for `tags`, which is treated as an object with key-value access given by the first two items of each tag (and in the case of multiple tags with the same key only one, presumably the first, should be used).
**For example,**
- a reasonable template for a `kind:1111` event (comment) would be: `{{content}}`
- a reasonable template for a `kind:14` event (direct message) would be: `encrypted message to {{tags.p}}`
- a reasonable template for a `kind:7` event (reaction) would be: `{{pubkey}} reacts to {{tags.e}} by {{tags.p}}{{#content}} with {{.}}{{/content}}`
- a reasonable template for a `kind:30617` event (repository announcement) would be: `git repository {{tags.name}}{{#tags.web}}hosted at {{.}}{{/tags.web}} by {{pubkey}}`
- a reasonable template for a `kind:10002` event (relay list) would be: `canonical relays list for {{pubkey}}`
- a reasonable template for a `kind:31922` event (calendar) would be: `{{tags.title}} happening at {{tags.start}}`
To be easily exchangeable and reusable, trusted providers that want to do it SHOULD serve these templates through HTTP at `https://<domain-name>/.well-known/nip31/<kind-number>`, returning just the raw text.
Clients MAY format `{{pubkey}}` into a clickable `nostr:npub1...` link, or print `created_at` as a human-friendly date instead of as a timestamp, or anything like that.
### `alt` tags
When creating a new custom event kind that is part of a custom protocol and isn't meant to be read as text, clients SHOULD write an `alt` tag to include a short human-readable plaintext summary of what that event is about.
This is recommended for a while, until clients and providers have been given enough time to update their templates, then clients should stop doing it.

37
73.md
View File

@@ -9,37 +9,26 @@ External Content IDs
There are certain established global content identifiers such as [Book ISBNs](https://en.wikipedia.org/wiki/ISBN), [Podcast GUIDs](https://podcastnamespace.org/tag/guid), and [Movie ISANs](https://en.wikipedia.org/wiki/International_Standard_Audiovisual_Number) that are useful to reference in nostr events so that clients can query all the events assosiated with these ids.
`i` tags are used for referencing these external content ids, with `k` tags representing the external content id kind so that clients can query all the events for a specific kind.
`i` tags are used for referencing these external content ids, with `k` tags representing the external content id kind so that clients can query all the events for a specific kind.
## Supported IDs
| Type | `i` tag | `k` tag |
| --- | --- | --- |
| URLs | "`<URL, normalized, no fragment>`" | "web" |
| Hashtags | "#`<topic, lowercase>`" | "#" |
| Geohashes | "geo:`<geohash, lowercase>`" | "geo" |
| Books | "isbn:`<id, without hyphens>`" | "isbn" |
| Podcast Feeds | "podcast:guid:`<guid>`" | "podcast:guid" |
| Podcast Episodes | "podcast:item:guid:`<guid>`" | "podcast:item:guid" |
| Podcast Publishers | "podcast:publisher:guid:`<guid>`" | "podcast:publisher:guid" |
| Movies | "isan:`<id, without version part>`" | "isan" |
| Papers | "doi:`<id, lowercase>`" | "doi" |
| Type | `i` tag | `k` tag |
|- | - | - |
| URLs | "`<URL, normalized, no fragment>`" | "`<scheme-host, normalized>`" |
| Hashtags | "#`<topic, lowercase>`" | "#" |
| Geohashes| "geo:`<geohash, lowercase>`" | "geo" |
| Books | "isbn:`<id, without hyphens>`" | "isbn" |
| Podcast Feeds | "podcast:guid:`<guid>`" | "podcast:guid" |
| Podcast Episodes | "podcast:item:guid:`<guid>`" | "podcast:item:guid" |
| Podcast Publishers | "podcast:publisher:guid:`<guid>`" | "podcast:publisher:guid" |
| Movies | "isan:`<id, without version part>`" | "isan" |
| Papers | "doi:`<id, lowercase>`" | "doi" |
---
## Examples
### Webpages
For the webpage "https://myblog.example.com/post/2012-03-27/hello-world" the "i" and "k" tags are:
```jsonc
[
["i","https://myblog.example.com/post/2012-03-27/hello-world"],
["k", "web"]
]
```
### Books:
- Book ISBN: `["i", "isbn:9780765382030"]` - https://isbnsearch.org/isbn/9780765382030
@@ -67,3 +56,5 @@ Each `i` tag MAY have a url hint as the second argument to redirect people to a
`["i", "podcast:item:guid:d98d189b-dc7b-45b1-8720-d4b98690f31f", https://fountain.fm/episode/z1y9TMQRuqXl2awyrQxg]`
`["i", "isan:0000-0000-401A-0000-7", https://www.imdb.com/title/tt0120737]`

201
83.md
View File

@@ -1,201 +0,0 @@
# NIP-83: Stories
`draft` `optional`
This NIP defines a standard for "stories" content.
## Abstract
Stories allow users to share, usually time-limited, visual content that can be enhanced with interactive elements called "stickers".
## Specification
### Event Structure
Stories are represented as events with kind `23`.
### Tags
- `dim`: MUST be present, this is the story canvas in the format `["dim", "<width>x<height>"]`, which defines the coordinate system for all stickers and elements.
- `imeta` tags as defined in NIP-92.
- `dur` duration of the story in seconds.
#### Sticker Tags
Stickers are interactive elements placed on the story. They use the format:
```
["sticker", "<type>", "value", "<x>,<y>", "<width>x<height>", "key1 value1", "key2 value2", ...]
```
Where:
- `<type>`: The sticker type (see below)
- `<value>`: The main value of the sticker.
- `<x>,<y>`: Position coordinates relative to the story canvas
- `<width>x<height>`: Dimensions of the sticker
- Additional key-value pairs with the key and value combined in a single element, separated by a space, like `imeta` tags.
##### Sticker Types
- `pubkey`: Mentions a user. Requires a `p` tag with the same index.
- `event`: Embeds a Nostr event. Requires an `e` tag with the same index.
- `prompt`: Requests user input with optional placeholder text.
- `text`: Renders text on the story. The text content is specified using a `"text <value>"` property.
- `countdown`: Displays a countdown timer to a specific Unix timestamp. The value should be a valid Unix timestamp in seconds.
### Styling Properties
Stickers can have additional properties:
- `style`: A named style identifier. Clients are encouraged to mimic common style implementations from other clients.
- `rot`: Rotation in degrees (0-360).
Additional properties may be defined by clients, with common practices expected to emerge over time.
## Design Considerations
This NIP intentionally avoids highly specific styling mechanisms (like CSS) to ensure compatibility across different platforms, device types, and technologies. Instead, it provides foundational positioning and sizing with named styles that clients can interpret according to their capabilities.
## Examples
A basic story with an image and a text sticker:
```json
{
"kind": 23,
"content": "",
"tags": [
["dim", "1080x1920"],
[
"imeta",
"url",
"https://example.com/image.jpg",
"m",
"image/jpeg",
"blurhash",
"UBL_:rOpGG-;0g9FD%IA4oIpELxu"
],
[
"sticker",
"text",
"Hello Nostr!",
"540,960",
"600x200",
"style emphasis",
"rot 5"
]
]
}
```
A story with a user mention:
```json
{
"kind": 23,
"content": "",
"tags": [
["dim", "1080x1920"],
["expiration", "<timestampp>"],
["imeta", "url", "https://example.com/image.jpg", "m", "image/jpeg"],
["p", "fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52"],
[
"sticker",
"pubkey",
"fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52",
"540,960",
"300x300",
"style flou"
],
[
"a",
"30023:6260f29fa75c91aaa292f082e5e87b438d2ab4fdf96af398567b01802ee2fcd4:7b734cf9"
],
[
"sticker",
"event",
"30023:6260f29fa75c91aaa292f082e5e87b438d2ab4fdf96af398567b01802ee2fcd4:7b734cf9",
"540,960",
"300x300",
"style flou"
]
]
}
```
A story with a countdown timer:
```json
{
"kind": 23,
"content": "",
"tags": [
["expiration", "<timestamp>"],
["dim", "1080x1920"],
["imeta", "url", "https://example.com/event-image.jpg", "m", "image/jpeg"],
[
"sticker",
"countdown",
"1718486400",
"540,800",
"400x150",
"style emphasis",
"text Event starts in"
]
]
}
```
## Client Behavior
Clients SHOULD respect the coordinate system defined by the `dim` tag. When displaying stories on screens with different aspect ratios, clients SHOULD maintain the relative positioning of all elements.
## Implementation Notes
- Stories are ephemeral by nature. Clients MAY choose to display stories for a limited time (typically 24 hours).
- For consistent rendering across platforms, measurements and coordinates SHOULD be treated as logical units rather than specific pixel values.
- Clients SHOULD make reasonable attempts to reproduce named styles consistently with other implementations.
## A note about `style`
Stickers use a very ambiguous `style` with just a name. Clients can interpret what the name represents in their users screens freely, but clients should strive for consistency and sane defaults. Styles can emerge in the wild and clients are
encouraged to work on supporting what their users want.
The reason to avoid providing precise definitions and styling attributes is because recoinciling different platforms, native, web would end up yielding something as complicated as CSS which would be an overkill and, just like CSS has shown, an ever-shifting goal post.
## Appendix 1: Sticker Type Examples
### Mentions
```
["sticker", "pubkey", "fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52", "540,960", "300x300", "style default"]
```
### Event
An event to be embedded. Addressable events should use the `<kind>:<pubkey>:<d-tag>` format.
Additionally, event stickers should include the corresponding `a` and/or `e` tag to help find the event (relay hint, etc.).
```
["sticker", "event", "1a5f6849cef16334e1a73f289d457d54833769731c0631a39ca9631a6575e91d", "200,500", "400x200", "style card"]
```
### Ask for a reply
```
["sticker", "prompt", "Ask me a question", "540,1200", "600x100", "style rounded"]
```
### Embed text
```
["sticker", "text", "Hello world!", "540,960", "500x150", "style bold", "rot 15"]
```
### Timer countdown
```
["sticker", "countdown", "1718486400", "540,700", "400x100", "text Event starts in"]
```

View File

@@ -127,10 +127,6 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
| `20` | Picture | [68](68.md) |
| `21` | Video Event | [71](71.md) |
| `22` | Short-form Portrait Video Event | [71](71.md) |
| `30` | internal reference | [NKBIP-03] |
| `31` | external web reference | [NKBIP-03] |
| `32` | hardcopy reference | [NKBIP-03] |
| `33` | prompt reference | [NKBIP-03] |
| `40` | Channel Creation | [28](28.md) |
| `41` | Channel Metadata | [28](28.md) |
| `42` | Channel Message | [28](28.md) |
@@ -217,8 +213,8 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
| `30023` | Long-form Content | [23](23.md) |
| `30024` | Draft Long-form Content | [23](23.md) |
| `30030` | Emoji sets | [51](51.md) |
| `30040` | Curated Publication Index | [NKBIP-01] |
| `30041` | Curated Publication Content | [NKBIP-01] |
| `30040` | Modular Article Header | [NKBIP-01] |
| `30041` | Modular Article Content | [NKBIP-01] |
| `30063` | Release artifact sets | [51](51.md) |
| `30078` | Application-specific Data | [78](78.md) |
| `30166` | Relay Discovery | [66](66.md) |
@@ -252,9 +248,8 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
[cornychat-slideset]: https://cornychat.com/datatypes#kind30388slideset
[cornychat-linkset]: https://cornychat.com/datatypes#kind31388linkset
[joinstr]: https://gitlab.com/1440000bytes/joinstr/-/blob/main/NIP.md
[NKBIP-01]: https://wikistr.com/nkbip-01*fd208ee8c8f283780a9552896e4823cc9dc6bfd442063889577106940fd927c1
[NKBIP-02]: https://wikistr.com/nkbip-02*fd208ee8c8f283780a9552896e4823cc9dc6bfd442063889577106940fd927c1
[NKBIP-03]: https://wikistr.com/nkbip-03*fd208ee8c8f283780a9552896e4823cc9dc6bfd442063889577106940fd927c1
[NKBIP-01]: https://wikistr.com/nkbip-01
[NKBIP-02]: https://wikistr.com/nkbip-02
[blossom]: https://github.com/hzrd149/blossom
[Tidal-nostr]: https://wikistr.com/tidal-nostr
@@ -384,4 +379,4 @@ All NIPs are public domain.
<a align="center" href="https://github.com/nostr-protocol/nips/graphs/contributors">
<img src="https://contrib.rocks/image?repo=nostr-protocol/nips" />
</a>
</a>