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

+22 -6
View File
@@ -11,7 +11,7 @@ const NATIVE_API_ORIGIN = "https://iwanttoheal.phenomrom.com";
const SAVE_DEBOUNCE_MS = 500;
interface AuthResponse {
account: { id: string; username: string };
account: { id: string; username: string; roles?: readonly "gm"[] };
token: string;
}
@@ -21,6 +21,10 @@ interface CloudSaveResponse {
data: { version?: number; characters?: unknown };
}
interface MeResponse {
account: { id: string; username: string; roles?: readonly "gm"[] };
}
class OnlineApiError extends Error {
constructor(message: string, readonly status: number) {
super(message);
@@ -40,7 +44,7 @@ function apiOrigin(): string {
return Capacitor.isNativePlatform() ? NATIVE_API_ORIGIN : "";
}
async function requestJson<T>(pathname: string, init: RequestInit = {}, token?: string): Promise<T> {
export async function requestOnlineJson<T>(pathname: string, init: RequestInit = {}, token?: string): Promise<T> {
const headers = new Headers(init.headers);
headers.set("Accept", "application/json");
if (init.body !== undefined) headers.set("Content-Type", "application/json");
@@ -63,6 +67,7 @@ function accountResult(response: AuthResponse): AccountResult {
kind: "account",
ownerId: response.account.id,
displayName: response.account.username,
roles: response.account.roles ?? [],
accessToken: response.token,
},
};
@@ -70,7 +75,7 @@ function accountResult(response: AuthResponse): AccountResult {
async function authenticate(pathname: string, username: string, password: string): Promise<AccountResult> {
try {
const response = await requestJson<AuthResponse>(pathname, {
const response = await requestOnlineJson<AuthResponse>(pathname, {
method: "POST",
body: JSON.stringify({ username, password }),
});
@@ -94,7 +99,7 @@ function flushCloudSave(): void {
pendingCharacters = null;
if (!session?.accessToken || !characters) return;
saveQueue = saveQueue.then(async () => {
await requestJson<CloudSaveResponse>("/api/cloud-save", {
await requestOnlineJson<CloudSaveResponse>("/api/cloud-save", {
method: "PUT",
body: JSON.stringify({ data: { version: 1, characters } }),
}, session.accessToken);
@@ -122,7 +127,7 @@ export function activateOnlineSession(session: PlayerSession): void {
export async function hydrateOnlineSession(session: PlayerSession): Promise<CharacterProfile[]> {
if (!session.accessToken) return listCharacters(session.ownerId);
activateOnlineSession(session);
const cloud = await requestJson<CloudSaveResponse>("/api/cloud-save", {}, session.accessToken);
const cloud = await requestOnlineJson<CloudSaveResponse>("/api/cloud-save", {}, session.accessToken);
suppressUpload = true;
try {
return replaceCharactersForOwner(session.ownerId, cloud.data?.characters ?? []);
@@ -131,6 +136,17 @@ export async function hydrateOnlineSession(session: PlayerSession): Promise<Char
}
}
export async function refreshOnlineSession(session: PlayerSession): Promise<PlayerSession> {
if (!session.accessToken) return { ...session, roles: [] };
const response = await requestOnlineJson<MeResponse>("/api/me", {}, session.accessToken);
return {
...session,
ownerId: response.account.id,
displayName: response.account.username,
roles: response.account.roles ?? [],
};
}
export async function logoutOnlineSession(session: PlayerSession | null): Promise<void> {
if (saveTimer) {
clearTimeout(saveTimer);
@@ -139,7 +155,7 @@ export async function logoutOnlineSession(session: PlayerSession | null): Promis
}
if (session?.accessToken) {
await saveQueue;
await requestJson("/api/auth/logout", { method: "POST" }, session.accessToken).catch(() => undefined);
await requestOnlineJson("/api/auth/logout", { method: "POST" }, session.accessToken).catch(() => undefined);
}
if (activeSession?.ownerId === session?.ownerId) activeSession = null;
}