117 lines · 4.8 KB
import { first } from "../db";
import { forbidden, notFoundError } from "../errors";
import { canAdministerAccount, requireRepoAccess } from "../repos";
import type { Viewer } from "~/lib/types";
import { containerLimits, containersEnabled, containerStub } from "./container-config";
import {
  closeOrphanSession,
  containersAllowedFor,
  containerUsage,
  listContainerSessions,
  loadContainerSession,
} from "./container-meter";
import type { ContainerSessionRow, ContainerUsage } from "./container-meter";

export type ContainerOverview = {
  enabled: boolean;
  /** Whether the scope's plan (the account's, or the viewer's for a repo) includes containers. */
  allowed: boolean;
  idleMinutes: number;
  capHours: number;
  sessions: ContainerSessionRow[];
  /** Present for an account scope; a repo spans many billed accounts. */
  usage: ContainerUsage | null;
};

async function accountByName(name: string): Promise<{ id: string; name: string }> {
  const account = await first<{ id: string; name: string }>(
    "SELECT id, name FROM accounts WHERE name = ? COLLATE NOCASE",
    name,
  );
  if (!account) throw notFoundError("Account not found");
  return account;
}

/** The viewer themselves, or an org they own (site admins may see any account). */
export async function requireContainerAccount(
  viewer: Viewer,
  org: string | null,
): Promise<{ id: string; name: string }> {
  if (!org) return { id: viewer.id, name: viewer.name };