Apps im Überblick
Eine Pithyx-App ist ein statisches Frontend, das der Daemon ausliefert, plus ein optionales Backend aus null oder mehr Containern. Beschrieben wird sie durch ein Manifest (pithyx.json), ausgeliefert als eine einzige Paketdatei. Das Frontend läuft in einem Sandbox-iframe auf dem Desktop und spricht mit der Box nur über @pithyx/sdk. Die Box baut nie etwas: Sie installiert das fertige Paket.
Frontend und Backend
Abschnitt betitelt „Frontend und Backend“- Frontend. Statische Dateien unter
/apps/<id>/..., ausgeliefert nur mitGETundHEAD. Das Manifestfeldentrynennt die HTML-Seite infrontend/. Der Desktop öffnet sie in einem Fenster. - Backend. Optional. Eine Teilmenge von Docker Compose, die der Daemon startet und die nur über den Proxy des Daemons unter
/apps/<id>/api/erreichbar ist (und unter/apps/<id>/api-<name>/für weitere Endpunkte). Es werden nie Host-Ports veröffentlicht. Eine Backend-Instanz bedient alle Benutzer; wer gerade aufruft, erfährt sie aus Headern, die der Proxy setzt. Siehe Backends. - Kein Backend. Eine App ohne den Schlüssel
backendläuft nur im Browser. Der Installationsdialog weist darauf hin. - Reservierte Pfade. Ein Frontend-Pfad, dessen erstes Segment
apiist oder mitapi-beginnt, gehört dem Backend und liefert für Dateien 404. - Icon. Immer
icon.svgim Wurzelverzeichnis des Pakets (kein Manifestfeld), ausgeliefert unter/api/apps/{id}/icon. Höchstens 64 KB, ein gültiges SVG mit quadratischer viewBox und ohne Skripte,foreignObject, Bilder oder iframes.
Pithyx unterstützt keine Web-Apps mit eigenem Port, keine Apps, die mit anderen Apps sprechen, keine Desktop-Widgets und keinen App-Code ohne Fenster. Ein Backend ist der einzige Code, der ohne Fenster läuft.
Die Sandbox
Abschnitt betitelt „Die Sandbox“Eine App von Drittanbietern läuft in <iframe sandbox="allow-scripts allow-forms"> auf demselben Host wie der Desktop, ohne allow-same-origin. Die App hat einen opaken Origin, bekommt keine Cookies und kann localStorage oder IndexedDB nicht sinnvoll nutzen. Daten speichert sie über das SDK (app.storage), Dateien über app.files.
Der Daemon hängt diese Header an jede Antwort unter /apps/<id>/, auch an 404 und an Antworten des Backends über den Proxy (Frontend-Dateien bekommen außerdem Cache-Control, siehe unten):
Content-Security-Policy: sandbox allow-scripts allow-forms; default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; media-src 'self' data: blob:; worker-src 'self' blob:; object-src 'none'; base-uri 'none'; form-action 'self'; frame-ancestors 'self'; connect-src 'self'X-Content-Type-Options: nosniffAccess-Control-Allow-Origin: *Referrer-Policy: no-referrerMit der Berechtigung network.internet endet die Richtlinie auf connect-src 'self' https:. Daraus folgt:
- Keine Inline-Skripte und keine Skripte von einem CDN. Inline-Styles sind erlaubt.
- Bilder, Schriften und Medien kommen von der App selbst oder aus
data:- undblob:-URLs, auch mit der Internet-Berechtigung. - Aufrufe an andere Server (
fetch, WebSocket) nur mitnetwork.internet.
pithyx dev liefert dieselbe Richtlinie aus, sodass eine blockierte Anfrage schon während der Entwicklung auffällt.
Frontend-Dateien sind so öffentlich wie die eigenen Dateien des Desktops; der Zugriff wird entschieden, wenn das Fenster seine Tokens bekommt. Berechtigungen prüft der Daemon bei jedem Aufruf.
Kompression und Caching
Abschnitt betitelt „Kompression und Caching“Beim Installieren schreibt die Box von jeder Textdatei des Frontends ab 1 KB (JavaScript, CSS, HTML, JSON, Source Maps, SVG, Text, XML, WebAssembly) eine Brotli- und eine gzip-Kopie und liefert die Kopie aus, die der Browser annimmt, mit Content-Encoding und Vary: Accept-Encoding. Sie komprimiert nur, was im Paket steht; gebaut wird auf der Box nie.
Eine Datei unter assets/, deren Name auf einen Build-Hash endet, wie Vite ihn schreibt (assets/index-B4kz_x9Q.js: ein Bindestrich, acht Zeichen aus Buchstaben, Ziffern, _ oder -, mindestens eines davon kein Kleinbuchstabe), bekommt Cache-Control: public, max-age=31536000, immutable; alle anderen Dateien behalten no-cache. Der Browser behält gehashte Dateien über Fenster und Neuladen hinweg, prüft no-cache-Dateien eines Sandbox-Fensters aber nicht neu, deshalb laden diese mit jedem Fenster neu. Also:
- Behalte unter
assets/die Standard-Dateinamen von Vite; alles, was die Einstiegsseite lädt, sollte gehasht sein. - Lege unter
assets/nie eine Datei ab, deren Name wie ein Hash aussieht, deren Inhalt sich aber zwischen Versionen ändert: Nutzer würden die alte Datei ein Jahr lang behalten. - Halte die Einstiegsseite klein; sie lädt mit jedem Fenster.
App-IDs
Abschnitt betitelt „App-IDs“Eine ID besteht aus der umgekehrten Domain des Autors plus dem App-Namen, drei bis fünf Teile, zum Beispiel com.mueller.chat oder io.github.jan.chat.
- Jeder Teil nutzt Kleinbuchstaben, Ziffern und Bindestriche; der erste Teil beginnt mit einem Buchstaben. Die ganze ID hat höchstens 100 Zeichen. Muster:
^[a-z][a-z0-9-]*(\.[a-z0-9][a-z0-9-]*){2,4}$. org.pithyx.*ist für System-Apps und den offiziellen Katalog reserviert. Die Box lehnt es für ein per Sideload installiertes Paket ab (app.manifest.id_reserved).- Eine ungültige ID ergibt
app.manifest.id_invalid. - IDs sind auf einer Box eindeutig.
Das Paket
Abschnitt betitelt „Das Paket“Ein Paket heißt <id>-<version>.pithyxapp. Es ist ein gzip-komprimiertes tar-Archiv und deterministisch: Dieselben Dateien ergeben dieselben Bytes (Manifest zuerst, Icon als Zweites, der Rest sortiert, feste Rechte, fester Besitzer und feste Zeiten). Es enthält:
pithyx.jsonundicon.svg,frontend/mit dem gebauten Frontend,- optional
backend/compose.yamlundbackend/images.lock.jsonsowiebackend/images/<arch>/<config digest>.tarfür Offline-Installationen (benannt nach dem Digest der Image-Konfiguration, der im klassischen Image-Store von Docker die Image-ID ist, nicht nach dem Manifest-Digest, dencompose.yamlfestlegt), - die Dateien README und LICENSE, falls vorhanden,
CHECKSUMSim Format vonsha256sum -c.
Pfadregeln: relative Pfade mit /, ASCII-Buchstaben, Ziffern und ._~@+-, kein leeres Segment und kein Segment, das mit einem Punkt beginnt, höchstens 512 Zeichen pro Pfad, 255 pro Segment und 32 Segmente. Namen, die sich nur in der Groß- und Kleinschreibung unterscheiden, werden abgelehnt.
Grenzen beim Hochladen eines Pakets auf eine Box: 256 MB für die Datei, 512 MB entpackt, 10.000 Einträge und 64 KB für pithyx.json. Nur ein Administrator kann hochladen (PUT /api/apps/packages, 15 Minuten aufbewahrt) und dann installieren. Ein aus einer Datei installiertes Paket wird als Sideload markiert und als nicht geprüft angezeigt.
Pakete baust du mit dem Kommandozeilenwerkzeug: siehe @pithyx/cli und Deine erste App.
SDK-Leitfäden
Abschnitt betitelt „SDK-Leitfäden“Wie ein Frontend mit der Box arbeitet, Aufgabe für Aufgabe: