====== LPM — Registry-Protokoll ======
→ [[lyx_-_programmiersprache:tools:lpm|Zurück zu LPM]]
Die öffentliche Registry läuft unter **''https://lpm.seolizer.de''**.
Sie ist bewusst als **statische** Registry entworfen: alles, was ''lpm install'' braucht, sind ''GET''-Anfragen auf gewöhnliche Dateien. Serverseitige Logik gibt es an genau einer Stelle — dem Publish-Endpunkt.
Diese Seite beschreibt das Protokoll. Wie man einen solchen Server aufsetzt, steht unter [[lyx_-_programmiersprache:tools:lpm:registry-betreiben|Eine Registry betreiben]].
----
===== URL-Layout =====
^ Pfad ^ Inhalt ^ Content-Type ^
| ''/index.json'' | Gesamtindex aller Pakete (für ''lpm search'') | ''application/json'' |
| ''/packages/<name>/index.json'' | Versionsliste eines Pakets | ''application/json'' |
| ''/packages/<name>/<version>.lxpkg'' | Paket-Archiv (''tar.zst'') | ''application/octet-stream'' |
| ''/keys/<publisher>.pub'' | Ed25519-Publisher-Key (geplant, WP-PM-10) | ''text/plain'' |
| ''/api/v1/publish'' | Upload, ''POST'', Token erforderlich | ''application/json'' |
''<name>'' ist der hierarchische Paketname und wird **unverändert** als Pfad verwendet: ''net/http'' → ''/packages/net/http/1.2.0.lxpkg''.
Erlaubt sind die Zeichen ''[a-z0-9_/.-]''. Das schließt ''..'' als Segment aus und macht die Abbildung Name → Pfad eindeutig und traversal-frei — eine Eigenschaft, auf die sich der Server verlässt, statt Pfade nachträglich zu säubern.
''<version>'' ist die exakte SemVer-Version ohne ''v''-Präfix.
----
===== Der Gesamtindex =====
''/index.json'':
{
"generated": "2026-08-08T12:00:00Z",
"packages": [
{
"name": "net/http",
"latest": "1.3.0",
"description": "HTTP client and server for Lyx",
"versions": ["1.2.0", "1.3.0"]
}
]
}
Wird lokal unter ''~/.lpm/registry/index.json'' gespiegelt, **TTL eine Stunde**. Mit ''--offline'' wird ausschließlich der Spiegel benutzt, unabhängig von seinem Alter; ''lpm update'' umgeht die Frist.
----
===== Der Paketindex =====
''/packages/<name>/index.json'':
{
"name": "net/http",
"versions": [
{
"version": "1.2.0",
"sha256": "e3b0c442...",
"source": "https://lpm.seolizer.de/packages/net/http/1.2.0.lxpkg",
"publisher": "roene",
"dependencies": { "std/io": ">=1.0.0", "std/buffer": "^2.1.0" },
"yanked": false
}
]
}
Diese Datei ist die **Auflösungsquelle** für Constraints. Dass die Dependencies hier stehen und nicht nur im Archiv, ist der Grund, warum der Resolver einen Abhängigkeitsbaum aufbauen kann, ohne ein einziges Archiv herunterzuladen.
''yanked: true'' bedeutet: **nicht mehr für neue Auflösungen wählbar, aber weiter herunterladbar**. Bestehende ''lyx.lock''-Dateien bleiben damit reproduzierbar.
----
===== Statuscodes =====
Der Client unterscheidet nur nach HTTP-Status:
^ Status ^ Bedeutung für ''lpm'' ^
| 200 | ok |
| 304 | Spiegel ist aktuell (''If-None-Match'') |
| 404 | Paket bzw. Version existiert nicht |
| 4xx sonst | Client-Fehler, Abbruch mit Meldung |
| 5xx | Registry-Fehler, Abbruch — **kein erneuter Versuch** |
----
===== Integrität =====
Der ''sha256'' aus dem Paketindex wird beim Herunterladen geprüft und in ''lyx.lock'' gepinnt.
**Der Lock-Eintrag hat immer Vorrang vor der Registry-Angabe.** Weicht ein späterer Download vom gepinnten Wert ab, bricht ''lpm'' ab und löscht die Datei, ohne sie zu entpacken. Eine Registry, die ein Archiv nachträglich austauscht, fällt damit auf — sie kann eine bestehende Auflösung nicht stillschweigend verändern.
==== Zwei Prüfungen, zwei Reichweiten ====
^ Prüfung ^ deckt ab ^ Quelle ^
| ''sha256'' aus ''lyx.lock'' | den Weg **Server → Cache** | Paketindex der Registry |
| ''FILES.sha256'' im Archiv | den Zustand **im Cache** | liegt im Paket selbst |
Die zweite kam hinzu, weil die erste an der Entpackung endet: ein Paket, das nach dem Herunterladen unter ''~/.lpm/cache'' verändert wird, war damit nicht mehr erfasst. Vor der Benutzung wird jetzt jede Datei gegen ''FILES.sha256'' abgeglichen; weicht eine ab, verwirft ''lpm'' das Verzeichnis und holt es neu — mit ''--offline'' bleibt es bei der Meldung.
Fehlt ''FILES.sha256'' — bei Paketen aus der Zeit vor ''lpm pack'' — gilt das nicht als Fehler.
**Beide Prüfsummen sichern den Transportweg und den Ablageort, nicht die Herkunft.** Wer die Registry kontrolliert, kontrolliert auch die dort hinterlegten Prüfsummen — und damit die Pakete. Und ''FILES.sha256'' liegt im selben Archiv wie die Dateien: wer beides ändern kann, ändert eben beides. Gegen versehentliches Bearbeiten im Cache und halb entpackte Pakete hilft die Liste trotzdem.
Eine Signaturprüfung (''SIGNATURE.ed25519'' gegen ''/keys/<publisher>.pub'') ist als WP-PM-10 geplant, aber nicht umgesetzt.
----
===== Anforderungen an den vhost =====
Damit das Protokoll aufgeht, muss der Webserver drei Dinge einhalten:
* **''autoindex off''** — kein Directory-Listing.
* **''index.json'' darf nicht lange gecacht werden.** ''ETag'' plus ''Cache-Control: no-cache''; sonst liefert ein vorgeschalteter CDN nach einem ''publish'' weiter den alten Index aus.
* **''.lxpkg'' ist unveränderlich** (''expires max''), wird aber **nicht** gzip-komprimiert — der Inhalt ist bereits zstd-komprimiert, eine zweite Kompression kostet nur Rechenzeit.
Einzelheiten und eine fertige Konfiguration: [[lyx_-_programmiersprache:tools:lpm:registry-betreiben|Eine Registry betreiben]].