274 lines
7.3 KiB
TypeScript
274 lines
7.3 KiB
TypeScript
import {
|
|
formatCodexRemainingPercent,
|
|
formatCodexWindowDuration,
|
|
normalizeCodexResetTimestamp,
|
|
} from '@features/codex-account/renderer';
|
|
|
|
import type {
|
|
CodexAccountAuthMode,
|
|
CodexAccountEffectiveAuthMode,
|
|
} from '@features/codex-account/contracts';
|
|
import type { CliProviderAuthMode, CliProviderStatus } from '@shared/types';
|
|
|
|
export interface DashboardRateLimitItem {
|
|
label: string;
|
|
remaining: string;
|
|
resetsAt: string;
|
|
isDepleted: boolean;
|
|
}
|
|
|
|
export interface DashboardRateLimitSkeletonModeInput {
|
|
provider: CliProviderStatus;
|
|
sourceProvider?: CliProviderStatus | null;
|
|
configuredAuthModes?: {
|
|
anthropic?: CliProviderAuthMode | null;
|
|
codex?: CodexAccountAuthMode | CliProviderAuthMode | null;
|
|
};
|
|
}
|
|
|
|
function firstKnown<T>(...values: (T | null | undefined)[]): T | null {
|
|
for (const value of values) {
|
|
if (value !== null && typeof value !== 'undefined') {
|
|
return value;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function isCodexSubscriptionActive(
|
|
connection: CliProviderStatus['connection'] | null | undefined
|
|
): boolean {
|
|
return (
|
|
connection?.codex?.effectiveAuthMode === 'chatgpt' &&
|
|
(connection.codex.managedAccount?.type === 'chatgpt' || connection.codex.launchAllowed)
|
|
);
|
|
}
|
|
|
|
function isAnthropicSubscriptionActive(provider: CliProviderStatus): boolean {
|
|
return (
|
|
provider.providerId === 'anthropic' &&
|
|
provider.authenticated &&
|
|
provider.connection?.configuredAuthMode !== 'api_key' &&
|
|
(provider.authMethod === 'claude.ai' || provider.authMethod === 'oauth_token')
|
|
);
|
|
}
|
|
|
|
function getProviderConfiguredAuthMode({
|
|
provider,
|
|
sourceProvider,
|
|
configuredAuthModes,
|
|
}: DashboardRateLimitSkeletonModeInput): CliProviderAuthMode | null {
|
|
if (provider.providerId === 'anthropic') {
|
|
return firstKnown(
|
|
configuredAuthModes?.anthropic,
|
|
provider.connection?.configuredAuthMode,
|
|
sourceProvider?.connection?.configuredAuthMode
|
|
);
|
|
}
|
|
|
|
if (provider.providerId === 'codex') {
|
|
return firstKnown(
|
|
configuredAuthModes?.codex as CliProviderAuthMode | null | undefined,
|
|
provider.connection?.codex?.preferredAuthMode,
|
|
provider.connection?.configuredAuthMode,
|
|
sourceProvider?.connection?.codex?.preferredAuthMode,
|
|
sourceProvider?.connection?.configuredAuthMode
|
|
);
|
|
}
|
|
|
|
return firstKnown(
|
|
provider.connection?.configuredAuthMode,
|
|
sourceProvider?.connection?.configuredAuthMode
|
|
);
|
|
}
|
|
|
|
function getCodexEffectiveAuthMode(
|
|
provider: CliProviderStatus,
|
|
sourceProvider: CliProviderStatus | null | undefined
|
|
): CodexAccountEffectiveAuthMode {
|
|
return firstKnown(
|
|
provider.connection?.codex?.effectiveAuthMode,
|
|
sourceProvider?.connection?.codex?.effectiveAuthMode
|
|
) as CodexAccountEffectiveAuthMode;
|
|
}
|
|
|
|
export function isDashboardRateLimitSubscriptionMode({
|
|
provider,
|
|
sourceProvider = null,
|
|
configuredAuthModes,
|
|
}: DashboardRateLimitSkeletonModeInput): boolean {
|
|
if (provider.providerId === 'anthropic') {
|
|
const configuredAuthMode = getProviderConfiguredAuthMode({
|
|
provider,
|
|
sourceProvider,
|
|
configuredAuthModes,
|
|
});
|
|
|
|
if (configuredAuthMode === 'api_key') {
|
|
return false;
|
|
}
|
|
|
|
if (configuredAuthMode === 'oauth') {
|
|
return true;
|
|
}
|
|
|
|
return (
|
|
provider.authMethod === 'claude.ai' ||
|
|
provider.authMethod === 'oauth_token' ||
|
|
sourceProvider?.authMethod === 'claude.ai' ||
|
|
sourceProvider?.authMethod === 'oauth_token'
|
|
);
|
|
}
|
|
|
|
if (provider.providerId === 'codex') {
|
|
const configuredAuthMode = getProviderConfiguredAuthMode({
|
|
provider,
|
|
sourceProvider,
|
|
configuredAuthModes,
|
|
});
|
|
|
|
if (configuredAuthMode === 'api_key') {
|
|
return false;
|
|
}
|
|
|
|
if (configuredAuthMode === 'chatgpt') {
|
|
return true;
|
|
}
|
|
|
|
return getCodexEffectiveAuthMode(provider, sourceProvider) === 'chatgpt';
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
export function shouldShowDashboardRateLimitSkeleton(
|
|
input: DashboardRateLimitSkeletonModeInput
|
|
): boolean {
|
|
return isDashboardRateLimitSubscriptionMode(input);
|
|
}
|
|
|
|
function buildRateLimitLabel(
|
|
fallbackTitle: 'Primary left' | 'Secondary left' | 'Weekly left',
|
|
windowDurationMins: number | null | undefined
|
|
): string {
|
|
const duration = formatCodexWindowDuration(windowDurationMins);
|
|
return duration ? `${duration} left` : fallbackTitle;
|
|
}
|
|
|
|
function buildAnthropicRateLimitLabel(
|
|
fallbackTitle: 'Primary left' | 'Secondary left' | 'Weekly left',
|
|
windowDurationMins: number | null | undefined
|
|
): string {
|
|
if (windowDurationMins === 10_080) {
|
|
return 'Weekly left';
|
|
}
|
|
|
|
return buildRateLimitLabel(fallbackTitle, windowDurationMins);
|
|
}
|
|
|
|
function formatDashboardResetTime(timestampSeconds: number | null | undefined): string {
|
|
const normalized = normalizeCodexResetTimestamp(timestampSeconds);
|
|
if (!normalized) {
|
|
return 'reset unknown';
|
|
}
|
|
|
|
return new Date(normalized).toLocaleString(undefined, {
|
|
month: 'short',
|
|
day: 'numeric',
|
|
hour: 'numeric',
|
|
minute: '2-digit',
|
|
});
|
|
}
|
|
|
|
function isRateLimitDepleted(usedPercent: number | null | undefined): boolean {
|
|
return typeof usedPercent === 'number' && Number.isFinite(usedPercent) && usedPercent >= 100;
|
|
}
|
|
|
|
function buildRateLimitItem(
|
|
label: string,
|
|
usedPercent: number,
|
|
resetsAt: number | null | undefined
|
|
): DashboardRateLimitItem {
|
|
return {
|
|
label,
|
|
remaining: formatCodexRemainingPercent(usedPercent) ?? 'Unknown',
|
|
resetsAt: formatDashboardResetTime(resetsAt),
|
|
isDepleted: isRateLimitDepleted(usedPercent),
|
|
};
|
|
}
|
|
|
|
export function getCodexDashboardRateLimits(
|
|
provider: CliProviderStatus
|
|
): DashboardRateLimitItem[] | null {
|
|
if (provider.providerId !== 'codex' || !isCodexSubscriptionActive(provider.connection)) {
|
|
return null;
|
|
}
|
|
|
|
const rateLimits = provider.connection?.codex?.rateLimits;
|
|
if (!rateLimits?.primary) {
|
|
return null;
|
|
}
|
|
|
|
const items: DashboardRateLimitItem[] = [
|
|
buildRateLimitItem(
|
|
buildRateLimitLabel('Primary left', rateLimits.primary.windowDurationMins),
|
|
rateLimits.primary.usedPercent,
|
|
rateLimits.primary.resetsAt
|
|
),
|
|
];
|
|
|
|
if (rateLimits.secondary) {
|
|
items.push(
|
|
buildRateLimitItem(
|
|
buildRateLimitLabel(
|
|
rateLimits.secondary.windowDurationMins === 10_080 ? 'Weekly left' : 'Secondary left',
|
|
rateLimits.secondary.windowDurationMins
|
|
),
|
|
rateLimits.secondary.usedPercent,
|
|
rateLimits.secondary.resetsAt
|
|
)
|
|
);
|
|
}
|
|
|
|
return items;
|
|
}
|
|
|
|
export function getAnthropicDashboardRateLimits(
|
|
provider: CliProviderStatus
|
|
): DashboardRateLimitItem[] | null {
|
|
if (!isAnthropicSubscriptionActive(provider)) {
|
|
return null;
|
|
}
|
|
|
|
const rateLimits = provider.subscriptionRateLimits;
|
|
if (!rateLimits?.primary && !rateLimits?.secondary) {
|
|
return null;
|
|
}
|
|
|
|
const items: DashboardRateLimitItem[] = [];
|
|
if (rateLimits.primary) {
|
|
items.push(
|
|
buildRateLimitItem(
|
|
buildAnthropicRateLimitLabel('Primary left', rateLimits.primary.windowDurationMins),
|
|
rateLimits.primary.usedPercent,
|
|
rateLimits.primary.resetsAt
|
|
)
|
|
);
|
|
}
|
|
|
|
if (rateLimits.secondary) {
|
|
items.push(
|
|
buildRateLimitItem(
|
|
buildAnthropicRateLimitLabel(
|
|
rateLimits.secondary.windowDurationMins === 10_080 ? 'Weekly left' : 'Secondary left',
|
|
rateLimits.secondary.windowDurationMins
|
|
),
|
|
rateLimits.secondary.usedPercent,
|
|
rateLimits.secondary.resetsAt
|
|
)
|
|
);
|
|
}
|
|
|
|
return items.length > 0 ? items : null;
|
|
}
|