Spaces:
Running
Running
| import crypto from 'node:crypto'; | |
| export function maskAccount(value) { | |
| const text = String(value || '').trim(); | |
| if (!text) { | |
| return 'Codex'; | |
| } | |
| const emailMatch = text.match(/^(.)([^@]*)(@.+)$/); | |
| if (emailMatch) { | |
| return `${emailMatch[1]}***${emailMatch[3]}`; | |
| } | |
| if (text.length <= 6) { | |
| return `${text.slice(0, 1)}***`; | |
| } | |
| return `${text.slice(0, 3)}***${text.slice(-2)}`; | |
| } | |
| export function safeId(...values) { | |
| const source = values.find((value) => value) || crypto.randomUUID(); | |
| return crypto.createHash('sha256').update(String(source)).digest('hex').slice(0, 16); | |
| } | |
| export function normalizePlan(value, fallback = '') { | |
| const text = String(value || fallback || '').trim().toLowerCase(); | |
| if (!text) { | |
| return ''; | |
| } | |
| if (text.includes('team')) { | |
| return 'Team'; | |
| } | |
| if (text.includes('plus')) { | |
| return 'Plus'; | |
| } | |
| if (text.includes('prolite') || text.includes('pro_lite') || text.includes('pro 5')) { | |
| return 'Pro 5x'; | |
| } | |
| if (text.includes('pro')) { | |
| return 'Pro 20x'; | |
| } | |
| if (text.includes('free')) { | |
| return 'Free'; | |
| } | |
| return text.slice(0, 1).toUpperCase() + text.slice(1); | |
| } | |
| export function planFromFileName(fileName) { | |
| const match = String(fileName || '').match(/-([A-Za-z0-9_]+)\.json$/); | |
| return match ? match[1] : ''; | |
| } | |
| export function authEntryName(entry) { | |
| return String(entry?.name || entry?.fileName || entry?.id || '').trim(); | |
| } | |
| export function authEntryAccountId(entry) { | |
| return String( | |
| entry?.id_token?.chatgpt_account_id || | |
| entry?.id_token?.chatgptAccountId || | |
| entry?.metadata?.id_token?.chatgpt_account_id || | |
| entry?.metadata?.id_token?.chatgptAccountId || | |
| entry?.account_id || | |
| entry?.accountId || | |
| '' | |
| ).trim(); | |
| } | |
| export function authEntryPlan(entry) { | |
| return ( | |
| entry?.plan_type || | |
| entry?.planType || | |
| entry?.id_token?.plan_type || | |
| entry?.id_token?.planType || | |
| entry?.metadata?.id_token?.plan_type || | |
| entry?.metadata?.id_token?.planType || | |
| planFromFileName(authEntryName(entry)) | |
| ); | |
| } | |
| export function numberOrNull(value) { | |
| if (typeof value === 'number' && Number.isFinite(value)) { | |
| return value; | |
| } | |
| if (typeof value === 'string') { | |
| const trimmed = value.trim(); | |
| if (!trimmed) { | |
| return null; | |
| } | |
| const normalized = trimmed.endsWith('%') ? trimmed.slice(0, -1) : trimmed; | |
| const parsed = Number(normalized); | |
| return Number.isFinite(parsed) ? parsed : null; | |
| } | |
| return null; | |
| } | |
| export function normalizePercent(value, limitReached, allowed) { | |
| const parsed = numberOrNull(value); | |
| if (parsed !== null) { | |
| return Math.max(0, Math.min(100, parsed)); | |
| } | |
| if (limitReached || allowed === false) { | |
| return 100; | |
| } | |
| return null; | |
| } | |
| export function windowSeconds(window) { | |
| return numberOrNull(window?.limit_window_seconds ?? window?.limitWindowSeconds); | |
| } | |
| export function slugLabel(value, fallback) { | |
| const text = String(value || fallback || '').trim(); | |
| if (!text) { | |
| return 'additional'; | |
| } | |
| return text | |
| .toLowerCase() | |
| .replace(/[^a-z0-9]+/g, '-') | |
| .replace(/^-+|-+$/g, '') || 'additional'; | |
| } | |
| export function resetLabel(window) { | |
| const value = | |
| window?.reset_after_seconds ?? | |
| window?.resetAfterSeconds ?? | |
| window?.reset_in ?? | |
| window?.resetIn ?? | |
| window?.ttl; | |
| const seconds = numberOrNull(value); | |
| if (!seconds || seconds <= 0) { | |
| return ''; | |
| } | |
| const hours = Math.floor(seconds / 3600); | |
| const minutes = Math.floor((seconds % 3600) / 60); | |
| if (hours > 0 && minutes > 0) { | |
| return `${hours}h ${minutes}m`; | |
| } | |
| if (hours > 0) { | |
| return `${hours}h`; | |
| } | |
| if (minutes > 0) { | |
| return `${minutes}m`; | |
| } | |
| return '<1m'; | |
| } | |
| export function selectPrimaryWindows(rateLimit) { | |
| const primary = rateLimit?.primary_window ?? rateLimit?.primaryWindow ?? null; | |
| const secondary = rateLimit?.secondary_window ?? rateLimit?.secondaryWindow ?? null; | |
| const candidates = [primary, secondary].filter(Boolean); | |
| let fiveHourWindow = null; | |
| let weeklyWindow = null; | |
| for (const candidate of candidates) { | |
| const seconds = windowSeconds(candidate); | |
| if (seconds === 18_000 && !fiveHourWindow) { | |
| fiveHourWindow = candidate; | |
| } else if (seconds === 604_800 && !weeklyWindow) { | |
| weeklyWindow = candidate; | |
| } | |
| } | |
| if (!fiveHourWindow && primary !== weeklyWindow) { | |
| fiveHourWindow = primary; | |
| } | |
| if (!weeklyWindow && secondary !== fiveHourWindow) { | |
| weeklyWindow = secondary; | |
| } | |
| return { fiveHourWindow, weeklyWindow }; | |
| } | |
| export function quotaWindow(id, label, window, rateLimit) { | |
| if (!window) { | |
| return null; | |
| } | |
| const usedPercent = normalizePercent( | |
| window.used_percent ?? window.usedPercent, | |
| rateLimit?.limit_reached ?? rateLimit?.limitReached, | |
| rateLimit?.allowed | |
| ); | |
| return { | |
| id, | |
| label, | |
| usedPercent, | |
| remainingPercent: usedPercent === null ? null : Math.max(0, Math.min(100, 100 - usedPercent)), | |
| displayPercent: usedPercent === null ? null : Math.max(0, Math.min(100, 100 - usedPercent)), | |
| resetLabel: resetLabel(window) | |
| }; | |
| } | |
| export function extractWindows(payload) { | |
| const rateLimit = payload?.rate_limit ?? payload?.rateLimit ?? null; | |
| if (!rateLimit) { | |
| return []; | |
| } | |
| const { fiveHourWindow, weeklyWindow } = selectPrimaryWindows(rateLimit); | |
| return [ | |
| quotaWindow('five-hour', '5 小时限额', fiveHourWindow, rateLimit), | |
| quotaWindow('weekly', '周限额', weeklyWindow, rateLimit) | |
| ].filter(Boolean); | |
| } | |
| export function quotaWindowsForRateLimit(rateLimit, labels) { | |
| if (!rateLimit) { | |
| return []; | |
| } | |
| const { fiveHourWindow, weeklyWindow } = selectPrimaryWindows(rateLimit); | |
| return [ | |
| quotaWindow(labels.fiveHourId, labels.fiveHourLabel, fiveHourWindow, rateLimit), | |
| quotaWindow(labels.weeklyId, labels.weeklyLabel, weeklyWindow, rateLimit) | |
| ].filter(Boolean); | |
| } | |
| export function additionalQuotaWindows(payload) { | |
| const limits = payload?.additional_rate_limits ?? payload?.additionalRateLimits; | |
| if (!Array.isArray(limits)) { | |
| return []; | |
| } | |
| return limits.flatMap((entry, index) => { | |
| const rateLimit = entry?.rate_limit ?? entry?.rateLimit ?? null; | |
| if (!rateLimit) { | |
| return []; | |
| } | |
| const rawName = | |
| entry?.limit_name ?? | |
| entry?.limitName ?? | |
| entry?.metered_feature ?? | |
| entry?.meteredFeature ?? | |
| `additional-${index + 1}`; | |
| const name = String(rawName || `additional-${index + 1}`).trim() || `additional-${index + 1}`; | |
| const slug = slugLabel(name, `additional-${index + 1}`); | |
| const primary = rateLimit.primary_window ?? rateLimit.primaryWindow ?? null; | |
| const secondary = rateLimit.secondary_window ?? rateLimit.secondaryWindow ?? null; | |
| return [ | |
| quotaWindow(`${slug}-five-hour-${index}`, `${name} 5 小时限额`, primary, rateLimit), | |
| quotaWindow(`${slug}-weekly-${index}`, `${name} 周限额`, secondary, rateLimit) | |
| ].filter(Boolean); | |
| }); | |
| } | |
| export function extractQuotaWindows(payload) { | |
| const rateLimit = payload?.rate_limit ?? payload?.rateLimit ?? null; | |
| const codeReviewRateLimit = payload?.code_review_rate_limit ?? payload?.codeReviewRateLimit ?? null; | |
| return [ | |
| ...quotaWindowsForRateLimit(rateLimit, { | |
| fiveHourId: 'five-hour', | |
| fiveHourLabel: '5 小时限额', | |
| weeklyId: 'weekly', | |
| weeklyLabel: '周限额' | |
| }), | |
| ...quotaWindowsForRateLimit(codeReviewRateLimit, { | |
| fiveHourId: 'code-review-five-hour', | |
| fiveHourLabel: '代码审查 5 小时限额', | |
| weeklyId: 'code-review-weekly', | |
| weeklyLabel: '代码审查周限额' | |
| }), | |
| ...additionalQuotaWindows(payload) | |
| ]; | |
| } | |