Record that downloads fill the Cache and ship the built app.

A failed open can repair the shell, and the installed PWA matches Ziele, Einstellungen, and the view download.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-09 08:55:43 +02:00
co-authored by Cursor
parent 2f1fab202e
commit 3a49d52681
36 changed files with 1801 additions and 24 deletions
+81
View File
@@ -0,0 +1,81 @@
import { kachelCacheName } from "./cache-storage";
const SHELL_REPAIR_TRIED = "karte-shell-repaired";
export type BootRepairPorts = {
registrations(): Promise<ReadonlyArray<{ unregister(): Promise<boolean> }>>;
cacheNames(): Promise<string[]>;
deleteCache(name: string): Promise<boolean>;
};
type FlagStore = {
getItem(key: string): string | null;
setItem(key: string, value: string): void;
removeItem(key: string): void;
};
/** Drop the installed app shell. Kacheln stay in their own cache. */
export async function repairAppShell(ports: BootRepairPorts): Promise<void> {
const registrations = await ports.registrations();
await Promise.all(registrations.map((registration) => registration.unregister()));
const names = await ports.cacheNames();
await Promise.all(
names
.filter((name) => name !== kachelCacheName)
.map((name) => ports.deleteCache(name)),
);
}
/** Drop every stored Kachel. The heruntergeladen marks stay. */
export async function deleteKachelCache(ports: Pick<BootRepairPorts, "deleteCache">): Promise<void> {
await ports.deleteCache(kachelCacheName);
}
export function bootFailureText(error: unknown): string {
if (error instanceof Error && error.message.trim()) return error.message;
return "Unbekannter Fehler";
}
export function createBrowserBootRepair(): BootRepairPorts {
return {
async registrations() {
if (!navigator.serviceWorker) return [];
return navigator.serviceWorker.getRegistrations();
},
cacheNames: () => caches.keys(),
deleteCache: (name) => caches.delete(name),
};
}
export function shellRepairWasTried(store: FlagStore | null = browserFlags()): boolean {
try {
return store?.getItem(SHELL_REPAIR_TRIED) === "1";
} catch {
return false;
}
}
export function markShellRepairTried(store: FlagStore | null = browserFlags()): void {
try {
store?.setItem(SHELL_REPAIR_TRIED, "1");
} catch {
// sessionStorage can be blocked. The repair still runs.
}
}
export function clearShellRepairTried(store: FlagStore | null = browserFlags()): void {
try {
store?.removeItem(SHELL_REPAIR_TRIED);
} catch {
// sessionStorage can be blocked.
}
}
function browserFlags(): FlagStore | null {
try {
if (typeof sessionStorage === "undefined") return null;
return sessionStorage;
} catch {
return null;
}
}