Spaces:
Running
Running
Download src/services/usageService.js from hari7775/resume-server: direct link, hf CLI and curl.
- Browser
- Download file 2.91 kB
-
https://huggingface.co/spaces/hari7775/resume-server/resolve/main/src/services/usageService.js
- Command line
-
hf download hf://spaces/hari7775/resume-server/src/services/usageService.js
-
curl -L -o usageService.js https://huggingface.co/spaces/hari7775/resume-server/resolve/main/src/services/usageService.js
2.91 kB
| import { admin } from '../auth/firebase.js'; | |
| import { FREE_DAILY_PDF_LIMIT, PREMIUM_DAILY_PDF_LIMIT, USAGE_WRITE_TIMEOUT_MS } from '../config.js'; | |
| const DATE_RE = /^\d{4}-\d{2}-\d{2}$/; | |
| const DAY_MS = 24 * 60 * 60 * 1000; | |
| function utcISODate(ms = Date.now()) { | |
| return new Date(ms).toISOString().slice(0, 10); | |
| } | |
| function shiftISODate(isoDate, days) { | |
| return utcISODate(Date.parse(`${isoDate}T00:00:00Z`) + days * DAY_MS); | |
| } | |
| // The quota "day" is the user's local day, so the client sends its local date. | |
| // Accept it only when it is a real date within a day of UTC now (every timezone is), else use UTC. | |
| function resolveUsageDate(clientDate) { | |
| if (typeof clientDate === 'string' && DATE_RE.test(clientDate)) { | |
| const diff = Math.abs(Date.parse(`${clientDate}T00:00:00Z`) - Date.parse(`${utcISODate()}T00:00:00Z`)); | |
| if (diff <= DAY_MS) return clientDate; | |
| } | |
| return utcISODate(); | |
| } | |
| async function incrementUsage(uid, today) { | |
| const db = admin.firestore(); | |
| const usageRef = db.doc(`users/${uid}/usage/pdf_exports`); | |
| const userRef = db.doc(`users/${uid}`); | |
| const yesterday = shiftISODate(today, -1); | |
| await db.runTransaction(async (tx) => { | |
| const [usageSnap, userSnap] = await Promise.all([tx.get(usageRef), tx.get(userRef)]); | |
| const prev = usageSnap.exists ? usageSnap.data() : {}; | |
| const user = userSnap.exists ? userSnap.data() : {}; | |
| const isPremium = user.premium === true || user.isPremium === true; | |
| const count = (prev.date === today ? prev.count || 0 : 0) + 1; | |
| let streak = prev.streak || 0; | |
| let lastStreakDate = prev.lastStreakDate || null; | |
| if (lastStreakDate !== today) { | |
| streak = lastStreakDate === yesterday ? streak + 1 : 1; | |
| lastStreakDate = today; | |
| } | |
| tx.set(usageRef, { | |
| date: today, | |
| count, | |
| maxDaily: isPremium ? PREMIUM_DAILY_PDF_LIMIT : FREE_DAILY_PDF_LIMIT, | |
| streak, | |
| lastStreakDate, | |
| totalGenerations: admin.firestore.FieldValue.increment(1), | |
| updatedAt: admin.firestore.FieldValue.serverTimestamp() | |
| }, { merge: true }); | |
| }); | |
| } | |
| /** | |
| * Counts one finished PDF generation against the user's daily usage doc. | |
| * Never throws: a Firestore problem is logged and must not fail the PDF the user already got. | |
| */ | |
| export async function recordPdfGeneration(uid, clientDate) { | |
| if (!uid) return; | |
| let timer; | |
| try { | |
| await Promise.race([ | |
| incrementUsage(uid, resolveUsageDate(clientDate)), | |
| new Promise((_, reject) => { | |
| timer = setTimeout(() => reject(new Error('usage write timed out')), USAGE_WRITE_TIMEOUT_MS); | |
| }) | |
| ]); | |
| } catch (err) { | |
| console.error(`[Usage] Failed to record PDF generation for ${uid}:`, err.message); | |
| } finally { | |
| clearTimeout(timer); | |
| } | |
| } | |