Shaheer Sarfaraz b94f85b149
Reduce low risk duplication (#79)
* clean up helpers

* shared in it's own top level folder

* workspaces setup

* build fix

* disable workspaces?

* run ci

* rename job-flow to gradcracker

* optional dependencies

* formatting?

* more optional modules

* allow post install runs

* node bump

* remove post install

* add optionals

* add more

* formatting

* comments, but im unsure

* run typescript DIRECTLY

* better build

* camoufox simplification

* lint

* build process doesn't exist

* build fix

* lockfile

* type check everything, build only for client

* rename steps correctly

* import from package!

* fix formatting

* don't fetch twice

* fix concern
2026-02-02 21:30:14 +00:00

82 lines
2.3 KiB
TypeScript

/**
* Profile service - fetches resume data from RxResume v4 API.
*
* The rxresumeBaseResumeId setting is REQUIRED for the app to function.
* There is no local file fallback.
*/
import type { ResumeProfile } from "@shared/types";
import { getSetting } from "../repositories/settings";
import { getResume, RxResumeCredentialsError } from "./rxresume-v4";
let cachedProfile: ResumeProfile | null = null;
let cachedResumeId: string | null = null;
/**
* Get the base resume profile from RxResume v4 API.
*
* Requires rxresumeBaseResumeId to be configured in settings.
* Results are cached until clearProfileCache() is called.
*
* @param forceRefresh Force reload from API.
* @throws Error if rxresumeBaseResumeId is not configured or API call fails.
*/
export async function getProfile(forceRefresh = false): Promise<ResumeProfile> {
const rxresumeBaseResumeId = await getSetting("rxresumeBaseResumeId");
if (!rxresumeBaseResumeId) {
throw new Error(
"Base resume not configured. Please select a base resume from your RxResume account in Settings.",
);
}
// Return cached profile if valid
if (
cachedProfile &&
cachedResumeId === rxresumeBaseResumeId &&
!forceRefresh
) {
return cachedProfile;
}
try {
console.log(
`📋 Fetching profile from RxResume v4 API (resume: ${rxresumeBaseResumeId})...`,
);
const resume = await getResume(rxresumeBaseResumeId);
if (!resume.data || typeof resume.data !== "object") {
throw new Error("Resume data is empty or invalid");
}
cachedProfile = resume.data as unknown as ResumeProfile;
cachedResumeId = rxresumeBaseResumeId;
console.log(`✅ Profile loaded from RxResume v4 API`);
return cachedProfile;
} catch (error) {
if (error instanceof RxResumeCredentialsError) {
throw new Error(
"RxResume credentials not configured. Set RXRESUME_EMAIL and RXRESUME_PASSWORD in settings.",
);
}
console.error(`❌ Failed to load profile from RxResume v4 API:`, error);
throw error;
}
}
/**
* Get the person's name from the profile.
*/
export async function getPersonName(): Promise<string> {
const profile = await getProfile();
return profile?.basics?.name || "Resume";
}
/**
* Clear the profile cache.
*/
export function clearProfileCache(): void {
cachedProfile = null;
cachedResumeId = null;
}