73 lines · 2.5 KB
import { meterDef } from "./meters";
import type { MeterId } from "./meters";
import { CONTAINER_SPECS, MARKUP, METER_PRICES, RESOURCE_RATES, containerPricePerHour, creditPoolFor } from "./pricing";

const GB = 1024 ** 3;
const HOUR = 3600;
const MILLION = 1e6;
const THOUSAND = 1000;
const ONE_CENT = 0.01;
const DOLLARS_PER_MICRO_CENT = 1e-8;

export function usd(dollars: number): string {
  if (dollars === 0) return "$0";
  if (dollars < ONE_CENT) return `$${Number(dollars.toPrecision(2))}`;
  if (dollars < 1) return `$${dollars.toFixed(3).replace(/0$/, "")}`;
  return `$${dollars.toFixed(2)}`;
}

/** A meter's overage price in the unit people think in: per hour, per GB-month, per million. Null when free. */
export function rateLabel(meter: string): string | null {
  const def = meterDef(meter);
  const price = (METER_PRICES as Record<string, number>)[meter] ?? 0;
  if (!def || price <= 0) return null;
  const perUnit = price * DOLLARS_PER_MICRO_CENT;
  if (def.unit === "seconds") return `${usd(perUnit * HOUR)} / hour`;
  if (def.unit === "bytes") return `${usd(perUnit * GB)} / GB${def.kind === "gauge" ? "-month" : ""}`;
  if (def.unit === "tokens") return `${usd(perUnit * MILLION)} / 1M tokens`;
  if (def.unit === "ms") return `${usd(perUnit * MILLION)} / 1M ms`;
  if (perUnit * THOUSAND >= ONE_CENT) return `${usd(perUnit * THOUSAND)} / 1,000`;
  return `${usd(perUnit * MILLION)} / 1M`;
}

export type RunnerTierRate = {
  meter: MeterId;
  instance: string;
  vcpu: number;
  memoryGib: number;
  diskGb: number;
  perHour: number;
  /** Standard-1 credit hours one hour on this tier uses. */