import {z} from 'zod' export type GetApiBareMetalLocationsOptions = {baseUrl: string, fetch?: typeof fetch | undefined}; export const bareMetalSpecs = z.object({gpu_model: z.enum(["h100-sxm5-80gb", "v100-sxm2-16gb", "v100-sxm2-32gb", "v100-sxm3-32gb", "a100-sxm4-80gb", "a100-pcie-80gb", "a100-pcie-40gb", "a40-pcie-48gb", "a2-pcie-16gb", "l40s-pcie-48gb", "l40-pcie-48gb", "l4-pcie-24gb", "rtx6000ada-pcie-48gb", "rtx5000ada-pcie-32gb", "rtx4500ada-pcie-24gb", "rtx4000ada-pcie-20gb", "rtx4000sffada-pcie-20gb", "rtxa6000-pcie-48gb", "rtxa5500-pcie-24gb", "rtxa5000-pcie-24gb", "rtxa4500-pcie-20gb", "rtxa4000-pcie-16gb", "quadrortx8000-pcie-48gb", "quadrortx6000-pcie-48gb", "teslap4-pcie-8gb", "teslap100-sxm2-16gb", "teslap100-pcie-16gb", "teslam40-pcie-24gb", "geforcertx4090-pcie-24gb", "geforcertx4080super-pcie-16gb", "geforcertx4080-pcie-16gb", "geforcertx4070tisuper-pcie-16gb", "geforcertx3090ti-pcie-24gb", "geforcertx3090-pcie-24gb", "geforcertx3080ti-pcie-12gb", "geforcertx3080-pcie-10gb", "geforcertx3080lhr-pcie-10gb", "geforcertx3070ti-pcie-8gb", "geforcertx3070-pcie-8gb", "geforcertx3060ti-pcie-8gb", "geforcertx3060tilhr-pcie-8gb", "geforcertx3060lhr-pcie-12gb", "geforcertx3060-pcie-12gb", "geforcertx3050-pcie-8gb", "geforcertx2080ti-pcie-11gb", "geforcertx2080super-pcie-8gb", "geforcertx2060super-pcie-8gb", "geforcegtx1650-pcie-4gb", "geforcegtx1070-pcie-8gb", "geforcegtx1060-pcie-6gb", "geforcegtx1660super-pcie-6gb", "geforecegt710-pcie-1gb"]).optional(), gpu_count: z.number().int().gte(0).optional(), cpu_model: z.string().optional(), cpu_count: z.number().int().gte(0).optional(), ram_gb: z.number().int().gte(0).optional(), storage_gb: z.number().int().gte(0).optional()}); export const bareMetalLocation = z.object({id: z.string(), gpu_count_ethernet: z.number().int().gte(0), gpu_price_ethernet: z.string(), gpu_count_infiniband: z.number().int().gte(0), gpu_price_infiniband: z.string(), reserved_gpu_count_infiniband_cluster_one: z.number().int().gte(0).nullable().optional(), reserved_gpu_count_infiniband_cluster_two: z.number().int().gte(0).nullable().optional(), specs_per_node: bareMetalSpecs}); export const paginatedResultBareMetalLocation = z.object({results: z.array(bareMetalLocation), total_result_count: z.number().int().gte(0), has_previous: z.boolean(), has_next: z.boolean()}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * List of available baremetal locations * * GET /bare-metal/locations */ export const getApiBareMetalLocations = async (options: GetApiBareMetalLocationsOptions) => { const {baseUrl, fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") const url = `${baseUrl.replace(/\/+$/, '')}/bare-metal/locations${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(paginatedResultBareMetalLocation, await res.json()) };