diff options
| author | Frank <[email protected]> | 2026-01-14 21:20:23 -0500 |
|---|---|---|
| committer | Frank <[email protected]> | 2026-01-14 21:20:26 -0500 |
| commit | e03932e586e89cc30015e6a5006ed5e83881a05c (patch) | |
| tree | 5655f0c063b717399a71a07625a8d6db8a942a5f /packages/console/core | |
| parent | 6b019a125a93a9816f9ddec17dc04d2c6e9b4257 (diff) | |
| download | opencode-e03932e586e89cc30015e6a5006ed5e83881a05c.tar.gz opencode-e03932e586e89cc30015e6a5006ed5e83881a05c.zip | |
zen: black usage
Diffstat (limited to 'packages/console/core')
| -rw-r--r-- | packages/console/core/src/billing.ts | 17 | ||||
| -rw-r--r-- | packages/console/core/src/black.ts | 72 |
2 files changed, 73 insertions, 16 deletions
diff --git a/packages/console/core/src/billing.ts b/packages/console/core/src/billing.ts index 181055c4e..f052e6fc6 100644 --- a/packages/console/core/src/billing.ts +++ b/packages/console/core/src/billing.ts @@ -25,22 +25,7 @@ export namespace Billing { export const get = async () => { return Database.use(async (tx) => tx - .select({ - customerID: BillingTable.customerID, - subscriptionID: BillingTable.subscriptionID, - paymentMethodID: BillingTable.paymentMethodID, - paymentMethodType: BillingTable.paymentMethodType, - paymentMethodLast4: BillingTable.paymentMethodLast4, - balance: BillingTable.balance, - reload: BillingTable.reload, - reloadAmount: BillingTable.reloadAmount, - reloadTrigger: BillingTable.reloadTrigger, - monthlyLimit: BillingTable.monthlyLimit, - monthlyUsage: BillingTable.monthlyUsage, - timeMonthlyUsageUpdated: BillingTable.timeMonthlyUsageUpdated, - reloadError: BillingTable.reloadError, - timeReloadError: BillingTable.timeReloadError, - }) + .select() .from(BillingTable) .where(eq(BillingTable.workspaceID, Actor.workspace())) .then((r) => r[0]), diff --git a/packages/console/core/src/black.ts b/packages/console/core/src/black.ts index 0ecbc94a4..753d25808 100644 --- a/packages/console/core/src/black.ts +++ b/packages/console/core/src/black.ts @@ -1,6 +1,8 @@ import { z } from "zod" import { fn } from "./util/fn" import { Resource } from "@opencode-ai/console-resource" +import { centsToMicroCents } from "./util/price" +import { getWeekBounds } from "./util/date" export namespace BlackData { const Schema = z.object({ @@ -18,3 +20,73 @@ export namespace BlackData { return Schema.parse(json) }) } + +export namespace Black { + export const analyzeRollingUsage = fn( + z.object({ + usage: z.number().int(), + timeUpdated: z.date(), + }), + ({ usage, timeUpdated }) => { + const now = new Date() + const black = BlackData.get() + const rollingWindowMs = black.rollingWindow * 3600 * 1000 + const rollingLimitInMicroCents = centsToMicroCents(black.rollingLimit * 100) + const windowStart = new Date(now.getTime() - rollingWindowMs) + if (timeUpdated < windowStart) { + return { + status: "ok" as const, + resetInSec: black.rollingWindow * 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({ + usage: z.number().int(), + timeUpdated: z.date(), + }), + ({ usage, timeUpdated }) => { + const black = BlackData.get() + const now = new Date() + const week = getWeekBounds(now) + const fixedLimitInMicroCents = centsToMicroCents(black.fixedLimit * 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, + } + }, + ) +} |
