/** Shared API contract between the Worker and the React client. */ export interface JobExtract { url: string; title: string; text: string; /** Where the text came from: JobPosting JSON-LD, stripped body HTML, non-HTML response, or user paste. */ source: "json-ld" | "html" | "plain" | "manual"; } export interface MatchedSkill { name: string; category: "language" | "framework" | "methodology" | "domain"; /** Number of times the skill (or an alias) appears in the job text. */ hits: number; } export interface RankedItem { type: "experience" | "project"; slug: string; title: string; company?: string; dates: string; score: number; matchedSkills: string[]; bullets: string[]; } export interface MatchResult { skills: MatchedSkill[]; items: RankedItem[]; } export interface ChatMessage { role: "user" | "assistant"; content: string; } export interface PlanSkillGroup { group: string; items: string[]; } export interface PlanExperience { slug: string; bullets: string[]; } export interface PlanProject { slug: string; heading: string; bullets: string[]; } /** The tailored selection the LaTeX template is filled from. */ export interface ResumePlan { /** Headline under the name, e.g. "Senior Blockchain & Protocol Engineer". */ title: string; skills: PlanSkillGroup[]; experience: PlanExperience[]; projects: PlanProject[]; } export interface PlanResponse { plan: ResumePlan; source: "ai" | "fallback"; note?: string; } export interface ApiError { error: string; log?: string; }