Files
healer-man/src/app/memoryReset.ts
T
2026-09-27 10:16:42 -04:00

64 lines
1.9 KiB
TypeScript

import type { ShellPhase } from "./types";
const HANDOFF_KEY = "healer-man.memory-reset.v1";
export interface MemoryResetHandoff {
readonly ownerId: string;
readonly characterId: string;
readonly phase: Extract<ShellPhase, "characters" | "main-menu" | "class-hall">;
}
interface HandoffStorage {
getItem(key: string): string | null;
setItem(key: string, value: string): void;
removeItem(key: string): void;
}
function browserStorage(): HandoffStorage | null {
try {
return typeof window === "undefined" ? null : window.sessionStorage;
} catch {
return null;
}
}
/** A full page reload is the browser's boundary for releasing imported modules. */
export function requestMemoryReset(handoff: MemoryResetHandoff): boolean {
if (import.meta.env.MODE === "test") return false;
const storage = browserStorage();
if (!storage) return false;
try {
storage.setItem(HANDOFF_KEY, JSON.stringify(handoff));
window.location.reload();
return true;
} catch {
try { storage.removeItem(HANDOFF_KEY); } catch { /* Storage may be disabled. */ }
return false;
}
}
/** Consume once so a later ordinary reload never replays an old navigation. */
export function consumeMemoryReset(
ownerId: string,
characterIds: readonly string[],
storage: HandoffStorage | null = browserStorage(),
): MemoryResetHandoff | null {
if (!storage) return null;
let raw: string | null;
try {
raw = storage.getItem(HANDOFF_KEY);
storage.removeItem(HANDOFF_KEY);
} catch {
return null;
}
if (!raw) return null;
try {
const value = JSON.parse(raw) as Partial<MemoryResetHandoff>;
if (value.ownerId !== ownerId || !value.characterId || !characterIds.includes(value.characterId)) return null;
if (value.phase !== "characters" && value.phase !== "main-menu" && value.phase !== "class-hall") return null;
return value as MemoryResetHandoff;
} catch {
return null;
}
}