diff options
| author | Frank <[email protected]> | 2026-02-22 18:41:34 -0500 |
|---|---|---|
| committer | Frank <[email protected]> | 2026-02-22 22:19:44 -0500 |
| commit | 5712cff5c453a185ac75a160f76ca06135d6ab2d (patch) | |
| tree | 6838fedd40aed31421265fdc8b9fe5826d396f86 /packages/console/core/src/subscription.ts | |
| parent | ee754c46f992dd4024e56e93246421246d16d13f (diff) | |
| download | opencode-5712cff5c453a185ac75a160f76ca06135d6ab2d.tar.gz opencode-5712cff5c453a185ac75a160f76ca06135d6ab2d.zip | |
zen: track session in usage
Diffstat (limited to 'packages/console/core/src/subscription.ts')
| -rw-r--r-- | packages/console/core/src/subscription.ts | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/packages/console/core/src/subscription.ts b/packages/console/core/src/subscription.ts new file mode 100644 index 000000000..ca3b17042 --- /dev/null +++ b/packages/console/core/src/subscription.ts @@ -0,0 +1,75 @@ +import { z } from "zod" +import { fn } from "./util/fn" +import { centsToMicroCents } from "./util/price" +import { getWeekBounds } from "./util/date" + +export namespace Subscription { + export const analyzeRollingUsage = fn( + z.object({ + limit: z.number().int(), + window: z.number().int(), + usage: z.number().int(), + timeUpdated: z.date(), + }), + ({ limit, window, usage, timeUpdated }) => { + const now = new Date() + const rollingWindowMs = window * 3600 * 1000 + const rollingLimitInMicroCents = centsToMicroCents(limit * 100) + const windowStart = new Date(now.getTime() - rollingWindowMs) + if (timeUpdated < windowStart) { + return { + status: "ok" as const, + resetInSec: window * 3600, + usagePercent: 0, + } + } + + const windowEnd = new Date(timeUpdated.getTime() + rollingWindowMs) + if (usage < rollingLimitInMicroCents) { + return { + status: "ok" as const, + resetInSec: Math.ceil((windowEnd.getTime() - now.getTime()) / 1000), + usagePercent: Math.ceil(Math.min(100, (usage / rollingLimitInMicroCents) * 100)), + } + } + return { + status: "rate-limited" as const, + resetInSec: Math.ceil((windowEnd.getTime() - now.getTime()) / 1000), + usagePercent: 100, + } + }, + ) + + export const analyzeWeeklyUsage = fn( + z.object({ + limit: z.number().int(), + usage: z.number().int(), + timeUpdated: z.date(), + }), + ({ limit, usage, timeUpdated }) => { + const now = new Date() + const week = getWeekBounds(now) + const fixedLimitInMicroCents = centsToMicroCents(limit * 100) + if (timeUpdated < week.start) { + return { + status: "ok" as const, + resetInSec: Math.ceil((week.end.getTime() - now.getTime()) / 1000), + usagePercent: 0, + } + } + if (usage < fixedLimitInMicroCents) { + return { + status: "ok" as const, + resetInSec: Math.ceil((week.end.getTime() - now.getTime()) / 1000), + usagePercent: Math.ceil(Math.min(100, (usage / fixedLimitInMicroCents) * 100)), + } + } + + return { + status: "rate-limited" as const, + resetInSec: Math.ceil((week.end.getTime() - now.getTime()) / 1000), + usagePercent: 100, + } + }, + ) +} |
