import {z} from 'zod' export type TimeRange = {start: string, end: string}; export type CloudProvider = 'aws' | 'gcp' | 'azure' | 'ovh'; export type AwsRegion = 'af-south-1' | 'ap-east-1' | 'ap-northeast-1' | 'ap-northeast-2' | 'ap-northeast-3' | 'ap-south-1' | 'ap-south-2' | 'ap-southeast-2' | 'ap-southeast-3' | 'ap-southeast-4' | 'ap-southeast-5' | 'ap-southeast-7' | 'ca-central-1' | 'ca-west-1' | 'eu-central-1' | 'eu-central-2' | 'eu-north-1' | 'eu-south-1' | 'eu-south-2' | 'eu-west-1' | 'eu-west-2' | 'eu-west-3' | 'il-central-1' | 'me-central-1' | 'mx-central-1' | 'sa-east-1' | 'us-east-1' | 'us-east-2' | 'us-west-1' | 'us-west-2'; export type GcpRegion = 'asia-east1' | 'asia-northeast1' | 'asia-southeast1' | 'europe-north1' | 'europe-west1' | 'europe-west3' | 'europe-west4' | 'northamerica-northeast2' | 'southamerica-west1' | 'us-central1' | 'us-east1' | 'us-east4' | 'us-west1' | 'us-west2'; export type AzureRegion = 'australiacentral' | 'australiaeast' | 'australiasoutheast' | 'brazilsouth' | 'canadacentral' | 'canadaeast' | 'centralindia' | 'centralus' | 'chinaeast2' | 'chinanorth' | 'chinanorth2' | 'chinanorth3' | 'eastasia' | 'eastus' | 'eastus2' | 'francecentral' | 'germanywestcentral' | 'indonesiacentral' | 'israelcentral' | 'italynorth' | 'japaneast' | 'japanwest' | 'koreacentral' | 'mexicocentral' | 'newzealandnorth' | 'northcentralus' | 'northeurope' | 'norwayeast' | 'polandcentral' | 'southafricanorth' | 'southcentralus' | 'southindia' | 'spaincentral' | 'swedencentral' | 'switzerlandnorth' | 'uaenorth' | 'uksouth' | 'ukwest' | 'westcentralus' | 'westeurope' | 'westus' | 'westus2' | 'westus3'; export type OvhRegion = 'fr-strasbourg' | 'pl-warsaw'; export type CloudZone = {provider: CloudProvider, region: AwsRegion | GcpRegion | AzureRegion | OvhRegion}; export type ScheduleRequest = {windows: Array, duration: unknown, zones: Array, num_options?: (number | null) | undefined}; export type CreateApiV0ScheduleArgs = {body: ScheduleRequest}; export type CreateApiV0ScheduleOptions = {baseUrl: string, fetch?: typeof fetch | undefined}; export const cloudProvider = z.enum(["aws", "gcp", "azure", "ovh"]); export const awsRegion = z.enum(["af-south-1", "ap-east-1", "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", "ap-south-1", "ap-south-2", "ap-southeast-2", "ap-southeast-3", "ap-southeast-4", "ap-southeast-5", "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", "eu-central-2", "eu-north-1", "eu-south-1", "eu-south-2", "eu-west-1", "eu-west-2", "eu-west-3", "il-central-1", "me-central-1", "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", "us-west-1", "us-west-2"]); export const gcpRegion = z.enum(["asia-east1", "asia-northeast1", "asia-southeast1", "europe-north1", "europe-west1", "europe-west3", "europe-west4", "northamerica-northeast2", "southamerica-west1", "us-central1", "us-east1", "us-east4", "us-west1", "us-west2"]); export const azureRegion = z.enum(["australiacentral", "australiaeast", "australiasoutheast", "brazilsouth", "canadacentral", "canadaeast", "centralindia", "centralus", "chinaeast2", "chinanorth", "chinanorth2", "chinanorth3", "eastasia", "eastus", "eastus2", "francecentral", "germanywestcentral", "indonesiacentral", "israelcentral", "italynorth", "japaneast", "japanwest", "koreacentral", "mexicocentral", "newzealandnorth", "northcentralus", "northeurope", "norwayeast", "polandcentral", "southafricanorth", "southcentralus", "southindia", "spaincentral", "swedencentral", "switzerlandnorth", "uaenorth", "uksouth", "ukwest", "westcentralus", "westeurope", "westus", "westus2", "westus3"]); export const ovhRegion = z.enum(["fr-strasbourg", "pl-warsaw"]); export const cloudZone = z.object({provider: cloudProvider, region: z.union([awsRegion, gcpRegion, azureRegion, ovhRegion])}); export const scheduleOption = z.object({time: z.string(), zone: cloudZone, co2_intensity: z.number()}); export const carbonSavings = z.object({vs_worst_case: z.number(), vs_naive_case: z.number(), vs_median_case: z.number()}); export const scheduleResponse = z.object({ideal: scheduleOption, options: z.array(scheduleOption), worst_case: scheduleOption, naive_case: scheduleOption, median_case: scheduleOption, carbon_savings: carbonSavings}); 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 }; /** * Schedule * * POST /v0/schedule/ */ export const createApiV0Schedule = async (args: CreateApiV0ScheduleArgs, options: CreateApiV0ScheduleOptions) => { const {baseUrl, fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") const url = `${baseUrl.replace(/\/+$/, '')}/v0/schedule/${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "POST", headers, body: JSON.stringify(args.body)}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(scheduleResponse, await res.json()) };