Zum Inhalt springen

Statische Seiten via Pull-API (Starlight, Astro, Hugo …)

Orimora kann die Inhaltsquelle einer statischen Seite sein, ohne einen Git-Mirror dazwischen. Die Seite zieht die veröffentlichten Dokumente eines freigegebenen Ordners zur Build-Zeit aus Orimoras token-gesicherter Pull-API und rendert sie — Orimora bleibt die einzige Quelle der Wahrheit, und es gibt kein separates Inhalts-Repository zu pflegen.

Das funktioniert mit jedem Generator, der Markdown + Frontmatter liest (Astro/Starlight, Hugo, Jekyll, Eleventy, …). Das Beispiel nutzt Starlight.

  1. Du legst in Orimora eine Ordnerfreigabe für eine Collection an. Sie erzeugt ein nur-lesendes, nur-veröffentlichtes Token, das genau auf diesen Ordner beschränkt ist — nur dessen veröffentlichte Dokumente werden je sichtbar (kein Entwurfs-Leak).
  2. Ein kleines Pull-Skript läuft vor jedem Build, holt den veröffentlichten Satz als Markdown aus der Pull-API und schreibt eine Markdown-Datei pro Dokument.
  3. Der Generator baut wie gewohnt aus diesen Dateien.

Dieses Rezept gilt für statische Generatoren (SSG: Starlight, Hugo, Jekyll, Eleventy …) — sie übernehmen Inhalte nur zur Build-Zeit, weshalb ein Pull-Skript und ein Rebuild-Auslöser nötig sind.

Server-gerenderte Apps (SSR/ISR — Next.js, Nuxt, SvelteKit …) brauchen dieses Rezept nicht. Sie rufen die Pull-API einfach zur Request-Zeit auf (mit Cache davor) — kein Build, kein Hook, Veröffentlichung ist sofort live. Die API unterstützt updatedSince für inkrementelle Abrufe.

  1. Öffne in der Seitenleiste das Menü einer Collection (Kebab oder Rechtsklick) und wähle „Mit Dienst verbinden…”. (Benötigt die Capability collection.share — standardmäßig nur für Admins.)
  2. Wähle den Zieltyp Statische Website (SSG) und erstelle die Freigabe. Orimora erzeugt ein Lese-Token und zeigt es einmalig — jetzt kopieren und wie ein Passwort aufbewahren. Der Dialog zeigt auch den API-Endpunkt.
  3. Notiere die Collection-ID (steht in der Collection-URL) — das Pull-Skript filtert darauf.

Du hast nun drei Werte für das Skript: die Orimora-Basis-URL, die Collection-ID und das Token.

Bevor Du irgendetwas baust, teste die Kette mit curl:

Terminal-Fenster
curl -H "Authorization: Bearer <token>" \
"https://wiki.example.com/api/v1/documents?collectionId=<collection-id>&format=markdown"

Du musst die veröffentlichten Dokumente des Ordners als JSON sehen (data: [...]), jeweils mit einem markdownText-Body und einem slug. Ein 401 heißt, das Token ist falsch; ein 403, dass das Token nicht auf diese Collection beschränkt ist; ein leeres data, dass der Ordner noch keine veröffentlichten Dokumente hat (Entwürfe erscheinen nie).

Lege das als scripts/pull-orimora.mjs in Dein Seiten-Repo. Es blättert (offset-basiert) durch die Pull-API und schreibt src/content/docs/orimora/<slug>.md:

