🛩️ OxiCloud v0.8.0 — "Airframe"
0.7.0 "Slipstream" taught OxiCloud to move. 0.8.0 "Airframe" rebuilt the thing it moves in.
The entire frontend — every screen, every interaction — was torn out and rebuilt from scratch in SvelteKit. Photos learned where your pictures were taken and who's in them. A plugin runtime opened the door to extending OxiCloud safely. And the upload path was hardened, again and again, until it stopped flinching at anything you throw at it — even named pipes.
This is the airframe release. New skin, new bones, same engine — and a platform that's ready to grow.
Self-hosted. No vendor. No telemetry. Just your data, in a cockpit that was rebuilt around it.
✨ Headline features
🧩 A brand-new frontend — rewritten in SvelteKit (Svelte 5)
The vanilla-JS/CSS app that carried OxiCloud through six releases is gone. The whole UI is now a SvelteKit single-page app — Svelte 5 runes + TypeScript, Vite, adapter-static:
- Type-safe end to end, code-split and lazy-loaded so the initial bundle is small.
- An in-memory listing cache, virtualization, and badge batching so big folders paint instantly.
- A unified API layer (
lib/api/endpoints/*), reactive rune stores, and a bespoke i18n that reads the same locale files. - The legacy
/staticapp and its tooling were removed entirely.
(#478, #486, #492, #506, #509)
📍 Photos: Places & People
Your library now knows geography and faces:
- Places — a map view that plots photos by their real capture location, with EXIF GPS recovery via
nom-exifwhen the primary parser rejects a file, and a lightweight world map fallback when no basemap is installed. - People — face grouping, paired with a gallery/lightbox polish pass.
🧩 WASM plugin system (M0)
The first milestone of an extensibility story: sandboxed, observe-only plugins compiled to WebAssembly, with the CI plumbing (check/clippy/test) to keep them honest. Huge thanks to @BCNelson. (#475, #459)
🗂️ Drives
Groundwork for multiple drives: ReBAC moved into a role-centric model, drives surfaced in the sidebar, and the UI wired to the new shape. (#465, #479, #507)
⬆️ Uploads that don't flinch
The upload path was hardened relentlessly this cycle:
- Batch dedup-check + instant by-hash uploads — content the server already has uploads with zero bytes on the wire; one request resolves a whole folder.
- Idempotent re-upload + auto-retry — a partially-uploaded folder self-completes, and re-uploading byte-identical content is a clean no-op instead of a wall of "already exists" errors.
- Self-aborting watchdog + bounded delta-worker connections — no more stalls or browser connection-pool exhaustion that froze big folder uploads at "93%".
- Skips non-regular files (FIFOs / sockets / devices) up front — a copied service tree full of named pipes no longer hangs a lane; you get "N uploaded · M skipped (not regular files)".
- Drag-out-to-OS download + folder drag-drop upload.
- Version auto-reload — an open tab notices a fresh deploy (
_app/version.jsonpolling) and reloads itself, so it never runs stale code after a rebuild.
(#500, #502, #503, plus the upload-hardening sweep on main)
🏎️ Performance
- Folder listing: in-memory cache + virtualization + badge batching so navigation is instant (#492).
- Lazy-loaded heavy components shrink the initial bundle (#506).
- Cache-stampede coalescing (single-flight) on content/transcode/search caches + DB pool safeguards (statement timeout + saturation monitor) (#508).
- Six measured backend optimizations — downloads, CDC reads, content cache, write path (#462).
- Batched resource resolution + live-role re-validation on every request (#484).
🔒 Reliability & security
- CalDAV / CardDAV client connectivity repaired (#481).
- Blob GC hardened and the content-index worker supervised so it restarts cleanly (#483).
- The SPA and the Places map boot under a strict CSP —
script-src 'self'+ per-inline-script SHA-256 hashes +'wasm-unsafe-eval'for the BLAKE3/FastCDC and map WASM (#495). - OIDC providers can be trusted via system certificates (#490, thanks @fkocik).
- The container starts cleanly for non-root users (#474, thanks @Cilenco).
- NextCloud login page migrated from
build.rsto askama templates (#493). - 5 deprecated list endpoints removed, superseded by the cursor-paginated
/resourcesfeed (#501). /by-hashworks even when the source blob is trashed (#472); i18n locale dir honoursOXICLOUD_STATIC_PATH(#468); a sweep of NextCloud/WebDAV bugs found by end-to-end tests (#473).
✅ Tests & CI
End-to-end WebDAV + NextCloud coverage (#450), expanded API tests (#452), a load & benchmark harness (#451), WASM check/clippy/test in CI (#459), front-end test cleanup (#460), and HTTP-log diagnostics targets (#449).
⚙️ Upgrade notes
- Requires Rust 1.93+ (edition 2024) and PostgreSQL 13+ with
pg_trgmandltree. Migrations apply automatically on startup. - The frontend is now SvelteKit, built by Vite into
static-dist/and served by the Rust web layer (unmatched client routes fall back to the SPA shell). The legacy/staticapp is gone. - Strict CSP is on by default (
script-src 'self'+ per-script hashes +'wasm-unsafe-eval'); any custom inline scripts you injected will be blocked — add a hash or move them to a file. - New surface: an observe-only WASM plugin runtime and multi-drive groundwork.
💛 Thank you — built by the community, again
Edouard Vanbelle (@EdouardVanbelle) — 56 commits this cycle. The Drives foundation and the ReBAC→role-centric move, the end-to-end WebDAV/NextCloud test suite that flushed out a pile of real bugs, the i18n and UI fixes, and relentless polish. Still, simply, a crack. 👑
Bradley Nelson (@BCNelson) — a spectacular first cycle: he kicked off the SvelteKit rewrite and built the sandboxed WASM plugin system (M0). Two of this release's pillars are his. Welcome, and thank you. 🙌
And huge thanks to:
- @Cilenco — non-root container startup (#474).
- @fkocik — system-certificate trust for OIDC providers (#490).
New Contributors
To every self-hoster running OxiCloud on a box in a closet: this one was rebuilt around you. ❤️
Full Changelog: v0.7.0...v0.8.0
What's Changed
- chore(logs): add specific target for HTTP logs to help diagnostics by @EdouardVanbelle in #449
- fix(i18n): locale dir based on OXICLOUD_STATIC_PATH by @EdouardVanbelle in #468
- refactor/ui: fix js types + correct owner display by @EdouardVanbelle in #471
- feat(by-hash): allow /by-hash even if blob is trashed by @EdouardVanbelle in #472
- fix(docker) Fix start up for non root users by @Cilenco in #474
- Add M0 WASM plugin system (sandboxed, observe-only) by @BCNelson in #475
- fix(nextcloud+webdav) fix bugs found via end to end tests by @EdouardVanbelle in #473
- Fix broken CI by @EdouardVanbelle in #477
- feat(drive): prepare drive implementation: move ReBAC into Role centric by @EdouardVanbelle in #465
- test/prepare load and benchmark test by @EdouardVanbelle in #451
- fix(dav): repair CalDAV/CardDAV client connectivity (#480) by @DioCrafts in #481
- Harden blob GC and supervise the content-index worker by @DioCrafts in #483
- Batch resource resolution and live-role re-validation on every request by @DioCrafts in #484
- feat: Photos evolution — Places (map) & People (faces) + gallery polish by @DioCrafts in #485
- Rewrite frontend in SvelteKit — updated to main, with Places/People/Photos ported by @DioCrafts in #486
- Rewrite frontend in SvelteKit (Svelte 5) by @BCNelson in #478
- docs(claude): describe the SvelteKit frontend in CLAUDE.md by @DioCrafts in #487
- Optimize folder listing with caching, virtualization, and badge batching by @DioCrafts in #492
- Allow the use of system certificates to trust OIDC provider by @fkocik in #490
- feat/drive impl by @EdouardVanbelle in #479
- Migrate Nextcloud login page from build.rs to askama templates by @DioCrafts in #493
- fix: make the SPA boot and Places map work under strict CSP by @DioCrafts in #495
- fix(ui): remove default link underline from sidebar nav items by @DioCrafts in #496
- fix(photos): recover EXIF GPS via nom-exif when kamadak-exif rejects the file by @DioCrafts in #497
- feat(photos): show a lightweight world map in Places when no basemap is installed by @DioCrafts in #499
- feat(files): drag-out-to-OS download + folder drag-drop upload (#500) by @DioCrafts in #504
- feat(shares): external-user vignette — avatar, email & internal/external badge (#500) by @DioCrafts in #503
- feat(files): bookmarkable file-preview URL + multi-drag count ghost (#500) by @DioCrafts in #502
- refactor(api): remove 5 deprecated list endpoints superseded by /resources by @DioCrafts in #501
- fix(sidebar): key nav icon colours off data-section, not DOM order by @DioCrafts in #505
- perf(frontend): lazy-load heavy components to shrink initial bundle by @DioCrafts in #506
- feat(drive): add drive in side bar + correct some glitch with new UI: by @EdouardVanbelle in #507
- perf: cache-stampede coalescing + DB safeguards; ui/i18n fixes by @DioCrafts in #508
- chore(frontend): remove the legacy vanilla-JS frontend and its tooling by @DioCrafts in #509
New Contributors
Full Changelog: v0.7.0...v0.8.0