mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-02-18 10:40:50 +08:00
165 lines
4.7 KiB
TypeScript
165 lines
4.7 KiB
TypeScript
/**
|
|
* Normalization and parsing functions for quota data.
|
|
*/
|
|
|
|
import type { CodexUsagePayload, GeminiCliQuotaPayload } from '@/types';
|
|
|
|
const GEMINI_CLI_MODEL_SUFFIX = '_vertex';
|
|
|
|
export function normalizeAuthIndexValue(value: unknown): string | null {
|
|
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
return value.toString();
|
|
}
|
|
if (typeof value === 'string') {
|
|
const trimmed = value.trim();
|
|
return trimmed ? trimmed : null;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function normalizeStringValue(value: unknown): string | null {
|
|
if (typeof value === 'string') {
|
|
const trimmed = value.trim();
|
|
return trimmed ? trimmed : null;
|
|
}
|
|
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
return value.toString();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function normalizeGeminiCliModelId(value: unknown): string | null {
|
|
const modelId = normalizeStringValue(value);
|
|
if (!modelId) return null;
|
|
if (modelId.endsWith(GEMINI_CLI_MODEL_SUFFIX)) {
|
|
return modelId.slice(0, -GEMINI_CLI_MODEL_SUFFIX.length);
|
|
}
|
|
return modelId;
|
|
}
|
|
|
|
export function normalizeNumberValue(value: unknown): number | null {
|
|
if (typeof value === 'number' && Number.isFinite(value)) return value;
|
|
if (typeof value === 'string') {
|
|
const trimmed = value.trim();
|
|
if (!trimmed) return null;
|
|
const parsed = Number(trimmed);
|
|
return Number.isFinite(parsed) ? parsed : null;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function normalizeQuotaFraction(value: unknown): number | null {
|
|
const normalized = normalizeNumberValue(value);
|
|
if (normalized !== null) return normalized;
|
|
if (typeof value === 'string') {
|
|
const trimmed = value.trim();
|
|
if (!trimmed) return null;
|
|
if (trimmed.endsWith('%')) {
|
|
const parsed = Number(trimmed.slice(0, -1));
|
|
return Number.isFinite(parsed) ? parsed / 100 : null;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function normalizePlanType(value: unknown): string | null {
|
|
const normalized = normalizeStringValue(value);
|
|
return normalized ? normalized.toLowerCase() : null;
|
|
}
|
|
|
|
export function decodeBase64UrlPayload(value: string): string | null {
|
|
const trimmed = value.trim();
|
|
if (!trimmed) return null;
|
|
try {
|
|
const normalized = trimmed.replace(/-/g, '+').replace(/_/g, '/');
|
|
const padded = normalized.padEnd(Math.ceil(normalized.length / 4) * 4, '=');
|
|
if (typeof window !== 'undefined' && typeof window.atob === 'function') {
|
|
return window.atob(padded);
|
|
}
|
|
if (typeof atob === 'function') {
|
|
return atob(padded);
|
|
}
|
|
} catch {
|
|
return null;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function parseIdTokenPayload(value: unknown): Record<string, unknown> | null {
|
|
if (!value) return null;
|
|
if (typeof value === 'object') {
|
|
return Array.isArray(value) ? null : (value as Record<string, unknown>);
|
|
}
|
|
if (typeof value !== 'string') return null;
|
|
const trimmed = value.trim();
|
|
if (!trimmed) return null;
|
|
try {
|
|
const parsed = JSON.parse(trimmed) as Record<string, unknown>;
|
|
if (parsed && typeof parsed === 'object') return parsed;
|
|
} catch {
|
|
// Continue to JWT parsing
|
|
}
|
|
const segments = trimmed.split('.');
|
|
if (segments.length < 2) return null;
|
|
const decoded = decodeBase64UrlPayload(segments[1]);
|
|
if (!decoded) return null;
|
|
try {
|
|
const parsed = JSON.parse(decoded) as Record<string, unknown>;
|
|
if (parsed && typeof parsed === 'object') return parsed;
|
|
} catch {
|
|
return null;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function parseAntigravityPayload(payload: unknown): Record<string, unknown> | null {
|
|
if (payload === undefined || payload === null) return null;
|
|
if (typeof payload === 'string') {
|
|
const trimmed = payload.trim();
|
|
if (!trimmed) return null;
|
|
try {
|
|
return JSON.parse(trimmed) as Record<string, unknown>;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
if (typeof payload === 'object') {
|
|
return payload as Record<string, unknown>;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function parseCodexUsagePayload(payload: unknown): CodexUsagePayload | null {
|
|
if (payload === undefined || payload === null) return null;
|
|
if (typeof payload === 'string') {
|
|
const trimmed = payload.trim();
|
|
if (!trimmed) return null;
|
|
try {
|
|
return JSON.parse(trimmed) as CodexUsagePayload;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
if (typeof payload === 'object') {
|
|
return payload as CodexUsagePayload;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function parseGeminiCliQuotaPayload(payload: unknown): GeminiCliQuotaPayload | null {
|
|
if (payload === undefined || payload === null) return null;
|
|
if (typeof payload === 'string') {
|
|
const trimmed = payload.trim();
|
|
if (!trimmed) return null;
|
|
try {
|
|
return JSON.parse(trimmed) as GeminiCliQuotaPayload;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
if (typeof payload === 'object') {
|
|
return payload as GeminiCliQuotaPayload;
|
|
}
|
|
return null;
|
|
}
|