feat: F6.1 FILIUS files on F: projects from examples and .fls, copies, export

/svc/examples lists FILIUS' examples, which lie beside F in the image (GPL
like this repository, kept out of the dashboard); /svc/projects makes a
project from one; /svc/projects/<id>/import takes a .fls (up to 64 MiB),
/copy copies a project as it is now, /export gives it back as a .fls with its
warnings. Large files go into the blob store on import and come back from it
on export, which is refused when one is missing.

Found on the way: Node's request body is a Buffer, and Yjs takes no Buffer
into a document, so every .fls with binary files would have failed; and
fflate, now in the bundle, imports createRequire itself, which the build's
banner declared again, so F did not start. The banner names it otherwise and
a test builds and starts the bundle. The proxy's /svc/ takes 70 MB.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-10 07:55:11 +00:00
co-authored by Claude Opus 5.5
parent 5fa590246c
commit fb1a467221
14 changed files with 503 additions and 26 deletions
+1
View File
@@ -286,6 +286,7 @@ Swift-Pfade relativ zu `filius-ipad/ios/FiliusPad/TopologyEditor/` (Stand
| `src/blobs.ts`, `src/blobRoutes.ts`, `src/simWorker.ts` (Blobs), `src/simRooms.ts` (Blobs), `src/simChannel.ts`, `src/server.ts` (`/blobs`), `src/main.ts`, `test/blobs.test.ts` | Plan §5.1 | neu (F5.5): die Blobs auf F, inhaltsadressiert (`filius_blob`, F rechnet den Namen selbst aus); `GET /blobs/<sha>?project=` mit Berechtigung am Projekt, `POST /blobs?project=` mit Schreibstufe, nicht eingefroren, nur von der Herkunft des Editors, höchstens 16 MiB; CORS für die Herkünfte des Editors; der Raumfaden fragt nach den Blobs seines Dokuments, ein Start wartet auf die gefragten, was F noch nicht hat, wird ein paar Mal neu gefragt und kommt in die laufende Simulation; ein Blob, den die Simulation macht, wird gespeichert, bevor die Änderung, die ihn nennt, angewandt wird. Noch nicht: Blobs vergessen, die kein Projekt mehr nennt |
| `src/editorFiles.ts`, `src/precompress.ts`, `src/precompressMain.ts`, `src/server.ts` (Editor), `src/main.ts` (`FILIUS_EDITOR_DIR`), `test/editorFiles.test.ts`, `editor/browser/fromF.spec.ts` | Plan §8.2, §8.3 | neu (F5.6b): F liefert die Seite und das Bundle des Editors selbst aus (Ordner `editor/` neben `main.mjs`), damit der Editor von Fs Herkunft kommt und sie als seinen Server nimmt; nur GET und HEAD, nur Dateien im Ordner (jedes `..`, auch kodiert, wird aufgelöst und außerhalb abgewiesen); Fs eigene Wege gehen vor; `assets/` (Vite benennt nach dem Inhalt) ein Jahr im Cache, alles andere jedes Mal neu gefragt; der Build legt `.br` und `.gz` daneben, wo sie kleiner sind, F schickt die bessere, die der Browser nimmt (das Bundle 695 KB → 212 KB mit brotli). Ohne Ordner beantwortet F nur seine Wege und meldet es im Protokoll |
| `src/ticket.ts` (`TICKET_AHEAD_SECONDS`), `test/ticket.test.ts`, `tools/ticket-oracle` (zwei Fälle) | itsdangerous 2.2.0 `TimestampSigner.unsign` | geändert (F5.6c): eine Karte darf bis zu 5 s vor Fs Uhr signiert sein — itsdangerous lehnt schon eine Sekunde ab. Gemessen auf test-filius: Fs Uhr 886 ms hinter der des Dashboard-Rechners wies fast neun von zehn Karten ab, mit NTP 8 ms noch eine von 125 (eine Karte trägt ganze Sekunden). Das Orakel hält fest, dass Python die Karten 1 s und 5 s voraus ablehnt und 6 s voraus wie F |
| `src/transfer.ts`, `src/service.ts` (Beispiele, Import, Kopie, Export), `src/server.ts`, `src/main.ts` (`FILIUS_EXAMPLES_DIR`), `test/transfer.test.ts`, `test/bundle.test.ts`, `package.json` (Banner) | Plan §11, F6 | neu (F6.1): FILIUS-Dateien über den Dienstweg — `GET /svc/examples` (die Java-Beispiele liegen neben F im Image, GPL wie dieses Repo, nicht im Dashboard), `POST /svc/projects` mit `example`, `POST /svc/projects/<id>/import` (die `.fls` als Rumpf, höchstens 64 MiB), `POST /svc/projects/<id>/copy` (der Stand jetzt, auch während jemand arbeitet), `GET /svc/projects/<id>/export` (die `.fls`, Warnungen in `X-Filius-Warnings` als base64url-JSON); große Dateien gehen beim Import zuerst in den Blob-Speicher, der Export nimmt ihre Bytes von dort und wird ohne sie nicht gemacht. **Fehler vorher gefunden:** der Rumpf einer Anfrage ist in Node ein `Buffer`, die Dateien einer `.fls` wären Stücke davon, und Yjs nimmt keinen `Buffer` ins Dokument — jede `.fls` mit Binärdateien wäre gescheitert. **Und beim Bau des Image:** `fflate` (über `fls` jetzt im Bundle) importiert `createRequire` selbst, das Banner des Builds deklarierte es ein zweites Mal — F startete nicht; das Banner nennt es jetzt anders, ein Test baut und startet den Bundle |
| `test/editorConnection.test.ts` | — | neu (F5.3b), erweitert (F5.4: Identität von F, die anderen über die Awareness, auch eine lesende Person, weg mit dem Schließen): `connectSharedDoc` des Editors gegen einen echten F — bereit mit Schreib- und Lesestufe, eingefroren und aufgetaut (neues Dokument, die verirrte Änderung ist weg, Schreiben geht wieder), eingefroren von Beginn an, Absage, Widerruf, Löschen, Loslassen |
| `test/sim.test.ts`, `test/harness.ts` (Faden) | — | neu (F5.3a): echte Sockets, der echte Faden (esbuild bündelt ihn wie der Build), Beispiel internetwork_komplett: ein Start für alle mit Namen, Ping in einer Befehlszeile bei der anderen, Zurückschreiben ins Dokument und eine Datei aus dem Dokument im Raum, Lesestufe, Absagen, Nachlauf, Einfrieren, Löschen, Widerruf, Wahl des Fadens, scheiternder Faden, Herunterfahren, Ping |
| `test/ticket.test.ts`, `test/tickets.ts`, `test/tickets.python.json` | `tools/ticket-oracle` | neu (F5.2): jede Karte des Python-Orakels liest Node wie Python (Nutzlast oder derselbe Grund der Ablehnung); in Node signierte Karten tragen dasselbe JSON zum selben Zeitpunkt (Nodes zlib packt anders, ungepackt byte-gleich); die Ansprüche |