From 2e6fa3cdc62d0670863bf98ab3f02d5ca64a27bb Mon Sep 17 00:00:00 2001
From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com>
Date: Sun, 15 Mar 2026 19:16:48 +0100
Subject: [PATCH] feat: optimize profile image sizes, silent PWA updates,
storage cleanup fixes
- Resize avatars/icons to 256px and banners to 1280px (client crop + server safety net)
- Add server-side resizeProfileImage() for federation/API uploads without crop modal
- Fix unconstrained crop on RegisterPage and CreateSpace (was missing maxOutputDimension)
- PWA: switch to autoUpdate with skipWaiting/clientsClaim for seamless deploys
- Storage janitor: exclude profile images from unlinked cleanup, delete stale thumbnails
- Add deleteAttachmentByFilename() to clean orphaned attachment records for profile images
- Migration: one-time cleanup of stale profile image attachment records
- GeneralPanel: wrap in
);
}
diff --git a/packages/web/src/components/modals/settingsPanels/AccountPanel.tsx b/packages/web/src/components/modals/settingsPanels/AccountPanel.tsx
index 57bbe70d..a3c96ba8 100644
--- a/packages/web/src/components/modals/settingsPanels/AccountPanel.tsx
+++ b/packages/web/src/components/modals/settingsPanels/AccountPanel.tsx
@@ -741,7 +741,7 @@ export function AccountPanel() {
title="Crop Avatar"
cropShape="round"
aspectRatio={1}
- maxOutputDimension={512}
+ maxOutputDimension={256}
/>
>
);
diff --git a/packages/web/src/components/ui/SwUpdatePrompt.tsx b/packages/web/src/components/ui/SwUpdatePrompt.tsx
index 0357ddf6..ce72576f 100644
--- a/packages/web/src/components/ui/SwUpdatePrompt.tsx
+++ b/packages/web/src/components/ui/SwUpdatePrompt.tsx
@@ -1,22 +1,22 @@
import { useRegisterSW } from 'virtual:pwa-register/react';
+import { useEffect } from 'react';
-export function SwUpdatePrompt() {
- const {
- needRefresh: [needRefresh],
- updateServiceWorker,
- } = useRegisterSW();
+export function SwAutoUpdate() {
+ useRegisterSW({
+ onRegisteredSW(_swUrl, registration) {
+ if (!registration) return;
+ setInterval(() => {
+ registration.update();
+ }, 60_000);
+ },
+ });
- if (!needRefresh) return null;
+ useEffect(() => {
+ if (!navigator.serviceWorker) return;
+ const onControllerChange = () => window.location.reload();
+ navigator.serviceWorker.addEventListener('controllerchange', onControllerChange);
+ return () => navigator.serviceWorker.removeEventListener('controllerchange', onControllerChange);
+ }, []);
- return (
-
- A new version is available
-
-
- );
+ return null;
}
diff --git a/packages/web/vite.config.ts b/packages/web/vite.config.ts
index 2660fed2..3b288d06 100644
--- a/packages/web/vite.config.ts
+++ b/packages/web/vite.config.ts
@@ -8,7 +8,7 @@ export default defineConfig({
plugins: [
react(),
VitePWA({
- registerType: 'prompt',
+ registerType: 'autoUpdate',
includeAssets: ['icons/favicon-32.png', 'icons/favicon-16.png', 'icons/apple-touch-icon.png'],
manifest: {
name: 'Backspace',
@@ -27,6 +27,9 @@ export default defineConfig({
workbox: {
navigateFallback: '/index.html',
navigateFallbackDenylist: [/^\/api/, /^\/ws/, /^\/uploads/],
+ skipWaiting: true,
+ clientsClaim: true,
+ cleanupOutdatedCaches: true,
},
}),
],