feat(content): owned-content persistence + Fedimint paid downloads, fmcd caps fix, FIPS warm-path perf

Buyer-side paid downloads now persist: purchases are cached on disk
(content_owned.rs) keyed by (seller onion, content_id), the gallery shows
an "Owned" badge unblurred, and items view/play in-app from the local
cache with no re-payment or reliance on a browser download (which
silently failed on the mobile companion). New RPCs content.owned-list /
content.owned-get. Validated e2e .116<-.198 (paid 100 sats via Fedimint,
166KB jpeg returns, survives restart).

fedimint-clientd manifest: restore the standard container capability set
(CHOWN/DAC_OVERRIDE/FOWNER/SETUID/SETGID) so fmcd's startup chown of an
existing-federation /data succeeds instead of dying EPERM (#7). Confirmed
the orchestrator applies these to the running container.

FIPS perf: tighten the supervisor warm-path keepalive 45s -> 25s so peer
paths stay inside the ~30-60s NAT cold window. Dials now reliably land on
FIPS instead of re-punching and falling back to Tor. Measured to the same
peer: cloud browse 18-22s -> 0.4s; full Fedimint paid download 29s -> 11s
(residual is the seller-side guardian reissue round-trip).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-06-20 18:58:52 -04:00
co-authored by Claude Opus 4.8
parent b0c9bd2a0c
commit db7d424bff
12 changed files with 544 additions and 26 deletions
+17
View File
@@ -413,4 +413,21 @@ router.afterEach((to) => {
}
})
// A route whose lazy-loaded component chunk 404s (stale index after a deploy)
// rejects through router.onError rather than window.unhandledrejection. Reload
// once so the browser fetches the fresh index + chunk map; the sessionStorage
// guard (10s) prevents a reload loop if the chunk is genuinely broken.
router.onError((err) => {
const msg = (err as { message?: string })?.message ?? String(err ?? '')
if (!/Failed to fetch dynamically imported module|error loading dynamically imported module|Importing a module script failed|ChunkLoadError|dynamically imported module/i.test(msg)) {
return
}
try {
const KEY = 'archy-chunk-reload-at'
if (Date.now() - Number(sessionStorage.getItem(KEY) || '0') < 10_000) return
sessionStorage.setItem(KEY, String(Date.now()))
} catch { /* sessionStorage unavailable — reload anyway */ }
location.reload()
})
export default router