59 lines · 2.4 KB
import { createServerFn } from "@tanstack/react-start";
import { z } from "zod";
import { requireViewer, viewerMiddleware } from "./middleware";
import { forbidden } from "~/server/errors";
import { limitWrite } from "~/server/limits";
import { billingAccountFor, requireSiteAdmin, topUsage } from "~/server/metering/access";
import { setPlan, setSpendingLimit } from "~/server/metering/quota";
import { periodOf } from "~/server/metering/record";
import { usageSummary } from "~/server/metering/summary";

const period = z
  .string()
  .regex(/^\d{4}-(0[1-9]|1[0-2])$/)
  .optional();
const org = z.string().min(1).max(100).nullable();

export const getBilling = createServerFn({ method: "GET" })
  .middleware([viewerMiddleware])
  .validator(z.object({ org, period }))
  .handler(async ({ data, context }) => {
    const viewer = requireViewer(context.viewer);
    const account = await billingAccountFor(viewer, data.org);
    const summary = await usageSummary(account.accountId, data.period ?? periodOf());
    return { account, summary };
  });

export const updateSpendingLimit = createServerFn({ method: "POST" })
  .middleware([viewerMiddleware])
  .validator(z.object({ org, cents: z.number().int().min(0).max(100_000_000).nullable() }))
  .handler(async ({ data, context }) => {
    const viewer = requireViewer(context.viewer);
    await limitWrite(viewer);
    const account = await billingAccountFor(viewer, data.org);
    if (!account.canEdit) throw forbidden("Only organization owners can change the spending limit");
    await setSpendingLimit(account.accountId, data.cents);
    return { ok: true };
  });

export const getAdminBilling = createServerFn({ method: "GET" })
  .middleware([viewerMiddleware])