Update Healer Man server
This commit is contained in:
1 parent
f8314e7de1
commit
1fedb9368d
76 files changed
+20556
-2523
No files matched your search
@@ -0,0 +1,104 @@
|
||||
import { create } from "zustand";
|
||||
import type { PlayerSession } from "../app/types";
|
||||
import { requestOnlineJson } from "../app/onlineAccountClient";
|
||||
import {
|
||||
companionSpecReadinessFromCache,
|
||||
normalizeCompanionSpecReadinessPolicy,
|
||||
type CompanionSpecReadinessPolicy,
|
||||
type PublishedCompanionSpecReadinessPolicy,
|
||||
} from "./companionSpecReadiness";
|
||||
|
||||
interface CompanionSpecReadinessState extends PublishedCompanionSpecReadinessPolicy {
|
||||
readonly draft: CompanionSpecReadinessPolicy;
|
||||
readonly loading: boolean;
|
||||
readonly saving: boolean;
|
||||
readonly dirty: boolean;
|
||||
readonly error: string | null;
|
||||
refresh: (session?: PlayerSession | null) => Promise<void>;
|
||||
setStatus: (specializationId: string, status: "ready" | "beta" | "needs-testing") => void;
|
||||
resetDraft: () => void;
|
||||
publish: (session?: PlayerSession | null) => Promise<boolean>;
|
||||
}
|
||||
|
||||
const CACHE_KEY = "healer-man.companion-spec-readiness.v1";
|
||||
const LOCAL_GUI = import.meta.env.VITE_LOCAL_BALANCE_LAB_GUI === "true";
|
||||
const LOCAL_PATH = "/api/local/balance-lab/companion-spec-readiness";
|
||||
|
||||
function cached(): PublishedCompanionSpecReadinessPolicy {
|
||||
return companionSpecReadinessFromCache(typeof window === "undefined" ? null : window.localStorage.getItem(CACHE_KEY));
|
||||
}
|
||||
|
||||
function cache(payload: PublishedCompanionSpecReadinessPolicy): void {
|
||||
try { window.localStorage.setItem(CACHE_KEY, JSON.stringify(payload)); } catch { /* optional offline cache */ }
|
||||
}
|
||||
|
||||
async function request<T>(pathname: string, init: RequestInit, session?: PlayerSession | null): Promise<T> {
|
||||
if (!LOCAL_GUI) return requestOnlineJson<T>(pathname, init, session?.accessToken);
|
||||
const headers = new Headers(init.headers);
|
||||
headers.set("Accept", "application/json");
|
||||
if (init.body !== undefined) headers.set("Content-Type", "application/json");
|
||||
const response = await fetch(LOCAL_PATH, { ...init, headers });
|
||||
const body = await response.json().catch(() => ({})) as T & { error?: string };
|
||||
if (!response.ok) throw new Error(body.error ?? `Local readiness request failed (${response.status}).`);
|
||||
return body;
|
||||
}
|
||||
|
||||
const initial = cached();
|
||||
|
||||
export const useCompanionSpecReadinessStore = create<CompanionSpecReadinessState>((set, get) => ({
|
||||
...initial,
|
||||
draft: initial.config,
|
||||
loading: false,
|
||||
saving: false,
|
||||
dirty: false,
|
||||
error: null,
|
||||
refresh: async (session = null) => {
|
||||
set({ loading: true, error: null });
|
||||
try {
|
||||
const gm = Boolean(session?.accessToken && session.roles?.includes("gm"));
|
||||
const pathname = gm ? "/api/gm/companion-spec-readiness" : "/api/companion-spec-readiness";
|
||||
const payload = await request<PublishedCompanionSpecReadinessPolicy>(pathname, {}, session);
|
||||
const normalized = { ...payload, config: normalizeCompanionSpecReadinessPolicy(payload.config) };
|
||||
cache(normalized);
|
||||
set({ ...normalized, draft: normalized.config, loading: false, dirty: false });
|
||||
} catch (error) {
|
||||
set({ loading: false, error: error instanceof Error ? error.message : "Could not load companion readiness." });
|
||||
}
|
||||
},
|
||||
setStatus: (specializationId, status) => set((state) => ({
|
||||
draft: {
|
||||
schemaVersion: 1,
|
||||
statuses: { ...state.draft.statuses, [specializationId]: status },
|
||||
},
|
||||
dirty: true,
|
||||
error: null,
|
||||
})),
|
||||
resetDraft: () => set((state) => ({ draft: state.config, dirty: false, error: null })),
|
||||
publish: async (session = null) => {
|
||||
if (!LOCAL_GUI && (!session?.accessToken || !session.roles?.includes("gm"))) {
|
||||
set({ error: "Game Master access is required." });
|
||||
return false;
|
||||
}
|
||||
set({ saving: true, error: null });
|
||||
try {
|
||||
const draft = normalizeCompanionSpecReadinessPolicy(get().draft);
|
||||
const payload = await request<PublishedCompanionSpecReadinessPolicy>(
|
||||
"/api/gm/companion-spec-readiness",
|
||||
{ method: "PUT", body: JSON.stringify({ expectedRevision: get().revision, config: draft }) },
|
||||
session,
|
||||
);
|
||||
const normalized = { ...payload, config: normalizeCompanionSpecReadinessPolicy(payload.config) };
|
||||
cache(normalized);
|
||||
set({ ...normalized, draft: normalized.config, saving: false, dirty: false });
|
||||
return true;
|
||||
} catch (error) {
|
||||
set({ saving: false, error: error instanceof Error ? error.message : "Could not publish companion readiness." });
|
||||
return false;
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
export function currentCompanionSpecReadinessPolicy(): PublishedCompanionSpecReadinessPolicy {
|
||||
const state = useCompanionSpecReadinessStore.getState();
|
||||
return { revision: state.revision, updatedAt: state.updatedAt, updatedBy: state.updatedBy, config: state.config };
|
||||
}
|
||||
Reference in new issue
Block a user