nips/512.md
2024-07-05 10:41:40 +02:00

8.0 KiB

Nostr Sites

This NIP describes a way to render a selection of Nostr events on a website.

A web page that is part of the Nostr Site must include nostr:site meta tag:

<meta property="nostr:site" content="<naddr>" /> 

The site event, referenced by naddr from nostr:site meta tag, is a parameterized replaceable event of kind 30512. The content field MAY contain a rich description of the site in markdown syntax (NIP-23), all tags are optional (except d).

Tags:

{
  "tags":[
    // absolute url of the nostr site root, may include /path/, must not include query string, must end with /
    ["r", "https://site.com/"], 
    ["name", "<pwa name>"],
    ["title", "<site title>"],
    ["summary", "<site description>"],
    ["image", "<site code image url>"],

    // contributors, if omitted - event's author is the single site contributor
    ["p", "<contributor-pubkey>"],

    // filters for fetching published events

    // <tag> - single-letter tag
    ["include", "<tag>", "<value>"],
    // list of included event kinds
    ["kind", "30023"],
    // override contributors' outbox relays to fetch content 
    ["relay", "<relay>"],

    // event id and package hash of the extensions (themes, plugin)
    ["x", "<id>", "<relay>", "<package-hash>", "<petname>"],

    // renderer engine, preferably reverse-domain notation, should match theme engine and plugin engine, i.e. `pro.npub.v1`
    ["z", "<engine>"],

    // meta tags for website rendering, seo, social, navigation
    ["icon", "<favicon url>"],
    ["logo", "<header logo url>"],
    ["color", "<#hex - accent color, PWA theme_color>"],
    ["lang", "<language code>"],
    ["meta_title", "<overrides title>"],
    ["meta_description", "<overrided summary>"],
    ["og_title", "<open-graph title, overrides title>"],
    ["og_description", "<open-graph description, overrides summary>"],
    ["og_image", "<open-graph image url, overrides image>"],
    ["twitter_image", "<twitter image url, overrides image>"],
    ["twitter_title", "<twitter title, overrides title>"],
    ["twitter_description", "<twitter description, overrides title>"],

    // primary navigation, one tag per link
    ["nav", "</relative/url>", "<label>"],
  ]
}

By default, no events are published on the site.

Admin MAY use include tags to specify which events, authored by contributors, should be displayed on the site. include contains a key:value pair of single-letter tag and it's value that will be used as filters to fetch published events, i.e. t:bitcoin or g:<geohash>. A special value of * means "everything".

If kind tags are specified, only these kinds will be fetched.

If relay tags are specified, only these relays will be used, overriding the outbox relays of the contributors.

If include has a special value of ? then "manual" submission is enabled and contributors MAY create submit events that reference the target events to be published on the site.

"Submit" events

Events of kind 512 are used by Nostr Site contributors to submit an event to the site (manual submission must be enabled with include=?). content field may be empty, tags may include:

{
  "tags":[
    ["a", "<addr>", "<relay>", "site"], // addr of the target site
    ["a"/"e", "<addr/id>", <relay>], // addr/id of the submitted event 
    ["a"/"e", "<addr/id>", <relay>], // addr/id of the submitted event 
    ["k", "<kind>"], // submitted event's kind, to allow filtering by target event's kind
    ["r", "<slug>"] // optional slug for submitted event, to be used in the website url, i.e. /posts/<slug>.
  ]
}

Only zero or one event may be referenced with a or e tag.

If relay tags are specified in site event, submit events will only be fetched from those relays.

If target event is authored by none of the contributors, it should be rendered as a repost by the contributor and show the original author.

If r tag's value starts with / then this a relative url of a static page (i.e. r:/path/to/static/page). The submitted events referenced by a or e tags of static pages SHOULD NOT be included when listing published events, but are only rendered at the specified url. If no a or e tags are specified in a submit event, then it's content field will be rendered as the content of the static page - this allows to exclude such static pages from social media feeds.

If several submit events published by contributors have the same r tag then the most recent one should be preferred.

To override default meta tags of a page, submit event may include meta info tags of the site event (title, image, meta_title, og_title etc).

Hashtag pages

Sites may need to display additional info on web pages dedicated to hashtags, and may use hashtag event published by contributors for that. The hashtag event is a parameterized replaceable event of kind 30513. the content field may include a string of text in the same format as "long-form content" NIP-23, to be used as the body of the hashtag web page. Hashtag event will have tags:

{
  "tags":[
    ["t", "<hashtag>"], // target hashtag, must be included exactly once
    ["a", "<addr>"], // nostr site address
    ["r", "<slug>"], // optional slug for hashtag, to be used in the website url, i.e. /tags/<slug>.
  ]
}

To override default meta tags of a hashtag page, hashtag event may include meta info tags of the site event (title, image, meta_title, og_title etc).

If r tag starts with / then it is a static hashtag webpage, and this hashtag should not be listed under posts and in other hashtag lists.

If several hashtag events published by contributors have the same r tag then the most recent one should be preferred.

Themes and Plugins

The theme event is parameterized replaceable event of kind 30514, it's content field may have a "rich" description in the same syntax as NIP-23 long-form notes. It has the following tags:

{
  "tags":[
    ["title", "<theme name>"],
    ["summary", "<theme description>"],
    ["version", "<latest version>"], 
    ["license", "<theme license>"], // MIT, etc
    ["e", "<package id>", "<relay>"], // theme code package event id
    ["z", "<website engine id>"], // engine, must match the nostr site engine
  ]
}

The plugin event is parameterized replaceable event of kind 30515 with the same structure.

The package event of kind 1036 (see the new NIP-136) is essentially a directory of files - relative urls and hashes. It may contain release notes, and also contains the package hash - a combined hash of all files and their relative urls.

The package event of kind 1036 SHOULD have additional tags:

{
  "tags":[
    ["l", "theme|plugin", "org.nostrsites.ontology"], // type of code
    ["L", "org.nostrsites.ontology"], // label category
    ["a", "<addr>"] // address of the theme or plugin replaceable event
  ]
}

The site events are linked to the themes and plugins using package event ids, and also the package hash (see site event above). This will allow us to handle link rot - if theme package event is deleted by relays, other events with the same package hash can be found to avoid disruption of every site using the deleted package.

Rendering

Steps to render a Nostr Site to produce an HTML page:

  • parse site event naddr from meta-tags of the HTML fetched from the server (or from settings for server-side rendering)
  • fetch site event from relays specified in naddr
  • if not found, fall back to fetching naddr author's outbox relays
  • fetch extensions (plugins and themes)
  • fetch authors' relays (will be omitted if single admin-author)
  • if include tags are specified then
  • fetch by tags from those authors from their outbox relays
  • also if include="?" is specified:
  • fetch submit events from authors' outbox relays
  • fetch targets (may include fetching target authors' relays)
  • init template engine and render the target events into html
  • if root url is specified, renderer should put all internal links as sub-path to root