Add URL→PDF endpoint, usage tracking middleware, free tier limits

This commit is contained in:
DocFast Bot 2026-02-14 13:02:40 +00:00
parent 8e03b8ab3c
commit 6896b72e0c
5 changed files with 158 additions and 4 deletions

68
src/middleware/usage.ts Normal file
View file

@ -0,0 +1,68 @@
import { Request, Response, NextFunction } from "express";
interface UsageRecord {
count: number;
monthKey: string;
}
// In-memory usage tracking (replace with Redis/DB for production)
const usage = new Map<string, UsageRecord>();
const FREE_TIER_LIMIT = 50; // 50 PDFs/month for free tier
const PRO_KEYS = new Set(
(process.env.PRO_KEYS || "").split(",").map((k) => k.trim()).filter(Boolean)
);
function getMonthKey(): string {
const d = new Date();
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`;
}
export function usageMiddleware(
req: Request,
res: Response,
next: NextFunction
): void {
const key = req.headers.authorization?.slice(7) || "unknown";
const monthKey = getMonthKey();
// Pro keys have no limit
if (PRO_KEYS.has(key)) {
trackUsage(key, monthKey);
next();
return;
}
// Free tier limit check
const record = usage.get(key);
if (record && record.monthKey === monthKey && record.count >= FREE_TIER_LIMIT) {
res.status(429).json({
error: "Free tier limit reached",
limit: FREE_TIER_LIMIT,
used: record.count,
upgrade: "Upgrade to Pro for unlimited conversions: https://docfast.dev/pricing",
});
return;
}
trackUsage(key, monthKey);
next();
}
function trackUsage(key: string, monthKey: string): void {
const record = usage.get(key);
if (!record || record.monthKey !== monthKey) {
usage.set(key, { count: 1, monthKey });
} else {
record.count++;
}
}
export function getUsageStats(): Record<string, { count: number; month: string }> {
const stats: Record<string, { count: number; month: string }> = {};
for (const [key, record] of usage) {
const masked = key.slice(0, 8) + "...";
stats[masked] = { count: record.count, month: record.monthKey };
}
return stats;
}