From c60219e22921ecae9dc7ffb86d9ece41308400e4 Mon Sep 17 00:00:00 2001 From: vimtor Date: Sun, 17 May 2026 09:43:33 +0200 Subject: [PATCH] core: let Go referral rewards lower active usage limits --- packages/console/core/src/billing.ts | 40 +++++++++++++++++++++++++++ packages/console/core/src/referral.ts | 37 ++----------------------- 2 files changed, 42 insertions(+), 35 deletions(-) diff --git a/packages/console/core/src/billing.ts b/packages/console/core/src/billing.ts index ca3a40878e..bec9cf9d7a 100644 --- a/packages/console/core/src/billing.ts +++ b/packages/console/core/src/billing.ts @@ -18,6 +18,7 @@ import { centsToMicroCents } from "./util/price" import { User } from "./user" import { BlackData } from "./black" import { LiteData } from "./lite" +import { getMonthlyBounds, getWeekBounds } from "./util/date" export namespace Billing { export const ITEM_CREDIT_NAME = "opencode credits" @@ -155,6 +156,45 @@ export namespace Billing { return amountInMicroCents } + export const subtractLiteUsage = async (workspaceID: string, amountInMicroCents: number) => { + await Database.transaction(async (tx) => { + const lite = await tx + .select({ timeCreated: LiteTable.timeCreated }) + .from(LiteTable) + .where(and(eq(LiteTable.workspaceID, workspaceID), isNull(LiteTable.timeDeleted))) + .then((rows) => rows[0]) + if (!lite) throw new Error("Subscribe to Go before applying referral rewards") + + const now = new Date() + const week = getWeekBounds(now) + const month = getMonthlyBounds(now, lite.timeCreated) + const rollingWindowSeconds = LiteData.getLimits().rollingWindow * 3600 + await tx + .update(LiteTable) + .set({ + monthlyUsage: sql` + CASE + WHEN ${LiteTable.timeMonthlyUpdated} >= ${month.start} THEN GREATEST(0, COALESCE(${LiteTable.monthlyUsage}, 0) - ${amountInMicroCents}) + ELSE ${LiteTable.monthlyUsage} + END + `, + weeklyUsage: sql` + CASE + WHEN ${LiteTable.timeWeeklyUpdated} >= ${week.start} THEN GREATEST(0, COALESCE(${LiteTable.weeklyUsage}, 0) - ${amountInMicroCents}) + ELSE ${LiteTable.weeklyUsage} + END + `, + rollingUsage: sql` + CASE + WHEN UNIX_TIMESTAMP(${LiteTable.timeRollingUpdated}) >= UNIX_TIMESTAMP(now()) - ${rollingWindowSeconds} THEN GREATEST(0, COALESCE(${LiteTable.rollingUsage}, 0) - ${amountInMicroCents}) + ELSE ${LiteTable.rollingUsage} + END + `, + }) + .where(and(eq(LiteTable.workspaceID, workspaceID), isNull(LiteTable.timeDeleted))) + }) + } + export const redeemCoupon = async (email: string, type: (typeof CouponType)[number]) => { const coupon = await Database.use((tx) => tx diff --git a/packages/console/core/src/referral.ts b/packages/console/core/src/referral.ts index 29461ed72a..6c80baa990 100644 --- a/packages/console/core/src/referral.ts +++ b/packages/console/core/src/referral.ts @@ -8,10 +8,9 @@ import { ReferralRewardTable, ReferralTable } from "./schema/referral.sql" import { AuthTable } from "./schema/auth.sql" import { UserTable } from "./schema/user.sql" import { WorkspaceTable } from "./schema/workspace.sql" -import { LiteData } from "./lite" import { centsToMicroCents, microCentsToCents } from "./util/price" -import { getMonthlyBounds, getWeekBounds } from "./util/date" import { fn } from "./util/fn" +import { Billing } from "./billing" export namespace Referral { export const REWARD_AMOUNT = centsToMicroCents(500) @@ -183,13 +182,6 @@ export namespace Referral { if (!reward) throw new Error("Referral reward not found") if (reward.timeApplied) return { applied: false } - const lite = await tx - .select({ id: LiteTable.id, timeCreated: LiteTable.timeCreated }) - .from(LiteTable) - .where(and(eq(LiteTable.workspaceID, workspaceID), isNull(LiteTable.timeDeleted))) - .then((rows) => rows[0]) - if (!lite) throw new Error("Subscribe to Go before applying referral rewards") - const update = await tx .update(ReferralRewardTable) .set({ @@ -205,32 +197,7 @@ export namespace Referral { ) if (update.rowsAffected === 0) return { applied: false } - const week = getWeekBounds(new Date()) - const month = getMonthlyBounds(new Date(), lite.timeCreated) - const rollingWindowSeconds = LiteData.getLimits().rollingWindow * 3600 - await tx - .update(LiteTable) - .set({ - monthlyUsage: sql` - CASE - WHEN ${LiteTable.timeMonthlyUpdated} >= ${month.start} THEN GREATEST(0, COALESCE(${LiteTable.monthlyUsage}, 0) - ${reward.amount}) - ELSE ${LiteTable.monthlyUsage} - END - `, - weeklyUsage: sql` - CASE - WHEN ${LiteTable.timeWeeklyUpdated} >= ${week.start} THEN GREATEST(0, COALESCE(${LiteTable.weeklyUsage}, 0) - ${reward.amount}) - ELSE ${LiteTable.weeklyUsage} - END - `, - rollingUsage: sql` - CASE - WHEN UNIX_TIMESTAMP(${LiteTable.timeRollingUpdated}) >= UNIX_TIMESTAMP(now()) - ${rollingWindowSeconds} THEN GREATEST(0, COALESCE(${LiteTable.rollingUsage}, 0) - ${reward.amount}) - ELSE ${LiteTable.rollingUsage} - END - `, - }) - .where(and(eq(LiteTable.workspaceID, workspaceID), isNull(LiteTable.timeDeleted))) + await Billing.subtractLiteUsage(workspaceID, reward.amount) return { applied: true, amount: microCentsToCents(reward.amount) } })