tinyrelaycommit

Commit 2b6691190621

browse files at this commit | history

1diff --git a/README.md b/README.md
2index a2d31b8..536025d 100644
3--- a/README.md
4+++ b/README.md
5@@ -2,6 +2,23 @@
6
7 `tiny` is a self-hosted, multitenant Nostr relay. Each tenant has durable local storage, an owner, relay policy, inbox and outbox delivery, hosted sites, file storage, and optional repository browsing.
8
9+```mermaid
10+flowchart LR
11+ people((people)) -- "NIP-07 or Nostr Connect" --> ui[web pages]
12+ agents((agents)) -- "MCP, Buzz, GRASP" --> api[/mcp, /events, git/]
13+ ui --> tenant
14+ api --> tenant
15+ subgraph tenant [one tenant]
16+ policy[owner and policy] --> store[(durable store)]
17+ store --> rooms[rooms]
18+ store --> wiki[wiki]
19+ store --> repos[repositories]
20+ store --> files[files and sites]
21+ store --> views[views and records]
22+ end
23+ tenant -- "inbox and outbox" --> relays((other relays))
24+```
25+
26 ## Run locally
27
28 Build and start the daemon:
29@@ -60,9 +77,24 @@ See [Agent identities](docs/agents.md) for granting an assistant or bot its own
30
31 See [Wiki](docs/wiki.md) for pages, versions and forks, merge requests and redirects.
32
33+See [Custom views](docs/views.md) for rendering fenced code blocks through a transform you run and keeping the result as signed artifacts.
34+
35 **Manage > Health** shows the relay and script versions and whether the browser's WebMCP tools are registered. See [WebMCP tools](docs/webmcp.md) for browser-agent integration and authorization behavior.
36
37-Agents outside the browser connect to `/mcp`, a stateless Model Context Protocol endpoint authenticated with NIP-98, and read `/llms.txt` for a summary of the relay's machine surface. See [MCP](docs/mcp.md).
38+Agents outside the browser connect to `/mcp`, a stateless Model Context Protocol endpoint authenticated with NIP-98, and read `/llms.txt` for a summary of the relay's machine surface. See [MCP](docs/mcp.md). An agent acts under a grant the owner signs, and the owner reviews what it proposes:
39+
40+```mermaid
41+sequenceDiagram
42+ participant O as owner
43+ participant R as relay
44+ participant A as agent
45+ O->>R: sign a kind 30392 grant (rooms, repos, wiki, sites, kinds)
46+ A->>R: publish under its own key
47+ R-->>A: accepted, or restricted with the reason
48+ R-->>O: wake a device: proposal or request
49+ O->>R: react + or - on the exact event
50+ R-->>A: visible to everyone, or held
51+```
52
53 ## Deployment
54
55@@ -83,6 +115,17 @@ sudo systemctl enable --now tiny
56
57 Keep the data directory on local durable storage. The process exposes `/healthz` and `/readyz`. An optional diagnostics listener provides `/metrics` and protected pprof endpoints. Set `--otlp-endpoint` or `OTEL_EXPORTER_OTLP_ENDPOINT` when exporting traces.
58
59+The reference installation keeps the relay off the public interface and lets two sidecars front it:
60+
61+```mermaid
62+flowchart LR
63+ internet((internet)) --> https[https sidecar]
64+ tailnet((tailnet)) --> ts[tailscale sidecar]
65+ https --> tiny[tiny]
66+ ts --> tiny
67+ tiny --> data[(data directory)]
68+```
69+
70 See [Personal relay deployment](docs/personal-relay.md) for the reference installation.
71
72 ## Test and diagnose
73diff --git a/docs/views.md b/docs/views.md
74new file mode 100644
75index 0000000..48b5e7e
76--- /dev/null
77+++ b/docs/views.md
78@@ -0,0 +1,77 @@
79+# Custom views
80+
81+A custom view renders the fenced code blocks a relay already holds. The owner names a set of event kinds and a set of fenced block languages, and points the view at an https transform they run. When a matching event arrives the relay posts the blocks in those languages to the transform, and keeps the SVG or PNG that comes back as a relay-signed artifact attached to the source event. The relay's pages then show the artifact in place of the code block.
82+
83+Nothing about a view is built into the relay. It renders what its owner asked for, through a service the owner chose. A relay with no views behaves exactly as before, and a block whose artifact is missing, still queued or refused stays visible as code.
84+
85+## Define a view
86+
87+Call the `addcustomview` management method, or the `add_custom_view` MCP tool, as the owner:
88+
89+```json
90+{"method": "addcustomview", "params": [{"name": "diagrams", "kinds": [30818, 30023, 30618], "transform": "https://render.example/tiny", "languages": ["mermaid", "dot", "d2"], "trigger": "write", "audience": "public"}]}
91+```
92+
93+| Field | Meaning |
94+| --- | --- |
95+| `name` | 1 to 32 lowercase letters, digits or hyphens. Names the view and its artifact paths. |
96+| `kinds` | 1 to 16 event kinds to watch. Kind 30618 sends the repository README at its head. |
97+| `transform` | An https URL on a public host. |
98+| `languages` | 1 to 32 fenced block languages, lowercase. Only these blocks are sent. |
99+| `trigger` | `write` sends each matching event as it arrives, `hourly` sends the newest ones every hour. Defaults to `write`. |
100+| `audience` | `public` publishes the artifacts, `members` keeps them to members. Defaults to `public`. |
101+| `max_bytes` | Largest artifact accepted. 1 MiB by default, 4 MiB at most. |
102+| `secret` | Optional shared secret, 16 to 128 printable ASCII characters. Generated when omitted. |
103+
104+The answer carries the secret once. Keep it: the transform needs it to verify each request. Only the owner may define, change or list views.
105+
106+## What the relay sends
107+
108+A view posts one request for each source event, carrying only the blocks:
109+
110+```json
111+{"relay": "https://relay.example", "view": "diagrams", "source": {"id": "<source>", "kind": 30818}, "blocks": [{"index": 2, "lang": "mermaid", "source": "graph TD;\n a-->b;"}]}
112+```
113+
114+`index` counts every fenced block in the text from zero, whether or not it carries a language, so an answer can name the block it rendered. No event content outside the blocks, and no tags, author or timestamp, leaves the relay. Blocks in other languages are dropped before the request is built, and a block whose artifact the relay already holds is reused rather than sent again.
115+
116+| Header | Value |
117+| --- | --- |
118+| `X-Tiny-View` | The view name. |
119+| `X-Tiny-Relay` | The relay's public URL. |
120+| `X-Tiny-Signature` | `sha256=` followed by the hex HMAC-SHA256 of the body under the view's secret. |
121+
122+Verify the signature before rendering anything. The relay waits 30 seconds for an answer.
123+
124+## What the transform answers
125+
126+```json
127+{"artifacts": [{"block": 2, "type": "svg", "body": "<svg ...>", "engine": "mermaid"}], "errors": [{"block": 5, "error": "unknown shape on line 3"}]}
128+```
129+
130+Each artifact names the block it rendered, its `type`, either `svg` or `png`, and its `body`, the SVG source or a base64 PNG. `engine` is optional and is recorded on the artifact. An artifact larger than the view's `max_bytes` is refused. SVG bodies are checked before they are stored: script elements, event handlers and external references are rejected rather than stripped, and the whole artifact is refused. A block listed under `errors`, or left out of the answer entirely, keeps showing its code.
131+
132+## Artifacts
133+
134+An artifact is a relay-signed kind 30078 record addressed `bind.ws/view/<name>/<hash>`, where the hash names the block's source text. The same block in two events produces one artifact with two sources. The record carries a `view` tag, one `block` tag for each source, a `type` tag and, when the transform reported one, an `engine` tag.
135+
136+Artifacts follow their sources. An artifact expires when its last source expires, and one that outlives every source that referred to it is deleted. Editing an event detaches the blocks it no longer carries, and the artifact is dropped once nothing points at it. Removing a view deletes every artifact it produced.
137+
138+Each artifact is served at `/views/<name>/<hash>.svg` or `.png` under a sandbox policy that blocks scripts and outside loads. A members-only view answers only members; a public one follows the relay's read rule. The relay's pages embed the artifact with the code block as its fallback, so a reader whose browser refuses the artifact still sees the source.
139+
140+## Failures
141+
142+A response outside 2xx, a timeout or a connection failure counts as a failure. The relay tries the event again after one minute and once more after five, three attempts in all, then drops it. After 20 failures in a row the view is paused and its status records the reason. A successful run resets the failure count.
143+
144+## Manage views
145+
146+| Method | Effect |
147+| --- | --- |
148+| `listcustomviews` | Lists views with their kinds, languages, transform host, trigger, audience, state, failure count and last run. The secret is never listed. |
149+| `addcustomview {name, kinds, transform, languages, trigger, audience, max_bytes, secret}` | Defines a view and returns its secret once. |
150+| `removecustomview <name>` | Deletes the view and every artifact it produced. |
151+| `pausecustomview <name>` | Stops transform requests. The artifacts stay. |
152+| `resumecustomview <name>` | Resumes the view and clears the failure count. |
153+| `runcustomview <name>` | Queues a backfill over the newest 500 events of the view's kinds. Blocks that already have an artifact are reused. |
154+
155+The **Manage > Views** page lists each view with its state, last run and failure count, and buttons to pause, resume, run or remove it. The same controls are available over MCP; see [MCP](mcp.md).

About

ownerc01503e8035f
visibilitypublic
head2b6691190621

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

  • https://012.run/npub1cq2s86qrtadf36eqq3epm38wmhdynrrcwxf84eldk3f94dkv7ttsrulrz5/tinyrelay.git

Refs