feat(core): display quota renewal date
Render subscription renewal dates and countdowns in quota output, normalize numeric period-end timestamps, and cover UTC and edge-case behavior.
This commit is contained in:
+35
-3
@@ -49,10 +49,42 @@ function creditsDetail(credits: CommandCodeCredits | null): string | undefined {
|
||||
return `Sources: ${parts.join(" / ")}`
|
||||
}
|
||||
|
||||
function subscriptionLine(subscription: CommandCodeSubscription): string {
|
||||
function parsePeriodEnd(value: string): Date | null {
|
||||
const trimmed = value.trim()
|
||||
const timestamp = /^\d+$/.test(trimmed) ? Number(trimmed) : Date.parse(trimmed)
|
||||
if (!Number.isFinite(timestamp) || timestamp < 0) return null
|
||||
const milliseconds = timestamp >= 1e12 ? timestamp : timestamp * 1000
|
||||
const date = new Date(milliseconds)
|
||||
return Number.isNaN(date.getTime()) ? null : date
|
||||
}
|
||||
|
||||
function subscriptionLine(
|
||||
subscription: CommandCodeSubscription,
|
||||
now: () => number = Date.now,
|
||||
): string {
|
||||
const plan = (subscription.planId ?? "Unknown").replace(/[_-]+/g, " ").trim()
|
||||
const status = subscription.status ? ` (${subscription.status})` : ""
|
||||
return `Plan: ${plan}${status}`
|
||||
let renewal = ""
|
||||
if (subscription.currentPeriodEnd) {
|
||||
const end = parsePeriodEnd(subscription.currentPeriodEnd)
|
||||
if (end) {
|
||||
const diffMs = end.getTime() - now()
|
||||
const days = Math.ceil(diffMs / 86_400_000)
|
||||
const dateStr = end.toLocaleDateString("en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
timeZone: "UTC",
|
||||
})
|
||||
if (days > 0) {
|
||||
renewal = ` · renews ${dateStr} (${days}d)`
|
||||
} else if (days === 0) {
|
||||
renewal = ` · renews ${dateStr} (today)`
|
||||
} else {
|
||||
renewal = ` · renewed ${dateStr}`
|
||||
}
|
||||
}
|
||||
}
|
||||
return `Plan: ${plan}${status}${renewal}`
|
||||
}
|
||||
|
||||
function formatTokens(tokens: number): string {
|
||||
@@ -77,7 +109,7 @@ export function formatQuota(quota: CommandCodeQuota, now: () => number = Date.no
|
||||
|
||||
const detail = creditsDetail(quota.credits)
|
||||
if (detail) lines.push(detail)
|
||||
if (quota.subscription) lines.push(subscriptionLine(quota.subscription))
|
||||
if (quota.subscription) lines.push(subscriptionLine(quota.subscription, now))
|
||||
|
||||
if (quota.summary) {
|
||||
lines.push("")
|
||||
|
||||
+9
-2
@@ -43,6 +43,13 @@ function stringValue(value: unknown): string | undefined {
|
||||
return typeof value === "string" && value.length > 0 ? value : undefined
|
||||
}
|
||||
|
||||
function timestampValue(value: unknown): string | undefined {
|
||||
const text = stringValue(value)
|
||||
if (text) return text
|
||||
const number = numberValue(value)
|
||||
return number === undefined ? undefined : String(number)
|
||||
}
|
||||
|
||||
function errorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error)
|
||||
}
|
||||
@@ -100,8 +107,8 @@ function parseSubscription(value: unknown): CommandCodeSubscription | null {
|
||||
const data = value.data
|
||||
const planId = stringValue(data.planId)
|
||||
const status = stringValue(data.status)
|
||||
const currentPeriodStart = stringValue(data.currentPeriodStart)
|
||||
const currentPeriodEnd = stringValue(data.currentPeriodEnd)
|
||||
const currentPeriodStart = timestampValue(data.currentPeriodStart)
|
||||
const currentPeriodEnd = timestampValue(data.currentPeriodEnd)
|
||||
if (!planId && !status && !currentPeriodStart && !currentPeriodEnd) return null
|
||||
return {
|
||||
planId: planId ?? null,
|
||||
|
||||
Reference in New Issue
Block a user