/** * Pure, dependency-free EPFO stub + validation logic (no express/playwright), so * the deterministic contract the PPMS app relies on can be unit-tested without * launching the service. `index.ts` uses these in its stub branches, so the * tested logic IS the production stub behaviour. * * Deterministic stub contract (EPFO_LIVE unset): * /otp validates the UAN and opens a session. * /verify validates session + UAN + OTP; matched iff OTP === STUB_MATCH_OTP. */ export const STUB_MATCH_OTP = "000000"; export const isUan = (s: unknown): s is string => typeof s === "string" && /^\d{12}$/.test(s); export const isOtp = (s: unknown): s is string => typeof s === "string" && /^\d{4,8}$/.test(s); export const mobileHint = (m?: string) => (m && m.length >= 4 ? `••••••${m.slice(-4)}` : "••••••••"); export interface StubResult { ok: boolean; status: number; body: Record; } /** Stub of POST /otp — validate the UAN and (caller-supplied) open a session. */ export function stubOtp(uan: unknown, sessionId: string): StubResult { if (!isUan(uan)) return { ok: false, status: 400, body: { error: "A 12-digit UAN is required" } }; return { ok: true, status: 200, body: { sessionId, mobileHint: mobileHint(), stub: true } }; } /** Stub of POST /verify — validate the session/UAN/OTP and return the match. */ export function stubVerify(session: { uan: string } | undefined, uan: unknown, otp: unknown): StubResult { if (!session) return { ok: false, status: 410, body: { error: "Session expired — request a new OTP" } }; if (!isUan(uan) || session.uan !== uan) return { ok: false, status: 400, body: { error: "UAN mismatch" } }; if (!isOtp(otp)) return { ok: false, status: 400, body: { error: "A valid OTP is required" } }; const matched = otp === STUB_MATCH_OTP; return { ok: true, status: 200, body: { matched, name: matched ? "EPFO Member (stub)" : null, status: matched ? "ACTIVE" : null, stub: true }, }; }