====== 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]].