Statische Seiten über die Pull-API (Starlight, Astro, Hugo …)
Orimora kann die Inhaltsquelle für eine statische Seite sein, ohne einen Git-Mirror dazwischen. Die Seite zieht die publizierten Dokumente zur Build-Zeit aus Orimoras token-gesicherter Pull-API und rendert sie — Orimora bleibt die Single Source of Truth, und es gibt kein separates Content-Repository zu pflegen.
Das funktioniert mit jedem Generator, der Markdown + Frontmatter liest (Astro/Starlight, Hugo, Jekyll, Eleventy …). Das Beispiel nutzt Starlight.
Funktionsweise
Abschnitt betitelt „Funktionsweise“- Du publizierst Dokumente (oder einen Ordner) zu einem Kanal in Orimora — nur diese werden ausgeliefert, sonst nichts (kein Draft-Leak).
- Ein kleines Pull-Skript läuft vor jedem Build, holt das publizierte Set aus der Pull-API und schreibt eine Markdown-Datei pro Dokument.
- Der Generator baut wie gewohnt aus diesen Dateien.
Vorab: SSG oder SSR? Zwei sehr verschiedene Wege
Abschnitt betitelt „Vorab: SSG oder SSR? Zwei sehr verschiedene Wege“Dieses Rezept ist für statische Generatoren (SSG: Starlight, Hugo, Jekyll, Eleventy …) — die übernehmen Inhalte nur beim Build, deshalb braucht es ein Pull-Skript und einen Rebuild-Auslöser.
Server-gerenderte Apps (SSR/ISR — Next.js, Nuxt, SvelteKit …) brauchen dieses Rezept
nicht. Sie rufen die Pull-API einfach zur Request-Zeit ab (mit Cache davor) — kein
Build, kein Hook, publizieren ist sofort live. Die API unterstützt dafür ETag /
If-None-Match (304-Antworten) und updatedSince für inkrementelle Abfragen.
1. Kanal in Orimora anlegen
Abschnitt betitelt „1. Kanal in Orimora anlegen“- Einstellungen → Publishing → Neuer Kanal, Transport Pull, Format Markdown. Optional: die Deploy-Hook-URL deines Hosts eintragen — dann stößt Orimora den Rebuild nach jedem Publizieren automatisch an (Details).
- Publiziere deine Dokumente per „An Kanal senden…” an einem Dokument oder Ordner — das läuft über deine Login-Session und braucht kein Token.
- Öffne den Kanal und erstelle ein Token — behandle es wie ein Passwort. Das Token ist nur für den Consumer (das Pull-Skript), nicht fürs Publizieren.
Du hast nun drei Werte für das Skript: die Orimora-Basis-URL, die Kanal-ID und das
Token. Basis-URL und Kanal-ID stecken in der Pull-API-URL, die auf der
Kanal-Karte steht und sich dort kopieren lässt
(https://<basis-url>/api/v1/published/<kanal-id>/documents).
Sofort verifizieren
Abschnitt betitelt „Sofort verifizieren“Bevor du irgendetwas baust, prüfe die Kette mit einem curl (Pull-URL von der Kanal-Karte kopieren, Token einsetzen):
curl -H "Authorization: Bearer <token>" \ "https://wiki.example.com/api/v1/published/<kanal-id>/documents"Du musst deine publizierten Dokumente als JSON sehen (data: [...]). Kommt 401,
stimmt das Token nicht; kommt 403, gehört das Token zu einem anderen Kanal; ist
data leer, wurde noch nichts an diesen Kanal gesendet. Danach stempelt der Kanal
„Zuletzt abgerufen” — daran erkennst du später jederzeit, ob dein Build wirklich zieht.
2. Das Pull-Skript
Abschnitt betitelt „2. Das Pull-Skript“Lege das in dein Site-Repo als scripts/pull-orimora.mjs. Es blättert per Cursor durch
die Pull-API und schreibt src/content/docs/orimora/<slug>.md:
import { mkdir, rm, writeFile } from 'node:fs/promises';import { join } from 'node:path';
const BASE = process.env.ORIMORA_URL; // z. B. https://wiki.example.comconst CHANNEL = process.env.ORIMORA_CHANNEL; // Kanal-IDconst TOKEN = process.env.ORIMORA_TOKEN; // Kanal-Tokenconst OUT = 'src/content/docs/orimora'; // Zielverzeichnis
if (!BASE || !CHANNEL || !TOKEN) { throw new Error('ORIMORA_URL, ORIMORA_CHANNEL und ORIMORA_TOKEN setzen');}
async function pull() { const docs = []; let cursor = null; do { const url = new URL(`${BASE}/api/v1/published/${CHANNEL}/documents`); url.searchParams.set('limit', '200'); if (cursor) url.searchParams.set('cursor', cursor); const res = await fetch(url, { headers: { Authorization: `Bearer ${TOKEN}` } }); if (!res.ok) throw new Error(`Pull fehlgeschlagen: ${res.status} ${res.statusText}`); const { data, meta } = await res.json(); docs.push(...data); cursor = meta?.nextCursor ?? null; } while (cursor); return docs;}
function toMarkdownFile(doc) { // `content` ist bereits Markdown, weil das Kanal-Format "markdown" ist. // `frontmatter` enthält title + alle auf dem Kanal gemappten Felder. const fm = { title: doc.title, ...doc.frontmatter }; const yaml = Object.entries(fm) .filter(([, v]) => v !== null && v !== undefined) .map(([k, v]) => `${k}: ${JSON.stringify(v)}`) .join('\n'); return `---\n${yaml}\n---\n\n${doc.content ?? ''}`;}
const docs = await pull();await rm(OUT, { recursive: true, force: true });for (const doc of docs) { // In menschenlesbare Ordner nach Collection-Name gruppieren (statt kryptischer IDs). const dir = join(OUT, doc.collectionSlug ?? 'uncategorised'); await mkdir(dir, { recursive: true }); await writeFile(join(dir, `${doc.slug}.md`), toMarkdownFile(doc), 'utf-8');}console.log(`${docs.length} Dokument(e) aus Orimora nach ${OUT} gezogen`);3. Vor dem Build ausführen
Abschnitt betitelt „3. Vor dem Build ausführen“Als prebuild-Schritt einbinden, damit jeder Build den Inhalt aktualisiert:
{ "scripts": { "prebuild": "node scripts/pull-orimora.mjs", "build": "astro build" }}npm run build zieht jetzt zuerst, dann baut es. Auf einem Host wie
Netlify/Vercel/Cloudflare Pages setzt du ORIMORA_URL, ORIMORA_CHANNEL,
ORIMORA_TOKEN als Build-Umgebungsvariablen.
4. Rebuild automatisch auslösen
Abschnitt betitelt „4. Rebuild automatisch auslösen“Publizieren schreibt nur in Orimora — deine Seite zeigt den Inhalt erst nach dem nächsten Build. Damit das automatisch passiert, trage am Pull-Kanal die Deploy-Hook-URL deines Hosts ein (Kanal bearbeiten → Konfiguration): Orimora POSTet dann nach jedem Publizieren dorthin. Wo die URL zu finden ist und welche Plattformen unterstützt werden, steht im Publishing-Guide. Ohne Hook bleibt es beim manuellen, zeitgesteuerten oder Git-getriggerten Rebuild — der Publish-Dialog erinnert dich daran („Löse jetzt den Build aus”).
Pull-API-Referenz
Abschnitt betitelt „Pull-API-Referenz“GET /api/v1/published/{channelId}/documents — Authorization: Bearer <token>.
| Query | Bedeutung |
|---|---|
limit | 1–200 (Default 50) |
cursor | ISO-Timestamp des letzten Eintrags — Cursor-Pagination |
updatedSince | ISO-Timestamp — nur Dokumente, die danach geändert wurden |
Jeder Eintrag: id, title, emoji, slug, collectionId, collectionName,
collectionSlug (direkt als Ordnersegment nutzbar), updatedAt, publishedAt,
content (Markdown bei einem Markdown-Kanal), frontmatter. meta.nextCursor ist
null auf der letzten Seite.
Fallbeispiel: diese Doku dogfoodet sich selbst
Abschnitt betitelt „Fallbeispiel: diese Doku dogfoodet sich selbst“Der Bereich Praxistipps dieser Doku wird genau nach diesem Rezept live aus Orimora gezogen — er ist der Realitätstest des Features:
- Die Tipps werden in Orimora geschrieben und an einen Pull-Kanal („Starlight Doku”) publiziert.
docs/scripts/pull-orimora.mjsläuft vor jedemastro buildund holt das Set über die Pull-API. Env-Vars:ORIMORA_URL,ORIMORA_PRAXISTIPPS_CHANNEL,ORIMORA_PRAXISTIPPS_TOKEN— gesetzt in Coolify an der Doku-App, durchgereicht als Docker-Build-Args (siehe Hinweis oben).- Bewusst robust: Fehlen die Variablen oder ist Orimora nicht erreichbar, skippt das Skript mit Exit 0 — ein Orimora-Ausfall kann den Doku-Build nie brechen; dann bleibt der committete Platzhalter-Index stehen.
- Verifikation: Im Build-Log steht
[pull-orimora] Pulled N Praxistipp(s)(bzw. die Skip-Begründung), und der Kanal zeigt „Zuletzt abgerufen” mit dem Build-Zeitpunkt.
Siehe auch
Abschnitt betitelt „Siehe auch“- Publishing-Kanäle — Kanäle, Tokens, Transporte, Deploy-Hook
- REST-API Überblick — Auth, Rate-Limits, Pagination