"use client"; import { useId } from "react"; import { ArrowRight, ArrowUpRight, Check, Cloud, Cpu, Info, Layers3, MapPin, Server, Database, ExternalLink, Globe2, KeyRound, PencilLine, CreditCard, LockKeyhole, Network, Plug, Sparkles, Terminal, Zap } from "lucide-react"; import { Badge } from "./badge"; import { BrandLoader } from "./brand-loader"; import { Button } from "./button"; import { Field } from "./field"; import { Input } from "./input"; import { Select } from "./select"; import { Popover, PopoverTrigger, PopoverContent } from "./popover"; import { Checkbox } from "./checkbox"; import { resolveLabels } from "./lib/labels"; import type { ReactNode } from "react"; export interface CloudMachineOption { id: string; name: string; family: string; vcpus: number; memoryGb: number; diskGb: number; transferGb: number; regions: string[]; monthlyCents: number; recommended: boolean; } export interface CloudRegionOption { id: string; name: string; country: string; } export interface CloudConfiguration { name: string; region: string; planId: string; overageCapCents: number; } /** Price, rather than catalog order or a recommendation, determines the starting configuration. */ export function cheapestCloudPlan(plans: CloudMachineOption[], region?: string, family?: string) { return plans.filter(p => (!region || p.regions.includes(region)) && (!family || p.family === family)) .reduce((lowest, plan) => !lowest || plan.monthlyCents < lowest.monthlyCents ? plan : lowest, undefined); } /** Prices are always USD; `locale` only changes how the amount is written. */ const money = (cents: number, locale: Intl.LocalesArgument = "en-US") => new Intl.NumberFormat(locale, { style: "currency", currency: "USD", maximumFractionDigits: cents % 100 ? 2 : 0 }).format(cents / 100); /** Interface text for CloudConfigurator. Plan, region and family names come from props. */ export interface CloudConfiguratorLabels { /** Product label above the heading, shown when `showEyebrow` is true. */ eyebrow: string; beta: string; title: string; description: string; /** Accessible name of the configuration section. */ editor: string; name: string; nameHint: string; /** Instance name placeholder; the `namePlaceholder` prop takes precedence. */ namePlaceholder: string; region: string; regionHelp: string; regionLoading: string; regionPlaceholder: string; family: string; familyHelp: string; configuration: string; configurationHelp: string; configurationPlaceholder: string; /** Description of a configuration option; `price` is already formatted with `locale`. */ planDescription: (price: string, recommended: boolean) => string; vcpu: string; memory: string; disk: string; transfer: string; /** Memory and disk size; `value` is the number of gigabytes. */ gigabytes: (value: string) => string; /** Included transfer; `value` is formatted with `locale`. */ terabytes: (value: string) => string; /** Summary of the collapsed spending-limit section. */ spendingLimit: string; /** Heading of the spending-limit help popover. */ spendingLimitHelpTitle: string; spendingLimitHelp: string; /** Visible text beside the spending-limit help button. */ spendingLimitHelpCaption: string; overageCap: string; overageCapHint: string; /** Accessible name of the price summary. */ summary: string; monthlyHosting: string; /** Text after the monthly price. */ perMonth: string; inclusions: readonly string[]; inferenceNoteTitle: string; inferenceNote: string; unavailable: string; continue: string; /** Continue button text while `busy`. */ preparingQuote: string; finePrint: string; selfHost: string; /** Accessible name of each field help button. */ fieldHelp: (label: string) => string; } export const defaultCloudConfiguratorLabels: CloudConfiguratorLabels = { eyebrow: "OMNIROUTE CLOUD", beta: "BETA", title: "Configure your gateway", description: "Choose a name, region, and resources. Connect your inference providers after setup.", editor: "Configure your instance", name: "Instance name", nameHint: "Shown in your dashboard. You can rename it later.", namePlaceholder: "e.g. Studio gateway", region: "Region", regionHelp: "Your gateway runs in this location. Choose somewhere close to the apps that send requests. Your chosen model providers may process data in other locations.", regionLoading: "Loading regions…", regionPlaceholder: "Choose a region", family: "Machine family", familyHelp: "Basic shares CPU time with other workloads. Premium families use different processors or storage. CPU-optimized configurations provide dedicated CPU capacity. This hosts your gateway; it does not run the AI models.", configuration: "Configuration", configurationHelp: "vCPU is processing capacity, RAM is working memory, and SSD is storage for your gateway. Start small and choose more resources for larger teams or heavier gateway traffic.", configurationPlaceholder: "Choose resources", planDescription: (price, recommended) => `${price}/month${recommended ? " · Recommended" : ""}`, vcpu: "vCPU", memory: "RAM", disk: "SSD", transfer: "transfer", gigabytes: (value) => `${value} GB`, terabytes: (value) => `${value} TB`, spendingLimit: "Bandwidth spending limit", spendingLimitHelpTitle: "Transfer and spending limits", spendingLimitHelp: "Transfer is data your gateway sends out. The plan includes a monthly allowance. This cap limits additional transfer fees, separate from your hosting price and inference charges. At the cap, inference traffic pauses until the allowance resets or the cap increases.", spendingLimitHelpCaption: "How this limit works", overageCap: "Maximum monthly overage (USD)", overageCapHint: "Extra transfer is $0.0125/GB. At your limit, inference traffic pauses; your dashboard stays available.", summary: "Hosting summary", monthlyHosting: "Monthly hosting", perMonth: "/ month", inclusions: ["Dedicated OmniRoute instance", "Managed HTTPS, updates, and monitoring", "Daily backups with recovery"], inferenceNoteTitle: "Inference is billed separately.", inferenceNote: "Connect Cheaper Inference or bring your own provider keys after setup.", unavailable: "Cloud setup is not available yet. Your self-hosted OmniRoute remains free to use.", continue: "Review hosting", preparingQuote: "Preparing your quote…", finePrint: "No payment until you confirm at checkout.", selfHost: "Self-hosting instructions", fieldHelp: (label) => `About ${label}`, }; /** Shared Cloud configuration pattern; fetching, quoting, payment and routing belong to the app. */ export interface CloudConfiguratorProps { value: CloudConfiguration; onChange: (value: CloudConfiguration) => void; plans: CloudMachineOption[]; regions: CloudRegionOption[]; onContinue: () => void; busy?: boolean; loading?: boolean; error?: string | null; unavailable?: boolean; disabled?: boolean; selfHostHref: string; /** Takes precedence over `labels.namePlaceholder`. */ namePlaceholder?: string; /** Omit when a surrounding shell already supplies the Cloud product breadcrumb. */ showEyebrow?: boolean; /** Localized interface text; omitted or `undefined` keys fall back to defaultCloudConfiguratorLabels. */ labels?: Partial; /** Formats prices, transfer and country names (default "en-US"). Prices stay in USD. */ locale?: Intl.LocalesArgument; } /** Interface text for CloudFieldHelp. The heading and explanation come from props. */ export interface CloudFieldHelpLabels { /** Accessible name of the help button. */ trigger: (label: string) => string; } export const defaultCloudFieldHelpLabels: CloudFieldHelpLabels = { trigger: (label) => `About ${label}`, }; export interface CloudFieldHelpProps { /** Field name; it heads the popover and names the dialog. */ label: string; children: ReactNode; /** Localized interface text; omitted or `undefined` keys fall back to defaultCloudFieldHelpLabels. */ labels?: Partial; } /** Clickable help works with touch and keyboard as well as a pointer. */ export function CloudFieldHelp({ label, children, labels: labelOverrides }: CloudFieldHelpProps) { const labels = resolveLabels(defaultCloudFieldHelpLabels, labelOverrides); const headingId = useId(); return {label}

{children}

; } function FamilyIcon({ family }: { family: string }) { const Icon = /cpu/i.test(family) ? Cpu : /memory/i.test(family) ? Database : /storage/i.test(family) ? Network : /intel|amd/i.test(family) ? Cpu : Layers3; return