scripts/pull-orimora.mjs
import { mkdir, rm, writeFile } from 'node:fs/promises';
import { join } from 'node:path';
const BASE = process.env.ORIMORA_URL; // z. B. https://wiki.example.com
const COLLECTION = process.env.ORIMORA_COLLECTION; // Collection-ID
const TOKEN = process.env.ORIMORA_TOKEN; // Ordnerfreigabe-Token (kb_…)
const OUT = 'src/content/docs/orimora'; // Zielverzeichnis
const PAGE = 200;
if (!BASE || !COLLECTION || !TOKEN) {
throw new Error('ORIMORA_URL, ORIMORA_COLLECTION und ORIMORA_TOKEN setzen');
}
async function pull() {
const docs = [];
let offset = 0;
let total = Infinity;
do {
const url = new URL(`${BASE}/api/v1/documents`);
url.searchParams.set('collectionId', COLLECTION);
url.searchParams.set('format', 'markdown');
url.searchParams.set('limit', String(PAGE));
url.searchParams.set('offset', String(offset));
const res = await fetch(url, { headers: { Authorization: `Bearer ${TOKEN}` } });
if (!res.ok) throw new Error(`Pull fehlgeschlagen: ${res.status} ${res.statusText}`);
const { data, total: t } = await res.json();
docs.push(...data);
total = typeof t === 'number' ? t : docs.length;
offset += PAGE;
} while (docs.length < total && offset < total);
return docs;
}
function toMarkdownFile(doc) {
// `markdownText` ist der serialisierte Body (?format=markdown). Nur der Titel
// wandert als Frontmatter — Starlights docsSchema verlangt ihn.
const fm = { title: doc.title };
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.markdownText ?? ''}`;
}
const docs = await pull();
await rm(OUT, { recursive: true, force: true });
await mkdir(OUT, { recursive: true });
for (const doc of docs) {
await writeFile(join(OUT, `${doc.slug}.md`), toMarkdownFile(doc), 'utf-8');
}
console.log(`${docs.length} Dokument(e) aus Orimora nach ${OUT} gezogen`);

Als prebuild-Schritt verdrahten, damit jeder Build die Inhalte auffrischt:

package.json
{
"scripts": {
"prebuild": "node scripts/pull-orimora.mjs",
"build": "astro build"
}
}

npm run build zieht jetzt erst, dann baut es. Auf einem Host wie Netlify/Vercel/Cloudflare Pages ORIMORA_URL, ORIMORA_COLLECTION, ORIMORA_TOKEN als Build-Umgebungsvariablen setzen.

Veröffentlichen schreibt nur nach Orimora — eine statische Seite zeigt den Inhalt erst nach dem nächsten Build. Löse ihn über Deinen Host aus: geplanter Build, manueller Deploy oder ein Git-Push. (Automatischer Rebuild-bei-Veröffentlichung für Ordnerfreigaben ist geplant.) Bei SSR/ISR-Apps stellt sich die Frage nicht — sie lesen die Pull-API live.

GET /api/v1/documentsAuthorization: Bearer <token>.

QueryBedeutung
collectionIdAuf einen Ordner filtern (die Collection der Freigabe)
formatmarkdownmarkdownText-Body + abgeleiteten slug ergänzen
limit1–100 (Default 25)
offsetOffset-Paginierung; die Antwort trägt total
updatedSinceISO-Zeitstempel — nur Dokumente, die danach geändert wurden

Jedes Element: id, title, emoji, collectionId, collectionName, collectionSlug, updatedAt, publishedAt, tags und — mit ?format=markdownslug und markdownText. Ein nur-veröffentlicht-Token einer Freigabe liefert unabhängig von einem status-Parameter nur veröffentlichte Dokumente.

Der Praxistipps-Bereich genau dieser Doku wird live aus Orimora gezogen — mit exakt diesem Rezept, als Realitätscheck des Features:

  • Die Tipps liegen in einer Praxistipps-Collection in Orimora, bereitgestellt über eine Ordnerfreigabe (nur-lesend, nur-veröffentlicht).
  • docs/scripts/pull-orimora.mjs läuft vor jedem astro build und holt den Satz über die Pull-API. Env-Vars: ORIMORA_URL, ORIMORA_PRAXISTIPPS_COLLECTION, ORIMORA_PRAXISTIPPS_TOKEN — in Coolify auf der Docs-App gesetzt und als Docker-Build-Args durchgereicht (siehe Hinweis oben).
  • Bewusst robust: Fehlen die Variablen oder ist Orimora nicht erreichbar, überspringt das Skript mit Exit 0 — ein Orimora-Ausfall kann den Doku-Build nie brechen; der committete Platzhalter-Index bleibt stehen.
  • Verifikation: Im Build-Log steht [pull-orimora] Pulled N Praxistipp(s) (bzw. die Skip-Begründung).
  • REST-API Überblick — Auth, Rate-Limits, Pagination
  • WordPress — denselben Ordner stattdessen nach WordPress importieren
  • Kirby — dasselbe Pull-Muster für Kirby
  • Git-Mirror — einen Ordner in ein Git-Repo pushen (statt dass die Seite zieht)