diff options
| author | Frank <[email protected]> | 2025-08-08 13:22:54 -0400 |
|---|---|---|
| committer | Frank <[email protected]> | 2025-08-08 13:24:32 -0400 |
| commit | 183e0911b76025a1f2a82e979d9834fec2131d0e (patch) | |
| tree | 9987c1753bd64d1ce1d174ab397f1a8c681f642c /cloud/core/src/billing.ts | |
| parent | c7bb19ad0712469063eab35589aa5d3602b0c5b1 (diff) | |
| download | opencode-183e0911b76025a1f2a82e979d9834fec2131d0e.tar.gz opencode-183e0911b76025a1f2a82e979d9834fec2131d0e.zip | |
wip: gateway
Diffstat (limited to 'cloud/core/src/billing.ts')
| -rw-r--r-- | cloud/core/src/billing.ts | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/cloud/core/src/billing.ts b/cloud/core/src/billing.ts new file mode 100644 index 000000000..1a7bb2946 --- /dev/null +++ b/cloud/core/src/billing.ts @@ -0,0 +1,71 @@ +import { Resource } from "sst" +import { Stripe } from "stripe" +import { Database, eq, sql } from "./drizzle" +import { BillingTable, UsageTable } from "./schema/billing.sql" +import { Actor } from "./actor" +import { fn } from "./util/fn" +import { z } from "zod" +import { Identifier } from "./identifier" +import { centsToMicroCents } from "./util/price" + +export namespace Billing { + export const stripe = () => + new Stripe(Resource.STRIPE_SECRET_KEY.value, { + apiVersion: "2025-03-31.basil", + }) + + export const get = async () => { + return Database.use(async (tx) => + tx + .select({ + customerID: BillingTable.customerID, + paymentMethodID: BillingTable.paymentMethodID, + balance: BillingTable.balance, + reload: BillingTable.reload, + }) + .from(BillingTable) + .where(eq(BillingTable.workspaceID, Actor.workspace())) + .then((r) => r[0]), + ) + } + + export const consume = fn( + z.object({ + requestID: z.string().optional(), + model: z.string(), + inputTokens: z.number(), + outputTokens: z.number(), + reasoningTokens: z.number().optional(), + cacheReadTokens: z.number().optional(), + cacheWriteTokens: z.number().optional(), + costInCents: z.number(), + }), + async (input) => { + const workspaceID = Actor.workspace() + const cost = centsToMicroCents(input.costInCents) + + return await Database.transaction(async (tx) => { + await tx.insert(UsageTable).values({ + workspaceID, + id: Identifier.create("usage"), + requestID: input.requestID, + model: input.model, + inputTokens: input.inputTokens, + outputTokens: input.outputTokens, + reasoningTokens: input.reasoningTokens, + cacheReadTokens: input.cacheReadTokens, + cacheWriteTokens: input.cacheWriteTokens, + cost, + }) + const [updated] = await tx + .update(BillingTable) + .set({ + balance: sql`${BillingTable.balance} - ${cost}`, + }) + .where(eq(BillingTable.workspaceID, workspaceID)) + .returning() + return updated.balance + }) + }, + ) +} |
