- commit
- 438f90ad102789364ce5a463dafe8875e869a59e
- parent
- b17032316c724aa39687f17674f44639df93e475
- author
- Dami <dami.etoile@gmail.com>
| M | apps/ | 1 | + |
| A | apps/ | 153 | ++++++++++++++++++++++++++++++ |
| M | apps/ | 5 | + |
@@ -24,6 +24,7 @@ Diagram.zip is a browser-based diagram editor. Write or paste source, edit struc
2424 - **Create**: choose a diagram type, edit Source and Details, and learn its short syntax guide.2525 - **Style**: set common presentation options in Details, then use type-specific settings.2626 - **Share**: understand read links, edit links, encryption, and saved state.27+- **Integrate**: render fenced diagram blocks for a relay through the [Tiny transform](/integrate/tiny-transform/) endpoint.2728 2829 The pages use short examples and direct links. Agents can use the same stable URLs and code blocks.2930 @@ -0,0 +1,153 @@
1+---2+id: tiny-transform3+title: Tiny transform4+description: Render fenced diagram blocks from Nostr events into static SVG artifacts through the diagram.zip transform endpoint.5+sidebar_position: 16+---7+8+# Tiny transform9+10+tinyrelay is a self-hosted Nostr relay with custom views. A view POSTs source events to a transform URL and stores the11+answer as static artifacts attached to the source event. Diagram.zip provides12+the diagram transform at this endpoint:13+14+```text15+POST https://diagram.zip/transform/tiny16+```17+18+The relay sends fenced code blocks. The endpoint maps each block language to a19+renderer and renders the blocks in parallel. It materializes the SVG in the20+requested appearance and returns one artifact per successful block. This is a server to21+server call. The endpoint does not send CORS headers and browsers cannot call22+it directly.23+24+## Request25+26+Send a JSON body with the source event and the fenced blocks the relay found in27+its content:28+29+```json30+{31+ "relay": "https://relay.example",32+ "view": "diagrams",33+ "appearance": "auto-transparent",34+ "event": {35+ "id": "<hex>",36+ "kind": 30818,37+ "pubkey": "<hex>",38+ "created_at": 0,39+ "content": "...",40+ "tags": [["title", "Delivery flow"]]41+ },42+ "blocks": [43+ { "index": 0, "lang": "mermaid", "source": "graph TD; a-->b" },44+ { "index": 1, "lang": "python", "source": "print(1)" }45+ ]46+}47+```48+49+| Field | Meaning |50+| --- | --- |51+| `relay` | The relay origin. Informational. |52+| `view` | The view name. Informational. |53+| `appearance` | Optional. One of the seven SVG appearances. The default is `auto-transparent`. |54+| `event` | The source event. A `title` tag becomes the SVG title. |55+| `blocks[].index` | The block position in the event content. It is echoed back on each artifact. |56+| `blocks[].lang` | The fence language. Blocks whose language is not a renderer are skipped. |57+| `blocks[].source` | The diagram source. |58+59+Send these headers with the request:60+61+| Header | Value |62+| --- | --- |63+| `Content-Type` | `application/json` |64+| `X-Tiny-View` | The view name. |65+| `X-Tiny-Relay` | The relay origin. |66+| `X-Tiny-Signature` | `sha256=<hex>`, the HMAC-SHA256 of the raw request body. |67+68+## Signature and secret69+70+The signature is the hex HMAC-SHA256 of the raw request body, keyed with a71+shared secret. The worker verifies it with a constant-time comparison before it72+parses the body. A request without a valid signature is answered with `401`.73+74+The operator stores the secret as a Workers secret named `TINY_TRANSFORM_SECRET`:75+76+```sh77+wrangler secret put TINY_TRANSFORM_SECRET --config services/shell/wrangler.jsonc78+```79+80+When the secret is not set, the endpoint answers `503` with a JSON error. A81+misdeployed worker never renders unsigned input.82+83+## Languages and renderers84+85+Each block language is lowercased and looked up in this alias table. Every86+renderer id is also accepted as a language.87+88+| Language | Renderer |89+| --- | --- |90+| `mermaid`, `mmd` | `mermaid` |91+| `dot`, `graphviz` | `graphviz` |92+| `plantuml`, `puml`, `uml` | `plantuml` |93+| `c4plantuml`, `c4` | `c4plantuml` |94+| `svgbob`, `bob` | `svgbob` |95+| `vegalite`, `vega-lite` | `vegalite` |96+| `diagramsnet`, `drawio` | `diagramsnet` |97+| `d2`, `pikchr`, `goat`, `tikz`, `ditaa`, `erd`, `nomnoml`, `wavedrom`, `vega`, `dbml`, `bpmn`, `bytefield`, `excalidraw`, `structurizr`, `umlet`, `squaring`, `trn`, `wireviz`, `symbolator` | the same id |98+| `blockdiag`, `seqdiag`, `actdiag`, `nwdiag`, `packetdiag`, `rackdiag` | the same id |99+100+Each block is posted to its renderer unit at101+`https://{engine}.render.diagram.zip/v1/svg` with an empty presentation and no102+renderer options. Up to six blocks render at the same time. Each render has a103+20 second timeout.104+105+## Appearance106+107+The renderer unit answers with canonical SVG. The endpoint materializes it with108+the requested appearance, as described in109+[SVG normalization](/style/svg-normalization/). When the normalization profile110+of a renderer does not support the requested appearance, the artifact falls111+back to `raw` and reports that value. The `raw` appearance keeps the renderer112+palette.113+114+## Response115+116+A successful transform answers `200` with `Cache-Control: no-store`:117+118+```json119+{120+ "artifacts": [121+ {122+ "block": 0,123+ "engine": "mermaid",124+ "type": "image/svg+xml",125+ "body": "<svg ...>",126+ "appearance": "auto-transparent"127+ }128+ ],129+ "errors": [130+ { "block": 1, "engine": "d2", "error": "renderer answered 422: ..." }131+ ]132+}133+```134+135+A block failure never fails the request. A renderer error, a timeout, an136+unreachable unit, or SVG that cannot be materialized becomes one entry in137+`errors`. The other blocks still produce artifacts. Skipped languages138+appear in neither list.139+140+## Limits141+142+The endpoint rejects a request with a JSON error in these cases:143+144+| Condition | Status |145+| --- | --- |146+| Body larger than 1 MiB | `413` |147+| More than 32 blocks | `413` |148+| A block source longer than 512 KiB | `413` |149+| Unknown appearance, invalid JSON, or a malformed block | `400` |150+| Missing or wrong signature | `401` |151+| Secret not configured | `503` |152+153+Error bodies have the form `{"error": {"code": "...", "message": "..."}}`.