Release Healer Man 0.1.5

This commit is contained in:
phenom committed 2026-08-18 16:22:19 -04:00
1 parent f4c9cf356c
commit 55cfd43d66
62 files changed
+3030 -153

No files matched your search

+101
View File
@@ -0,0 +1,101 @@
import { create } from "zustand";
import type { PlayerSession } from "../app/types";
import { requestOnlineJson } from "../app/onlineAccountClient";
import {
DEFAULT_MANASTORM_ADMIN_CONFIG,
MANASTORM_ADMIN_CACHE_KEY,
normalizeManastormAdminConfig,
resolvedBossAdminCatalog,
type ManastormAdminConfig,
type PublishedManastormAdminConfig,
} from "./manastormAdminConfig";
interface CachedPayload extends PublishedManastormAdminConfig {}
function readCache(): CachedPayload {
try {
const raw = typeof window !== "undefined" ? window.localStorage.getItem(MANASTORM_ADMIN_CACHE_KEY) : null;
const parsed = raw ? JSON.parse(raw) as Partial<CachedPayload> : null;
if (!parsed || !Number.isInteger(parsed.revision) || (parsed.revision ?? -1) < 0) throw new Error("missing cache");
return {
revision: parsed.revision!,
updatedAt: typeof parsed.updatedAt === "number" ? parsed.updatedAt : null,
config: normalizeManastormAdminConfig(parsed.config),
};
} catch {
return { revision: 0, updatedAt: null, config: DEFAULT_MANASTORM_ADMIN_CONFIG };
}
}
function writeCache(payload: PublishedManastormAdminConfig): void {
try {
window.localStorage.setItem(MANASTORM_ADMIN_CACHE_KEY, JSON.stringify(payload));
} catch {
// Private browsing and storage quotas must not prevent play.
}
}
export interface ManastormAdminState extends PublishedManastormAdminConfig {
readonly draft: ManastormAdminConfig;
readonly loading: boolean;
readonly saving: boolean;
readonly error: string | null;
readonly editingBossKey: string | null;
readonly dirty: boolean;
refresh: () => Promise<void>;
replaceDraft: (config: ManastormAdminConfig) => void;
resetDraft: () => void;
publish: (session: PlayerSession | null) => Promise<boolean>;
setEditingBossKey: (key: string | null) => void;
}
const cached = readCache();
export const useManastormAdminStore = create<ManastormAdminState>((set, get) => ({
...cached,
draft: cached.config,
loading: false,
saving: false,
error: null,
editingBossKey: null,
dirty: false,
refresh: async () => {
set({ loading: true, error: null });
try {
const payload = await requestOnlineJson<PublishedManastormAdminConfig>("/api/manastorm-config");
const normalized = { ...payload, config: normalizeManastormAdminConfig(payload.config) };
writeCache(normalized);
set({ ...normalized, draft: normalized.config, dirty: false, loading: false });
} catch (error) {
set({ loading: false, error: error instanceof Error ? error.message : "Could not refresh Manastorm configuration." });
}
},
replaceDraft: (draft) => set({ draft: normalizeManastormAdminConfig(draft), dirty: true, error: null }),
resetDraft: () => set((state) => ({ draft: state.config, dirty: false, error: null })),
publish: async (session) => {
if (!session?.accessToken || !session.roles?.includes("gm")) {
set({ error: "Game Master access is required." });
return false;
}
const invalidReadyBoss = resolvedBossAdminCatalog(get().draft).find((entry) => entry.status === "ready" && !entry.runnable);
if (invalidReadyBoss) {
set({ error: `${invalidReadyBoss.name} cannot be published as Ready: ${invalidReadyBoss.validationIssues.join(" ")}` });
return false;
}
set({ saving: true, error: null });
try {
const payload = await requestOnlineJson<PublishedManastormAdminConfig>("/api/gm/manastorm-config", {
method: "PUT",
body: JSON.stringify({ expectedRevision: get().revision, config: get().draft }),
}, session.accessToken);
const normalized = { ...payload, config: normalizeManastormAdminConfig(payload.config) };
writeCache(normalized);
set({ ...normalized, draft: normalized.config, dirty: false, saving: false });
return true;
} catch (error) {
set({ saving: false, error: error instanceof Error ? error.message : "Could not publish Manastorm configuration." });
return false;
}
},
setEditingBossKey: (editingBossKey) => set({ editingBossKey }),
}));