Release Healer Man 0.1.12

This commit is contained in:
phenom committed 2026-09-01 14:35:56 -04:00
1 parent 13970d03c8
commit 65e24f644e
201 files changed
+5061 -123

No files matched your search

+86 -11
View File
@@ -7,10 +7,13 @@ import {
} from "./manastorm";
import { INSTALLED_MANASTORM_RUNTIME_CATALOG } from "./manastormInstalledCatalog";
export const MANASTORM_ADMIN_CONFIG_SCHEMA_VERSION = 1;
export const MANASTORM_ADMIN_CACHE_KEY = "healer-man.manastorm-admin-config.v1";
export const MANASTORM_ADMIN_CONFIG_SCHEMA_VERSION = 2;
export const MANASTORM_ADMIN_CACHE_KEY = "healer-man.manastorm-admin-config.v2";
export const LEGACY_MANASTORM_ADMIN_CACHE_KEY = "healer-man.manastorm-admin-config.v1";
export const GM_REVIEW_NOTE_MAX_LENGTH = 1_000;
export type ManastormBossStatus = "ready" | "needs-tested" | "not-ready";
export type GmReadinessStatus = "ready" | "needs-tested" | "not-ready";
export type ManastormBossStatus = GmReadinessStatus;
export interface ManastormGlobalOptions {
readonly enabled: boolean;
@@ -37,15 +40,24 @@ export interface ManastormAdminStageConfig {
readonly requiredKillCount: number;
}
export interface ManastormBossAdminRecord {
readonly status: ManastormBossStatus;
export interface GmReviewRecord {
readonly status: GmReadinessStatus;
readonly note?: string;
readonly reviewedAt?: number;
readonly reviewedBy?: string;
}
export interface ManastormBossAdminRecord extends GmReviewRecord {
readonly stage?: ManastormAdminStageConfig;
}
export type DungeonAdminRecord = GmReviewRecord;
export interface ManastormAdminConfig {
readonly schemaVersion: typeof MANASTORM_ADMIN_CONFIG_SCHEMA_VERSION;
readonly global: ManastormGlobalOptions;
readonly dungeonSpawns: Readonly<Record<string, WorldSpawn>>;
readonly dungeons: Readonly<Record<string, DungeonAdminRecord>>;
readonly bosses: Readonly<Record<string, ManastormBossAdminRecord>>;
}
@@ -71,6 +83,9 @@ export interface UnifiedBossCatalogEntry {
export interface ResolvedBossAdminEntry extends UnifiedBossCatalogEntry {
readonly status: ManastormBossStatus;
readonly reviewNote: string;
readonly reviewedAt: number | null;
readonly reviewedBy: string | null;
readonly stage: ManastormEncounterDefinition | null;
readonly runnable: boolean;
readonly validationIssues: readonly string[];
@@ -88,6 +103,7 @@ export const DEFAULT_MANASTORM_ADMIN_CONFIG: ManastormAdminConfig = Object.freez
milestoneEncountersEnabled: true,
}),
dungeonSpawns: Object.freeze({}),
dungeons: Object.freeze({}),
bosses: Object.freeze({}),
});
@@ -143,10 +159,37 @@ function normalizedStage(value: unknown): ManastormAdminStageConfig | null {
};
}
function normalizedReviewFields(value: Partial<GmReviewRecord>): Omit<GmReviewRecord, "status"> {
const rawNote = typeof value.note === "string"
? value.note.replace(/\r\n?/g, "\n").slice(0, GM_REVIEW_NOTE_MAX_LENGTH)
: "";
const reviewedAt = typeof value.reviewedAt === "number"
&& Number.isInteger(value.reviewedAt)
&& value.reviewedAt > 0
? value.reviewedAt
: null;
const reviewedBy = typeof value.reviewedBy === "string"
? value.reviewedBy.trim().slice(0, 256)
: "";
return {
...(rawNote.trim() ? { note: rawNote } : {}),
...(reviewedAt ? { reviewedAt } : {}),
...(reviewedBy ? { reviewedBy } : {}),
};
}
export function normalizeManastormAdminConfig(value: unknown): ManastormAdminConfig {
if (!value || typeof value !== "object") return DEFAULT_MANASTORM_ADMIN_CONFIG;
const input = value as Partial<ManastormAdminConfig>;
if (input.schemaVersion !== MANASTORM_ADMIN_CONFIG_SCHEMA_VERSION) return DEFAULT_MANASTORM_ADMIN_CONFIG;
const input = value as {
readonly schemaVersion?: unknown;
readonly global?: Partial<ManastormGlobalOptions>;
readonly dungeonSpawns?: Readonly<Record<string, unknown>>;
readonly dungeons?: Readonly<Record<string, unknown>>;
readonly bosses?: Readonly<Record<string, unknown>>;
};
if (input.schemaVersion !== 1 && input.schemaVersion !== MANASTORM_ADMIN_CONFIG_SCHEMA_VERSION) {
return DEFAULT_MANASTORM_ADMIN_CONFIG;
}
const globalInput = input.global as Partial<ManastormGlobalOptions> | undefined;
const global: ManastormGlobalOptions = {
enabled: globalInput?.enabled !== false,
@@ -160,14 +203,42 @@ export function normalizeManastormAdminConfig(value: unknown): ManastormAdminCon
const spawn = normalizedSpawn(value);
return id && spawn ? [[id, spawn]] : [];
}));
const dungeons = Object.fromEntries(Object.entries(input.dungeons ?? {}).flatMap(([id, value]) => {
if (!id || !value || typeof value !== "object") return [];
const candidate = value as Partial<DungeonAdminRecord>;
const status: GmReadinessStatus = candidate.status === "ready" || candidate.status === "not-ready"
? candidate.status
: "needs-tested";
return [[id, { status, ...normalizedReviewFields(candidate) }]];
}));
const bosses = Object.fromEntries(Object.entries(input.bosses ?? {}).flatMap(([key, value]) => {
if (!key || !value || typeof value !== "object") return [];
const candidate = value as Partial<ManastormBossAdminRecord>;
const status: ManastormBossStatus = candidate.status === "ready" || candidate.status === "not-ready" ? candidate.status : "needs-tested";
const status: GmReadinessStatus = candidate.status === "ready" || candidate.status === "not-ready" ? candidate.status : "needs-tested";
const stage = normalizedStage(candidate.stage);
return [[key, { status, ...(stage ? { stage } : {}) }]];
return [[key, { status, ...normalizedReviewFields(candidate), ...(stage ? { stage } : {}) }]];
}));
return { schemaVersion: MANASTORM_ADMIN_CONFIG_SCHEMA_VERSION, global, dungeonSpawns, bosses };
return {
schemaVersion: MANASTORM_ADMIN_CONFIG_SCHEMA_VERSION,
global,
dungeonSpawns,
dungeons,
bosses,
};
}
export function publicManastormAdminConfig(config: ManastormAdminConfig): ManastormAdminConfig {
return {
...config,
dungeons: Object.fromEntries(Object.entries(config.dungeons).map(([key, record]) => [
key,
{ status: record.status },
])),
bosses: Object.fromEntries(Object.entries(config.bosses).map(([key, record]) => [
key,
{ status: record.status, ...(record.stage ? { stage: record.stage } : {}) },
])),
};
}
function dungeonBossEntityId(dungeonId: string, objectiveId: string): string {
@@ -351,7 +422,8 @@ export function resolveBossAdminEntry(
entry: UnifiedBossCatalogEntry,
config: ManastormAdminConfig,
): ResolvedBossAdminEntry {
const status = config.bosses[entry.key]?.status ?? "needs-tested";
const record = config.bosses[entry.key];
const status = record?.status ?? "needs-tested";
const stage = configuredStageForBoss(entry, config);
const issues: string[] = [];
if (!stage) issues.push("No runnable Manastorm stage has been configured.");
@@ -370,6 +442,9 @@ export function resolveBossAdminEntry(
return {
...entry,
status,
reviewNote: record?.note ?? "",
reviewedAt: record?.reviewedAt ?? null,
reviewedBy: record?.reviewedBy ?? null,
stage,
runnable,
validationIssues: Object.freeze(issues),