mirror of
https://github.com/dergigi/boris.git
synced 2026-01-31 12:44:37 +01:00
docs: simplify NIP-85 to match NIP-84 style and length
- Remove verbose rationale section - Remove excessive querying examples - Remove privacy considerations (obvious) - Remove implementation notes fluff - Remove references section - Keep only essential: format, tags, content, examples - Match NIP-84's concise, to-the-point style From 190 lines down to ~75 lines - much more readable
This commit is contained in:
@@ -8,33 +8,26 @@ This NIP defines kind `39802`, a parameterized replaceable event for tracking re
|
||||
|
||||
## Table of Contents
|
||||
|
||||
* [Event Kind](#event-kind)
|
||||
* [Event Structure](#event-structure)
|
||||
* [Format](#format)
|
||||
* [Tags](#tags)
|
||||
* [Content](#content)
|
||||
* [Semantics](#semantics)
|
||||
* [Examples](#examples)
|
||||
* [Querying](#querying)
|
||||
* [Privacy Considerations](#privacy-considerations)
|
||||
* [Rationale](#rationale)
|
||||
* [Implementation Notes](#implementation-notes)
|
||||
|
||||
## Event Kind
|
||||
|
||||
- `39802`: Reading Progress (Parameterized Replaceable)
|
||||
|
||||
## Event Structure
|
||||
## Format
|
||||
|
||||
Reading progress events use NIP-33 parameterized replaceable semantics. The `d` tag serves as the unique identifier per author and target content.
|
||||
|
||||
### Tags
|
||||
|
||||
Events SHOULD tag the source of the reading progress, whether nostr-native or not. `a` tags should be used for nostr events and `r` tags for URLs.
|
||||
|
||||
When tagging a URL, clients generating these events SHOULD do a best effort of cleaning the URL from trackers or obvious non-useful information from the query string.
|
||||
|
||||
- `d` (required): Unique identifier for the target content
|
||||
- For Nostr articles: `30023:<pubkey>:<identifier>` (matching the article's coordinate)
|
||||
- For external URLs: `url:<base64url-encoded-url>`
|
||||
- `a` (optional but recommended for Nostr articles): Article coordinate `30023:<pubkey>:<identifier>`
|
||||
- `r` (optional but recommended for URLs): Raw URL of the external content
|
||||
- Clients SHOULD clean URLs from tracking parameters and non-essential query strings before tagging
|
||||
|
||||
### Content
|
||||
|
||||
@@ -42,23 +35,16 @@ The content is a JSON object with the following fields:
|
||||
|
||||
- `progress` (required): Number between 0 and 1 representing reading progress (0 = not started, 1 = completed)
|
||||
- `loc` (optional): Number representing a location marker (e.g., pixel scroll position, page number, etc.)
|
||||
- `ts` (optional): Unix timestamp (seconds) when the progress was recorded. This is for display purposes only; event ordering MUST use `created_at`
|
||||
- `ver` (optional): Schema version string (e.g., "1")
|
||||
- `ts` (optional): Unix timestamp (seconds) when the progress was recorded
|
||||
- `ver` (optional): Schema version string
|
||||
|
||||
### Semantics
|
||||
The latest event by `created_at` per (`pubkey`, `d`) pair is authoritative (NIP-33 semantics).
|
||||
|
||||
- The latest event by `created_at` per (`pubkey`, `d`) pair is authoritative (NIP-33 semantics)
|
||||
- Clients SHOULD implement rate limiting to avoid excessive relay traffic:
|
||||
- Debounce writes (recommended: 5 seconds)
|
||||
- Only save when progress changes significantly (recommended: ≥1% delta)
|
||||
- Skip saving very early progress (recommended: <5%)
|
||||
- Always save on completion (progress = 1) and when unmounting/closing content
|
||||
- The `created_at` timestamp SHOULD match the time the progress was observed
|
||||
- Event ordering and replaceability MUST use `created_at`, not the optional `ts` field in content
|
||||
Clients SHOULD implement rate limiting to avoid excessive relay traffic (debounce writes, only save significant changes).
|
||||
|
||||
## Examples
|
||||
|
||||
### Nostr Article Progress
|
||||
### Nostr Article
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -69,13 +55,11 @@ The content is a JSON object with the following fields:
|
||||
"tags": [
|
||||
["d", "30023:<author-pubkey>:<article-identifier>"],
|
||||
["a", "30023:<author-pubkey>:<article-identifier>"]
|
||||
],
|
||||
"id": "<event-id>",
|
||||
"sig": "<signature>"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### External URL Progress
|
||||
### External URL
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -86,104 +70,6 @@ The content is a JSON object with the following fields:
|
||||
"tags": [
|
||||
["d", "url:aHR0cHM6Ly9leGFtcGxlLmNvbS9wb3N0"],
|
||||
["r", "https://example.com/post"]
|
||||
],
|
||||
"id": "<event-id>",
|
||||
"sig": "<signature>"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Querying
|
||||
|
||||
### All progress for a user
|
||||
|
||||
```json
|
||||
{
|
||||
"kinds": [39802],
|
||||
"authors": ["<user-pubkey>"]
|
||||
}
|
||||
```
|
||||
|
||||
### Progress for a specific Nostr article
|
||||
|
||||
```json
|
||||
{
|
||||
"kinds": [39802],
|
||||
"authors": ["<user-pubkey>"],
|
||||
"#d": ["30023:<author-pubkey>:<article-identifier>"]
|
||||
}
|
||||
```
|
||||
|
||||
Or using the `a` tag:
|
||||
|
||||
```json
|
||||
{
|
||||
"kinds": [39802],
|
||||
"authors": ["<user-pubkey>"],
|
||||
"#a": ["30023:<author-pubkey>:<article-identifier>"]
|
||||
}
|
||||
```
|
||||
|
||||
### Progress for a specific URL
|
||||
|
||||
```json
|
||||
{
|
||||
"kinds": [39802],
|
||||
"authors": ["<user-pubkey>"],
|
||||
"#r": ["https://example.com/post"]
|
||||
}
|
||||
```
|
||||
|
||||
## Privacy Considerations
|
||||
|
||||
Reading progress events are public by default to enable interoperability between clients. Users concerned about privacy should:
|
||||
|
||||
- Use clients that allow disabling progress sync
|
||||
- Use clients that allow selective relay publishing
|
||||
- Be aware that reading progress reveals their reading habits
|
||||
|
||||
A future extension could define an encrypted variant for private progress tracking, but that is out of scope for this NIP.
|
||||
|
||||
## Rationale
|
||||
|
||||
### Why a dedicated kind instead of NIP-78 application data?
|
||||
|
||||
While NIP-78 (kind 30078) can store arbitrary application data, a dedicated kind offers several advantages:
|
||||
|
||||
1. **Discoverability**: Other clients can easily find and display reading progress without knowing application-specific `d` tag conventions
|
||||
2. **Interoperability**: Standard schema enables cross-client compatibility
|
||||
3. **Indexing**: Relays can efficiently index and query reading progress separately from other app data
|
||||
4. **Semantics**: Clear, well-defined meaning for the event kind
|
||||
|
||||
### Why parameterized replaceable (NIP-33)?
|
||||
|
||||
- Each article/URL needs exactly one current progress value per user
|
||||
- Automatic deduplication by relays reduces storage and bandwidth
|
||||
- Simple last-write-wins semantics based on `created_at`
|
||||
- Efficient querying by `d` tag
|
||||
|
||||
### Why include both `d` and `a`/`r` tags?
|
||||
|
||||
- `d` provides the unique key for replaceability
|
||||
- `a` and `r` enable efficient filtering without parsing `d` values
|
||||
- Redundancy improves relay compatibility and query flexibility
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- Clients SHOULD use the event's `created_at` as the authoritative timestamp for sorting and merging progress
|
||||
- The optional `ts` field in content is for display purposes only (e.g., "Last read 2 hours ago")
|
||||
- For URLs, the base64url encoding in the `d` tag MUST use URL-safe characters (replace `+` with `-`, `/` with `_`, remove padding `=`)
|
||||
- Clients SHOULD validate that `progress` is between 0 and 1
|
||||
|
||||
### URL Handling
|
||||
|
||||
When generating events for external URLs:
|
||||
|
||||
- Clients SHOULD clean URLs by removing tracking parameters (e.g., `utm_*`, `fbclid`, etc.) and other non-essential query strings
|
||||
- The cleaned URL should be used for both the `r` tag and the base64url encoding in the `d` tag
|
||||
- This ensures that the same article from different sources (with different tracking params) maps to the same reading progress event
|
||||
|
||||
## References
|
||||
|
||||
- [NIP-01: Basic protocol flow](https://github.com/nostr-protocol/nips/blob/master/01.md)
|
||||
- [NIP-33: Parameterized Replaceable Events](https://github.com/nostr-protocol/nips/blob/master/33.md)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user