Initial commit: restructure to flat layout with ui/ and web/ at root

This commit is contained in:
2026-03-12 21:33:50 +08:00
commit decba25a08
1708 changed files with 199890 additions and 0 deletions

View File

@@ -0,0 +1,46 @@
import fs from 'fs';
import path from 'path';
import os from 'os';
const OPENCODE_CONFIG_DIR = path.join(os.homedir(), '.config', 'opencode');
const OPENCODE_DATA_DIR = path.join(os.homedir(), '.local', 'share', 'opencode');
export const ANTIGRAVITY_ACCOUNTS_PATHS = [
path.join(OPENCODE_CONFIG_DIR, 'antigravity-accounts.json'),
path.join(OPENCODE_DATA_DIR, 'antigravity-accounts.json')
];
export const readJsonFile = (filePath) => {
if (!fs.existsSync(filePath)) {
return null;
}
try {
const raw = fs.readFileSync(filePath, 'utf8');
const trimmed = raw.trim();
if (!trimmed) return null;
return JSON.parse(trimmed);
} catch (error) {
console.warn(`Failed to read JSON file: ${filePath}`, error);
return null;
}
};
export const getAuthEntry = (auth, aliases) => {
for (const alias of aliases) {
if (auth[alias]) {
return auth[alias];
}
}
return null;
};
export const normalizeAuthEntry = (entry) => {
if (!entry) return null;
if (typeof entry === 'string') {
return { token: entry };
}
if (typeof entry === 'object') {
return entry;
}
return null;
};

View File

@@ -0,0 +1,76 @@
export const formatResetTime = (timestamp) => {
try {
const resetDate = new Date(timestamp);
const now = new Date();
const isToday = resetDate.toDateString() === now.toDateString();
if (isToday) {
return resetDate.toLocaleTimeString(undefined, {
hour: 'numeric',
minute: '2-digit'
});
}
return resetDate.toLocaleString(undefined, {
month: 'short',
day: 'numeric',
weekday: 'short',
hour: 'numeric',
minute: '2-digit'
});
} catch {
return null;
}
};
export const calculateResetAfterSeconds = (resetAt) => {
if (!resetAt) return null;
const delta = Math.floor((resetAt - Date.now()) / 1000);
return delta < 0 ? 0 : delta;
};
export const toUsageWindow = ({ usedPercent, windowSeconds, resetAt, valueLabel }) => {
const resetAfterSeconds = calculateResetAfterSeconds(resetAt);
const resetFormatted = resetAt ? formatResetTime(resetAt) : null;
return {
usedPercent,
remainingPercent: usedPercent !== null ? Math.max(0, 100 - usedPercent) : null,
windowSeconds: windowSeconds ?? null,
resetAfterSeconds,
resetAt,
resetAtFormatted: resetFormatted,
resetAfterFormatted: resetFormatted,
...(valueLabel ? { valueLabel } : {})
};
};
export const buildResult = ({ providerId, providerName, ok, configured, usage, error }) => ({
providerId,
providerName,
ok,
configured,
usage: usage ?? null,
...(error ? { error } : {}),
fetchedAt: Date.now()
});
export const durationToLabel = (duration, unit) => {
if (!duration || !unit) return 'limit';
if (unit === 'TIME_UNIT_MINUTE') return `${duration}m`;
if (unit === 'TIME_UNIT_HOUR') return `${duration}h`;
if (unit === 'TIME_UNIT_DAY') return `${duration}d`;
return 'limit';
};
export const durationToSeconds = (duration, unit) => {
if (!duration || !unit) return null;
if (unit === 'TIME_UNIT_MINUTE') return duration * 60;
if (unit === 'TIME_UNIT_HOUR') return duration * 3600;
if (unit === 'TIME_UNIT_DAY') return duration * 86400;
return null;
};
export const formatMoney = (value) => {
if (typeof value !== 'number' || !Number.isFinite(value)) return null;
return value.toFixed(2);
};

View File

@@ -0,0 +1,10 @@
/**
* Quota Utilities
*
* Shared utility functions for quota calculations and formatting.
* @module quota/utils
*/
export * from './auth.js';
export * from './transformers.js';
export * from './formatters.js';

View File

@@ -0,0 +1,55 @@
export const asObject = (value) => (value && typeof value === 'object' ? value : null);
export const asNonEmptyString = (value) => {
if (typeof value !== 'string') return null;
const trimmed = value.trim();
return trimmed ? trimmed : null;
};
export const toNumber = (value) => {
if (typeof value === 'number' && Number.isFinite(value)) {
return value;
}
if (typeof value === 'string') {
const parsed = Number(value);
return Number.isFinite(parsed) ? parsed : null;
}
return null;
};
export const toTimestamp = (value) => {
if (!value) return null;
if (typeof value === 'number') {
return value < 1_000_000_000_000 ? value * 1000 : value;
}
if (typeof value === 'string') {
const parsed = Date.parse(value);
return Number.isNaN(parsed) ? null : parsed;
}
return null;
};
export const normalizeTimestamp = (value) => {
if (typeof value !== 'number') return null;
return value < 1_000_000_000_000 ? value * 1000 : value;
};
export const resolveWindowSeconds = (limit) => {
const ZAI_TOKEN_WINDOW_SECONDS = { 3: 3600 };
if (!limit || !limit.number) return null;
const unitSeconds = ZAI_TOKEN_WINDOW_SECONDS[limit.unit];
if (!unitSeconds) return null;
return unitSeconds * limit.number;
};
export const resolveWindowLabel = (windowSeconds) => {
if (!windowSeconds) return 'tokens';
if (windowSeconds % 86400 === 0) {
const days = windowSeconds / 86400;
return days === 7 ? 'weekly' : `${days}d`;
}
if (windowSeconds % 3600 === 0) {
return `${windowSeconds / 3600}h`;
}
return `${windowSeconds}s`;
};