Add aggregate hash and site snapshots to NIP-5A (#2287)

This commit is contained in:
hzrd149
2026-06-16 11:10:10 -05:00
committed by GitHub
parent a932d690fe
commit 5d6b432267
3 changed files with 276 additions and 88 deletions

359
5A.md
View File

@@ -8,27 +8,196 @@ Static Websites (nsites)
This NIP describes a method by which static websites can be hosted from Blossom assets.
### Site Manifest Definition
### Site Manifests
A site manifest event MUST be a replaceable or an addressable event as defined in [NIP-01](01.md). There are two types of site manifest event kinds:
A site manifest event MUST be a regular, replaceable, or an addressable event as defined in [NIP-01](01.md).
There are two types of nsite manifest event kinds:
- **Root site**: Uses kind `15128` and MUST NOT include a `d` tag. This is a single replaceable event per pubkey and serves as the root site for the pubkey.
- **Named sites**: Uses kind `35128` and MUST have a `d` tag containing the site identifier. These can be smaller websites under a pubkey and can be thought of as sub-domains.
- **Named sites**: Uses kind `35128`. These can be smaller websites under a pubkey and can be thought of as subdomains.
### Named Sites
A named site uses kind `35128` and MUST include a `d` tag containing the site identifier.
The `d` tag identifies the named site and is used as the site's identifier within the author's namespace.
For canonical named-site URLs, the `d` tag value MUST match `^[a-z0-9-]{1,13}$` and MUST NOT end with `-`.
Because DNS labels are limited to 63 characters and `pubkeyB36` uses 50 of them, the `d` tag value MUST be 1-13 characters.
#### Nsite Event Tags
| Tag | Role | Required |
| ------------- | --------------------------------------------------------------------------------------------------- | ------------------------------ |
| `path` | Maps an absolute path to the sha256 hash of the file served at that path. | Yes, one or more |
| `x` | Provides the aggregate hash of the full manifest so the site version is indexable and discoverable. | Optional, recommended |
| `d` | Short identifier for the named site. This tag is used only for kind `35128` events. | Required for named sites only |
| `a` | References the immediate parent nsite from which this copied site was made. | Required for copied sites only |
| `A` | References the origin nsite of a copied site's lineage. | Required for copied sites only |
| `server` | Hints which blossom servers can be used to retrieve the blobs. | No |
| `title` | Provides a human-readable site title. | No |
| `description` | Provides a short human-readable description of the site. | No |
| `source` | Points to the site's source code repository or source archive. | No |
The event MUST include one or more `path` tags that map absolute paths to sha256 hashes. Each `path` tag MUST have the format `["path", "/absolute/path", "sha256hash"]` where:
- The first element is the literal string `"path"`
- The second element is an absolute path ending with a filename and extension
- The third element is the sha256 hash of the file that will be served under this path
The event SHOULD include an `x` tag containing the site aggregate hash as defined below. The `x` tag MUST have the format `["x", "<sha256-hex>", "aggregate"]`, where `<sha256-hex>` is the lowercase hexadecimal aggregate hash.
The event MAY include `server` tags that hint at which blossom servers can be used to find the blobs associated with the hashes.
The event MAY include `title` and `description` tags that provide simple site information.
The event MAY include a `source` tag that links to the site's source code repository or source archive. The `source` tag MUST have the format `["source", "<url>"]`, where `<url>` is an absolute `http` or `https` URL.
The event MAY include a `source` tag that links to the site's source code repository or source archive. The `source` tag MUST have the format `["source", "<url>"]`. For source code repositories, `<url>` MAY be a `nostr://` git URL as defined by [NIP-34](34.md), or an absolute `https://` git URL. For source archives, `<url>` MUST be an absolute `https://` URL.
The site icon SHOULD be provided by setting the `/favicon.ico` path in the manifest.
### Manifest Snapshots
For example, a root site manifest:
A manifest snapshot uses kind `5128` and is a regular event. Its purpose is to capture the state of a root site or named site at a particular point in time.
When publishing root sites or named sites, authors MAY also publish manifest snapshot events alongside them as additional events in order to preserve version history and make historical versions addressable by snapshot event id. For a given site, the snapshot event's `created_at` timestamp is the version timestamp of that snapshot.
For snapshotting an existing root site or named site, the manifest snapshot event MUST copy the source manifest's `path` tags, MUST include exactly one `x` tag whose value exactly matches the source manifest's aggregate `x` tag, and MUST include exactly one `a` tag referencing the source root site or named site. If the source manifest includes an `A` tag, the snapshot event MUST copy that `A` tag unchanged. If the source manifest does not include an `A` tag, the snapshot event SHOULD omit it. The referenced site identifies the snapshotted nsite, while the snapshot event's own `created_at` identifies the version. Other valid nsite tags such as `title`, `description`, `source`, `app`, `server`, or relay hints MAY also be copied if the author intends to preserve them, but they are optional.
### Aggregate Hash
The site aggregate hash is a deterministic hash of the site's `path` tags. It identifies a specific site version and can be used to identify equivalent site manifests published by different pubkeys.
The aggregate hash MUST be computed using only `path` tags. It MUST NOT depend on the order of tags in the manifest, and it MUST ignore all other tags and event fields, including `app` tags.
Two site manifest events are equivalent if and only if they produce the same aggregate hash.
A site manifest SHOULD include this value in an `x` tag with the format `["x", "<sha256-hex>", "aggregate"]` so the aggregate hash is indexable for discoverability and lookup. Manifest snapshot events of kind `5128` MUST include exactly one such tag, and it MUST exactly match the parent nsite's aggregate `x` tag.
To compute the aggregate hash:
1. Collect every `path` tag.
2. For each tag, produce a line in the exact format `<sha256hash> <absolute-path>\n`.
3. Sort all lines in ascending lexicographic order.
4. Concatenate the sorted lines as UTF-8 bytes.
5. Compute the SHA-256 hash of the concatenated bytes.
The resulting digest MUST be encoded as lowercase hexadecimal.
Example inputs:
```text
186ea5fd14e88fd1ac49351759e7ab906fa94892002b60bf7f5a428f28ca1c99 /index.html
fedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321 /favicon.ico
```
Example calculations:
```bash
nak req -k 15128 -a <pubkey> --limit 1 wss://relay.example.com | jq -r '.tags[] | select(.[0] == "path") | "\(.[2]) \(.[1])"' | sort | sha256sum
```
```javascript
const aggregateHash = sha256(event.tags.filter(t => t[0] === "path").map(([, path, hash]) => `${hash} ${path}\n`).sort().join(""))
```
### Upstream App Descriptors
An nsite MAY include one or more `app` tags that reference upstream app descriptor events that the manifest is part of. The `app` tag MUST have the format `["app", "<kind>:<pubkey>:<d-tag>", "<relay>"]`, where the second element is an addressable event reference to an app descriptor and the third element is a relay hint for locating that event.
This linkage is optional. It is intended to make room for application-level discovery and packaging flows without requiring app creators to extend nsite manifests themselves or overload them with non-manifest concerns.
The referenced app descriptor kind is intentionally generic so nsites can reference [NIP-89](89.md) applications and other present or future forms of app descriptors. Discoverability, app store metadata, runtime compatibility, and similar application-level concerns belong in those app descriptor events, while the nsite manifest remains focused on describing the site's files.
### Copying nsites
An nsite MAY be created by copying another root site or named site in order to pin that site under a different author's namespace at a specific state.
The purpose of copying is to preserve and republish an existing nsite while allowing the new author to maintain it independently. For this reason, authors creating a copied nsite SHOULD copy all tags from the source nsite whenever they remain applicable, including `path`, `x`, `app`, `server`, `title`, `description`, and `source`.
Copying an nsite does not require preserving the original site's kind or identifier. A copied root site MAY become a named site, a copied named site MAY become a root site, and a copied named site MAY use a different `d` tag than its parent.
When a site is copied from another nsite, the new manifest MUST include exactly one lowercase `a` tag referencing the immediate parent nsite from which it was copied.
Copied sites MUST also include exactly one uppercase `A` tag referencing the origin nsite of the copy lineage. If a site is copied directly from an original nsite, the `a` and `A` tags MAY reference the same nsite. If a site is copied from another copied site, the `A` tag MUST be copied unchanged from the parent site.
Because copied sites may change kind or identifier, the `a` and `A` tags are the stable, indexable references that preserve the lineage of the copied site.
Sites that were not copied from another nsite SHOULD NOT include `a` or `A` tags.
### Host server implementation
A host server is a HTTP server that is responsible for serving pubkey static websites
#### Address Formats
For interoperability, host servers SHOULD use the following canonical URL formats:
- Root site: `<npub>.nsite-host.com`
- Snapshot: `v<snapshotIdB36>.nsite-host.com`
- Named site: `<pubkeyB36><dTag>.nsite-host.com`
`pubkeyB36` is the author's raw 32-byte pubkey encoded with base36 (lowercase, digits `0-9` then letters `a-z`, no padding) and is always exactly 50 characters.
`snapshotIdB36` is the raw 32-byte snapshot event id encoded with base36 (lowercase, digits `0-9` then letters `a-z`, no padding) and is always exactly 50 characters.
`dTag` is the site identifier (`d` tag value) as plain text. It is appended directly after `pubkeyB36` with no separator.
This single-label format avoids wildcard certificate limitations with multi-level subdomains.
If the host server is using subdomain routing it MAY serve anything at its own root domain `nsite-host.com` (a landing page for example).
Example subdomains:
- Root site: `npub10phxfsms72rhafrklqdyhempujs9h67nye0p67qe424dyvcx0dkqgvap0e.nsite-host.com`
- Snapshot: `v<50-char-snapshotIdB36>.nsite-host.com`
- Named site: `<50-char-pubkeyB36><dTag>.nsite-host.com`
For canonical subdomain formats, the host server MUST parse the left-most DNS label as follows:
1. If the label is a valid `npub`, decode it and resolve the root site manifest.
2. Otherwise, if the label matches `^v[0-9a-z]{50}$`, treat it as a snapshot label where:
- `snapshotIdB36` is the final 50 characters after the leading `v`
- decode `snapshotIdB36` to the 32-byte event id
- resolve the manifest snapshot for that event id
3. Otherwise, if the label matches `^[0-9a-z]{50}[a-z0-9-]{1,13}$` and does not end with `-`, treat it as a named-site label where:
- `pubkeyB36` is the first 50 characters
- `dTag` is the remaining 1-13 characters
- decode `pubkeyB36` to a 32-byte pubkey
- use `dTag` as the identifier (`d` tag value)
- resolve the named site manifest for that pubkey and identifier
If parsing fails, the host server MUST treat the site as not found.
#### Resolving Paths
Once the site manifest event is found, the host server MUST extract the path-to-hash mappings from the `path` tags in the manifest. The host server SHOULD look for a `path` tag where the second element matches the requested path.
The host server SHOULD verify that the sha256 hash of any served blob matches the hash in the corresponding `path` tag. If the blob hash does not match, the host server SHOULD treat the site as not found.
##### Index Pages
If the request path does not end with a filename, the host server MUST fall back to using the `index.html` filename.
For example: `/` -> `/index.html` or `/blog/` -> `/blog/index.html`
Once the host server has found the site manifest event and located the matching `path` tag for the requested path, it should use the sha256 hash defined in the third element of the `path` tag to retrieve the file.
The host server SHOULD prioritize using `server` tags from the site manifest event as hints for which blossom servers to query. If the manifest includes `server` tags, the host server SHOULD attempt to retrieve the file from those servers first.
If the pubkey has a `10063` [BUD-03 user servers](https://github.com/hzrd149/blossom/blob/master/buds/03.md) event, the server MUST attempt to retrieve the file from the listed servers using the path defined in [BUD-01](https://github.com/hzrd149/blossom/blob/master/buds/01.md#get-sha256---get-blob).
If a pubkey does not have a `10063` event and no `server` tags are found in the manifest, the host server MUST respond with a status code 404.
The host server MUST forward the `Content-Type` and `Content-Length` headers from the Blossom server. If neither is defined, the host server MAY set `Content-Type` from the file extension in the requested path.
##### Not Found
If a host server is unable to find a site manifest event or a matching `path` tag for the requested path, it MUST use `/404.html` as a fallback path.
### Examples
#### Root Site Manifest
```yaml
{
@@ -39,22 +208,21 @@ For example, a root site manifest:
"pubkey": "266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5",
"sig": "f4e4a9e785f70e9fcaa855d769438fea10781e84cd889e3fcb823774f83d094cf2c05d5a3ac4aebc1227a4ebc3d56867286c15a6df92d55045658bb428fd5fb5",
"tags": [
// path mappings: absolute path -> sha256 hash
["path", "/index.html", "186ea5fd14e88fd1ac49351759e7ab906fa94892002b60bf7f5a428f28ca1c99"],
["path", "/about.html", "a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456"],
["path", "/favicon.ico", "fedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321"],
// optional: blossom server hints
["x", "<site-aggregate-sha256>", "aggregate"],
["app", "31990:266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5:my-app", "wss://relay.example.com"],
["app", "32267:266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5:com.example.webapp", "wss://relay.example.com"],
["server", "https://blossom.example.com"],
// optional: site metadata
["title", "My Nostr Site"],
["description", "A static website hosted on Nostr"],
// optional: source code location
["source", "https://github.com/example/my-nostr-site"]
]
}
```
And a named site manifest:
#### Named Site Manifest
```yaml
{
@@ -65,99 +233,114 @@ And a named site manifest:
"pubkey": "266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5",
"sig": "f4e4a9e785f70e9fcaa855d769438fea10781e84cd889e3fcb823774f83d094cf2c05d5a3ac4aebc1227a4ebc3d56867286c15a6df92d55045658bb428fd5fb5",
"tags": [
// site identifier
["d", "blog"],
// path mappings: absolute path -> sha256 hash
["path", "/index.html", "186ea5fd14e88fd1ac49351759e7ab906fa94892002b60bf7f5a428f28ca1c99"],
["path", "/post.html", "a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456"],
// optional: blossom server hints
["x", "<site-aggregate-sha256>", "aggregate"],
["app", "31990:266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5:my-blog-app", "wss://relay.example.com"],
["app", "32267:266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5:com.example.blog", "wss://relay.example.com"],
["server", "https://blossom.example.com"],
// optional: site metadata
["title", "My Blog"],
["description", "A blog hosted on Nostr"],
// optional: source code location
["source", "https://github.com/example/my-nostr-blog"]
]
}
```
### Host server implementation
#### Copied Named Site Manifest
A host server is a HTTP server that is responsible for serving pubkey static websites
#### Resolving Pubkeys
For interoperability, host servers SHOULD use the following canonical URL formats:
- Root site: `<npub>.nsite-host.com`
- Named site: `<pubkeyB36><dTag>.nsite-host.com`
`pubkeyB36` is the author's raw 32-byte pubkey encoded with base36 (lowercase, digits `0-9` then letters `a-z`, no padding) and is always exactly 50 characters.
`dTag` is the site identifier (`d` tag value) as plain text. It is appended directly after `pubkeyB36` with no separator.
For canonical named-site URLs, `dTag` MUST match `^[a-z0-9-]{1,13}$` and MUST NOT end with `-`.
Because DNS labels are limited to 63 characters and `pubkeyB36` uses 50 of them, `dTag` MUST be 1-13 characters.
This single-label format avoids wildcard certificate limitations with multi-level subdomains.
If the host server is using subdomain routing it MAY serve anything at its own root domain `nsite-host.com` (a landing page for example).
Example subdomains:
- Root site: `npub10phxfsms72rhafrklqdyhempujs9h67nye0p67qe424dyvcx0dkqgvap0e.nsite-host.com`
- Named site: `<50-char-pubkeyB36><dTag>.nsite-host.com`
#### Resolving Paths
When the host server receives a request and is able to determine the pubkey and identifier, it should fetch the users `10002` [NIP-65](https://github.com/nostr-protocol/nips/blob/master/65.md) relay list and lookup the site manifest event for the pubkey and identifier.
For canonical subdomain formats, the host server MUST parse the left-most DNS label as follows:
1. If the label is a valid `npub`, decode it and query for the root site manifest.
2. Otherwise, if the label matches `^[0-9a-z]{50}[a-z0-9-]{1,13}$` and does not end with `-`, treat it as a named-site label where:
- `pubkeyB36` is the first 50 characters
- `dTag` is the remaining 1-13 characters
- decode `pubkeyB36` to a 32-byte pubkey
- use `dTag` as the identifier (`d` tag value)
If parsing fails, the host server MUST treat the site as not found.
The host server should query for the site manifest event:
```yaml
// For root site (kind 15128, no d tag)
{ "kinds": [15128], "authors": [<pubkey>] }
// For named site (kind 35128, with d tag)
{ "kinds": [35128], "authors": [<pubkey>], "#d": [<identifier>] }
```jsonc
{
"content": "",
"created_at": 1727373475,
"id": "b1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456",
"kind": 35128,
"pubkey": "9f6815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd4000ff",
"sig": "f4e4a9e785f70e9fcaa855d769438fea10781e84cd889e3fcb823774f83d094cf2c05d5a3ac4aebc1227a4ebc3d56867286c15a6df92d55045658bb428fd5fb5",
"tags": [
["d", "blog"],
// copied directly from the original named site
["a", "35128:266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5:blog"],
// origin of this copy lineage; same as `a` for a direct copy
["A", "35128:266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5:blog"],
["path", "/index.html", "186ea5fd14e88fd1ac49351759e7ab906fa94892002b60bf7f5a428f28ca1c99"],
["path", "/post.html", "b1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456"],
["x", "<site-aggregate-sha256>", "aggregate"],
["title", "My Copied Blog"],
["description", "A copy of another named nsite"]
]
}
```
Once the site manifest event is found, the host server MUST extract the path-to-hash mappings from the `path` tags in the manifest. The host server should look for a `path` tag where the second element matches the requested path.
#### Copied Site Derived From Another Copied Site
If the request path does not end with a filename the host server MUST fallback to using the `index.html` filename
```jsonc
{
"content": "",
"created_at": 1727374475,
"id": "c1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456",
"kind": 35128,
"pubkey": "7a6815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd4bbbb",
"sig": "f4e4a9e785f70e9fcaa855d769438fea10781e84cd889e3fcb823774f83d094cf2c05d5a3ac4aebc1227a4ebc3d56867286c15a6df92d55045658bb428fd5fb5",
"tags": [
["d", "blog"],
// copied from another copied site, not directly from the origin
["a", "35128:9f6815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd4000ff:blog"],
// still points at the original site where this lineage began
["A", "35128:266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5:blog"],
["path", "/index.html", "186ea5fd14e88fd1ac49351759e7ab906fa94892002b60bf7f5a428f28ca1c99"],
["path", "/post.html", "c1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456"],
["x", "<site-aggregate-sha256>", "aggregate"],
["title", "My Derived Blog"],
["description", "A copy of a copied nsite that preserves the original lineage"]
]
}
```
For example: `/` -> `/index.html` or `/blog/` -> `/blog/index.html`
#### Manifest Snapshot
#### Resolving Files
```jsonc
{
"content": "",
"created_at": 1727373475,
"id": "9f8e7d6c5b4a39281716151413121110ffeeddccbbaa99887766554433221100",
"kind": 5128,
"pubkey": "266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5",
"sig": "f4e4a9e785f70e9fcaa855d769438fea10781e84cd889e3fcb823774f83d094cf2c05d5a3ac4aebc1227a4ebc3d56867286c15a6df92d55045658bb428fd5fb5",
"tags": [
["a", "35128:266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5:blog"],
["path", "/index.html", "186ea5fd14e88fd1ac49351759e7ab906fa94892002b60bf7f5a428f28ca1c99"],
["path", "/post.html", "a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456"],
["x", "<site-aggregate-sha256>", "aggregate"],
["server", "https://blossom.example.com"],
["title", "My Blog v1"],
["description", "An immutable snapshot of a blog hosted on Nostr"],
["source", "https://github.com/example/my-nostr-blog"]
]
}
```
Once the host server has found the site manifest event and located the matching `path` tag for the requested path, it should use the sha256 hash defined in the third element of the `path` tag to retrieve the file.
#### Manifest Snapshot Of A Copied Site
The host server SHOULD prioritize using `server` tags from the site manifest event as hints for which blossom servers to query. If the manifest includes `server` tags, the host server SHOULD attempt to retrieve the file from those servers first.
If the pubkey has a `10063` [BUD-03 user servers](https://github.com/hzrd149/blossom/blob/master/buds/03.md) event the server MUST attempt to retrieve the file from the listed servers using the path defined in [BUD-01](https://github.com/hzrd149/blossom/blob/master/buds/01.md#get-sha256---get-blob)
If a pubkey does not have a `10063` event and no `server` tags are found in the manifest, the host server MUST respond with a status code 404
The host server MUST forward the `Content-Type`, and `Content-Length` headers from the Blossom server. If none are defined the host server MAY set `Content-Type` from the file extension in the requested path
#### Handling Not Found
If a host server is unable to find a site manifest event or a matching `path` tag for the requested path, it MUST use `/404.html` as a fallback path
### Legacy Support
Kind `34128` is marked as legacy/deprecated. This kind was used for individual static file events where each file was represented by a separate event with a `d` tag for the path and an `x` tag for the sha256 hash.
Host servers MAY still support kind `34128` for backward compatibility with existing sites, but new sites SHOULD use kind `15128` (root site manifest) or kind `35128` (named site manifest) instead.
Read the [legacy version](https://github.com/hzrd149/nips/blob/41e77b45a1e8a8d170097e363f7d7254797cc5c5/nsite.md) for more details.
```jsonc
{
"content": "",
"created_at": 1727375475,
"id": "8f8e7d6c5b4a39281716151413121110ffeeddccbbaa99887766554433221100",
"kind": 5128,
"pubkey": "9f6815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd4000ff",
"sig": "f4e4a9e785f70e9fcaa855d769438fea10781e84cd889e3fcb823774f83d094cf2c05d5a3ac4aebc1227a4ebc3d56867286c15a6df92d55045658bb428fd5fb5",
"tags": [
// the site manifest this snapshot captures
["a", "35128:9f6815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd4000ff:blog"],
// copied unchanged from the snapshotted site's origin lineage
["A", "35128:266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5:blog"],
["path", "/index.html", "186ea5fd14e88fd1ac49351759e7ab906fa94892002b60bf7f5a428f28ca1c99"],
["path", "/post.html", "b1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456"],
["x", "<site-aggregate-sha256>", "aggregate"],
["app", "31990:266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5:my-blog-app", "wss://relay.example.com"],
["title", "My Copied Blog v1"],
["description", "An immutable snapshot of a copied nsite"]
]
}
```

4
89.md
View File

@@ -56,6 +56,8 @@ The third value of the tag SHOULD be the platform where this recommendation migh
"tags": [
["d", <random-id>],
["k", <supported-event-kind>],
["latest", "35128:<application-pubkey>:<site-d-identifier>", "wss://relay1"],
["next", "35128:<application-pubkey>:<next-site-d-identifier>", "wss://relay1"],
["web", "https://..../a/<bech32>", "nevent"],
["web", "https://..../p/<bech32>", "nprofile"],
["web", "https://..../e/<bech32>"],
@@ -70,6 +72,8 @@ The third value of the tag SHOULD be the platform where this recommendation migh
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.
* App descriptor events SHOULD tag or otherwise reference related site manifest events when applicable, so clients can discover the deployed site manifest for an application directly from the upstream app descriptor.
* For web applications, `kind:31990` events SHOULD include `latest` and `next` tags referencing related nsite manifests when applicable. These tags use the same shape as an `a` tag: the second element is `<kind>:<pubkey>:<d-tag>` and the third element is an optional relay hint. `latest` SHOULD reference the current site manifest for the application, while `next` SHOULD reference the next site manifest intended for rollout or upgrade.
* `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.

View File

@@ -227,6 +227,7 @@ This table is not exhaustive. For a machine-readable registry of all known event
| `10312` | Room Presence | [53](53.md) |
| `13194` | Wallet Info | [47](47.md) |
| `13534` | Membership Lists | [43](43.md) |
| `5128` | nsite manifest snapshot | [5A](5A.md) |
| `15128` | Root nsite manifest | [5A](5A.md) |
| `17375` | Cashu Wallet Event | [60](60.md) |
| `22242` | Client Authentication | [42](42.md) |