This commit is contained in:
hodlbod 2024-12-11 11:58:38 +01:00 committed by GitHub
commit d8e29d3fd0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 124 additions and 0 deletions

120
97.md Normal file
View File

@ -0,0 +1,120 @@
NIP-97
======
Seen Status
-----------
`draft` `optional`
Clients may wish to track whether certain events have been seen by a user, including mentions,
replies, likes, messages, community posts, and more. Keeping a single timestamp for each category
can result in events being missed if they are not fetched successfully on the first attempt.
Meanwhile, tagging every event seen is wasteful and can result in a lot of events being published
and downloaded just to maintain a notification badge.
This NIP combines both approaches, tracking categories of things a user might want to "check" by
both timestamp and event id. This results in small event payloads, only a few replaceable events,
and granular seen status for recent events.
Seen status events SHOULD have one or more `seen` tags associating a timestamp and zero or more
event ids with a key. The timestamp SHOULD be a time in the recent past, and all known events
created after that time for the given category should be represented in the id list.
The status key can be any string, but recommendations are made below. The special key `*` MAY be
used to indicate a timestamp for all keys not listed explicitly. This can be useful for ignoring
very old activity.
All tags MUST be encrypted using [NIP 44](./44.md) and placed in the seen status event's `content`
field to prevent leaking conversation metadata.
A few event kinds are defined here to separate broad categories and prevent tag lists from filling
up too quickly.
## Account-level notifications
Kind `10115` tracks account-level notifications, for example reactions, reposts, new followers, etc.
Kind `10115` SHOULD use the following keys as applicable, but MAY use other keys as needed:
- `reactions` - reactions to the user's notes
- `reposts` - reposts of the user's notes
- `zaps` - zaps tagging the user
- `mentions` - other notes tagging the user that aren't replies
- `replies` - replies to user notes
- `follows` - new followers of the current user
- `unfollows` - lost followers of the current user
- `mutes` - new mutes of the current user
- `unmutes` - new mutes of the current user
```json
{
"kind": "10115",
"created_at": 1722372950,
"content": nip44_encrypt_json([
["seen", "mentions", "1722372950", "<event1_id>", "<event2_id>"],
["seen", "replies", "1722372950", "<event1_id>"]
]),
}
```
## Context-level notifications
Kind `10116` tracks context-level notifications, including posts sent to groups or communities.
Kind `10116` SHOULD use the following key types:
- The address of a NIP 72 community for tracking posts to that community
- The address of a NIP 89 closed group for tracking posts to that group
- The id of a NIP 29 group for tracking posts to that group
```json
{
"kind": "10116",
"created_at": 1722372950,
"content": nip44_encrypt_json([
["seen", "34550:7fe92740b0530c0e8f1ec4c7dfbfdbd7e6e5194cc7cb853cb512e4d9862b5406:9174501", "1722372950", "<event1_id>"]
]),
}
```
## Conversation-level notifications
Kind `10117` tracks conversation-level notifications, including NIP 04 DMs and NIP 17 group chats.
Clients MAY choose to delete an entry from the seen status event if the current user was the most
recent one to post to the conversation, since the existence of that message implies the conversation
was read.
```json
{
"kind": "10117",
"created_at": 1722372950,
"content": nip44_encrypt_json([
["seen", "7fe92740b0530c0e8f1ec4c7dfbfdbd7e6e5194cc7cb853cb512e4d9862b5406", "1722372950", "<event1_id>"]
["seen", "1f8f6b86ec6f4902eb99058afeb68e0b7ca7aa2a090ea0ae3a2b64653aac9cc2", "1722372951", "<event1_id>"]
]),
}
```
To get the conversation id:
- Sort user and conversation partner pubkeys in lexicographically ascending order
- Concatenate and hash with sha256 and convert to hex
```typescript
// Our partner pubkeys
const partners = [
'7fe92740b0530c0e8f1ec4c7dfbfdbd7e6e5194cc7cb853cb512e4d9862b5406',
'6fc1d1e7a1b265f531838e2399858c14e4901ac23d927b2de1c36a713646b4de',
]
// encode as UTF-8
const msgBuffer = new TextEncoder().encode(partners.join(''));
// hash the message
const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
// convert ArrayBuffer to Array
const hashArray = Array.from(new Uint8Array(hashBuffer));
// convert bytes to hex string
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
```

View File

@ -93,6 +93,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
- [NIP-92: Media Attachments](92.md)
- [NIP-94: File Metadata](94.md)
- [NIP-96: HTTP File Storage Integration](96.md)
- [NIP-97: Seen Status](97.md)
- [NIP-98: HTTP Auth](98.md)
- [NIP-99: Classified Listings](99.md)
- [NIP-7D: Threads](7D.md)
@ -175,6 +176,9 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
| `10050` | Relay list to receive DMs | [51](51.md), [17](17.md) |
| `10063` | User server list | [Blossom][blossom] |
| `10096` | File storage server list | [96](96.md) |
| `10115` | Account level seen statuses | [97](97.md) |
| `10116` | Context level seen statuses | [97](97.md) |
| `10117` | Conversation level seen statuses| [97](97.md) |
| `13194` | Wallet Info | [47](47.md) |
| `21000` | Lightning Pub RPC | [Lightning.Pub][lnpub] |
| `22242` | Client Authentication | [42](42.md) |