Function bodies 113 total
calcBCPTTFirstTimeSavings function · typescript · L151-L164 (14 LOC)src/lib/mortgage.ts
export function calcBCPTTFirstTimeSavings(
homePrice: number,
isFirstTimeBuyer: boolean
): number {
if (!isFirstTimeBuyer) return 0;
const fullPTT = calcBCPTT(homePrice);
if (homePrice <= 500_000) return fullPTT;
if (homePrice <= 525_000) {
// Partial exemption: proportional phase-out
const ratio = (525_000 - homePrice) / 25_000;
return fullPTT * ratio;
}
return 0;
}convertFrequency function · typescript · L168-L186 (19 LOC)src/lib/mortgage.ts
export function convertFrequency(
monthlyPayment: number,
frequency: PaymentFrequency
): number {
switch (frequency) {
case "monthly":
return monthlyPayment;
case "semi-monthly":
return monthlyPayment / 2;
case "bi-weekly":
return (monthlyPayment * 12) / 26;
case "accelerated-bi-weekly":
return monthlyPayment / 2;
case "weekly":
return (monthlyPayment * 12) / 52;
case "accelerated-weekly":
return monthlyPayment / 4;
}
}getFrequencyLabel function · typescript · L188-L198 (11 LOC)src/lib/mortgage.ts
export function getFrequencyLabel(frequency: PaymentFrequency): string {
const labels: Record<PaymentFrequency, string> = {
monthly: "Monthly",
"semi-monthly": "Semi-Monthly",
"bi-weekly": "Bi-Weekly",
"accelerated-bi-weekly": "Accelerated Bi-Weekly",
weekly: "Weekly",
"accelerated-weekly": "Accelerated Weekly",
};
return labels[frequency];
}calcStressTestRate function · typescript · L202-L204 (3 LOC)src/lib/mortgage.ts
export function calcStressTestRate(contractRate: number): number {
return Math.max(contractRate + 0.02, 0.0525);
}calculateMortgage function · typescript · L208-L292 (85 LOC)src/lib/mortgage.ts
export function calculateMortgage(inputs: MortgageInputs): MortgageResults {
const {
homePrice,
downPayment,
annualRate,
amortYears,
frequency,
propertyTaxAnnual,
homeInsuranceAnnual,
strataMonthly,
isFirstTimeBuyer,
} = inputs;
const cmhcPremium = calcCMHC(
homePrice,
downPayment,
amortYears,
isFirstTimeBuyer
);
const cmhcRequired = cmhcPremium > 0;
// Principal = home price - down payment + CMHC (added to mortgage)
const totalMortgageAmount = homePrice - downPayment + cmhcPremium;
const monthlyPI = calcMonthlyPayment(
totalMortgageAmount,
annualRate,
amortYears
);
const frequencyPayment = convertFrequency(monthlyPI, frequency);
const propertyTaxMonthly = propertyTaxAnnual / 12;
const homeInsuranceMonthly = homeInsuranceAnnual / 12;
const totalMonthlyHousing =
monthlyPI + propertyTaxMonthly + homeInsuranceMonthly + strataMonthly;
const totalPayments = monthlyPI * amortYears * 12;
cgenerateAmortization function · typescript · L296-L321 (26 LOC)src/lib/mortgage.ts
export function generateAmortization(
principal: number,
annualRate: number,
amortYears: number
): AmortizationRow[] {
const r = getMonthlyRate(annualRate);
const n = amortYears * 12;
const payment = calcMonthlyPayment(principal, annualRate, amortYears);
let balance = principal;
const schedule: AmortizationRow[] = [];
for (let i = 1; i <= n; i++) {
const interest = balance * r;
const principalPaid = payment - interest;
balance = Math.max(0, balance - principalPaid);
schedule.push({
period: i,
payment,
principal: principalPaid,
interest,
balance,
});
}
return schedule;
}getYearlySummary function · typescript · L323-L355 (33 LOC)src/lib/mortgage.ts
export function getYearlySummary(schedule: AmortizationRow[]): YearlySummary[] {
const years: YearlySummary[] = [];
let cumulativeInterest = 0;
for (let y = 0; y < Math.ceil(schedule.length / 12); y++) {
const start = y * 12;
const end = Math.min(start + 12, schedule.length);
const yearRows = schedule.slice(start, end);
let annualPayments = 0;
let principalPaid = 0;
let interestPaid = 0;
for (const row of yearRows) {
annualPayments += row.payment;
principalPaid += row.principal;
interestPaid += row.interest;
}
cumulativeInterest += interestPaid;
years.push({
year: y + 1,
annualPayments,
principalPaid,
interestPaid,
remainingBalance: yearRows[yearRows.length - 1]?.balance ?? 0,
cumulativeInterest,
});
}
return years;
}Repobility · code-quality intelligence · https://repobility.com
formatCurrency function · typescript · L359-L366 (8 LOC)src/lib/mortgage.ts
export function formatCurrency(value: number, decimals = 0): string {
return new Intl.NumberFormat("en-CA", {
style: "currency",
currency: "CAD",
minimumFractionDigits: decimals,
maximumFractionDigits: decimals,
}).format(value);
}formatPercent function · typescript · L368-L370 (3 LOC)src/lib/mortgage.ts
export function formatPercent(value: number, decimals = 2): string {
return `${(value * 100).toFixed(decimals)}%`;
}cleanup function · typescript · L17-L27 (11 LOC)src/lib/rate-limit.ts
function cleanup() {
const now = Date.now();
if (now - lastCleanup < CLEANUP_INTERVAL) return;
lastCleanup = now;
for (const [key, entry] of rateLimitMap) {
if (now > entry.resetAt) {
rateLimitMap.delete(key);
}
}
}rateLimit function · typescript · L46-L76 (31 LOC)src/lib/rate-limit.ts
export function rateLimit(
identifier: string,
options: RateLimitOptions
): RateLimitResult {
cleanup();
const now = Date.now();
const windowMs = options.windowSeconds * 1000;
const key = identifier;
const entry = rateLimitMap.get(key);
// No existing entry or window expired — start fresh
if (!entry || now > entry.resetAt) {
rateLimitMap.set(key, { count: 1, resetAt: now + windowMs });
return { success: true, remaining: options.limit - 1, resetAt: now + windowMs };
}
// Within window — increment
entry.count += 1;
if (entry.count > options.limit) {
return { success: false, remaining: 0, resetAt: entry.resetAt };
}
return {
success: true,
remaining: options.limit - entry.count,
resetAt: entry.resetAt,
};
}getIP function · typescript · L82-L90 (9 LOC)src/lib/rate-limit.ts
export function getIP(request: Request): string {
const forwarded = request.headers.get("x-forwarded-for");
if (forwarded) return forwarded.split(",")[0].trim();
const realIP = request.headers.get("x-real-ip");
if (realIP) return realIP;
return "127.0.0.1";
}cn function · typescript · L4-L6 (3 LOC)src/lib/utils.ts
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}‹ prevpage 3 / 3