62 lines
3.0 KiB
TypeScript
62 lines
3.0 KiB
TypeScript
import * as z from "zod";
|
|
import type { CommissionRequest } from "./request";
|
|
|
|
const draftKey = z.string().max(64);
|
|
const draftRequestSchema = z.object({
|
|
teams: z.array(z.object({ members: z.array(z.object({
|
|
characterKey: draftKey, weaponKey: draftKey, artifactKey: draftKey,
|
|
constellation: z.enum(["0", "1", "2", "3", "4", "5", "6", "0-6"]),
|
|
refinement: z.enum(["1", "2", "3", "4", "5", "1-5"]),
|
|
})).length(4) })).max(20),
|
|
weapons: z.array(z.object({
|
|
characterKey: draftKey, weaponKeys: z.array(draftKey).min(1).max(100),
|
|
refinements: z.record(draftKey, z.enum(["1", "2", "3", "4", "5"])).optional(),
|
|
})).max(20),
|
|
constellations: z.array(z.object({
|
|
characterKey: draftKey, levels: z.array(z.number().int().min(0).max(6)).max(7),
|
|
})).max(20),
|
|
});
|
|
const draftSchema = z.object({ version: z.literal(1), savedAt: z.number(), request: draftRequestSchema });
|
|
const DRAFT_LIFETIME_MS = 7 * 24 * 60 * 60 * 1000;
|
|
|
|
type DraftCatalog = {
|
|
characters: { key: string; weaponType?: string | null }[];
|
|
weapons: { key: string; weaponType?: string | null }[];
|
|
artifacts: { key: string }[];
|
|
};
|
|
|
|
export function commissionDraftKey(userId: string) {
|
|
return `commission-request-draft:${userId}`;
|
|
}
|
|
|
|
export function serializeCommissionDraft(request: CommissionRequest, now = Date.now()) {
|
|
return JSON.stringify({ version: 1, savedAt: now, request });
|
|
}
|
|
|
|
export function restoreCommissionDraft(serialized: string | null, catalog: DraftCatalog, now = Date.now()): CommissionRequest | null {
|
|
if (!serialized) return null;
|
|
let parsed;
|
|
try { parsed = draftSchema.safeParse(JSON.parse(serialized)); } catch { return null; }
|
|
if (!parsed.success || now - parsed.data.savedAt > DRAFT_LIFETIME_MS || parsed.data.savedAt > now) return null;
|
|
const request = parsed.data.request;
|
|
const characterKeys = new Set(catalog.characters.map((item) => item.key));
|
|
const artifactKeys = new Set(catalog.artifacts.map((item) => item.key));
|
|
const compatibleWeapon = (characterKey: string, weaponKey: string) => {
|
|
const character = catalog.characters.find((item) => item.key === characterKey);
|
|
return character?.weaponType && catalog.weapons.some((item) => item.key === weaponKey && item.weaponType === character.weaponType)
|
|
? weaponKey : "";
|
|
};
|
|
for (const team of request.teams) for (const member of team.members) {
|
|
if (!characterKeys.has(member.characterKey)) member.characterKey = "";
|
|
member.weaponKey = compatibleWeapon(member.characterKey, member.weaponKey);
|
|
if (!artifactKeys.has(member.artifactKey)) member.artifactKey = "";
|
|
}
|
|
for (const set of request.weapons) {
|
|
if (!characterKeys.has(set.characterKey)) set.characterKey = "";
|
|
set.weaponKeys = set.weaponKeys.map((key) => compatibleWeapon(set.characterKey, key));
|
|
set.refinements = Object.fromEntries(Object.entries(set.refinements ?? {}).filter(([key]) => key && set.weaponKeys.includes(key)));
|
|
}
|
|
for (const set of request.constellations) if (!characterKeys.has(set.characterKey)) set.characterKey = "";
|
|
return request;
|
|
}
|