import {z} from 'zod' export type ConfigPublish = {[key: string]: {publish?: ('0' | '1') | undefined}}; export type CreateApiApiUmbrellaV1ConfigPublishArgs = {body: {config?: ({apis?: ConfigPublish | undefined, website_backends?: ConfigPublish | undefined}) | undefined}}; export type CreateApiApiUmbrellaV1ConfigPublishOptions = {baseUrl: string, apiKey?: string | undefined, fetch?: typeof fetch | undefined}; export const apiServer = z.object({id: z.string().optional(), host: z.string(), port: z.number().int()}); export const apiUrlMatch = z.object({id: z.string().optional(), frontend_prefix: z.string(), backend_prefix: z.string()}); export const apiSettingsHeader = z.object({id: z.string().optional(), key: z.string().optional(), value: z.string().optional()}); export const apiSettingsRateLimit = z.object({id: z.string().optional(), duration: z.number().int().optional(), accuracy: z.number().int().optional(), limit_by: z.enum(["ip", "apiKey"]).optional(), distributed: z.boolean().optional(), response_headers: z.boolean().optional()}); export const apiSettings = z.object({id: z.string().optional(), append_query_string: z.string().optional(), headers: z.array(apiSettingsHeader).optional(), headers_string: z.string().optional(), default_response_headers: z.array(apiSettingsHeader).optional(), default_response_headers_string: z.string().optional(), override_response_headers: z.array(apiSettingsHeader).optional(), override_response_headers_string: z.string().optional(), http_basic_auth: z.string().optional(), require_https: z.enum(["required_return_error", "required_return_redirect", "transition_return_error", "transition_return_redirect optional"]).optional(), require_https_transition_start_at: z.string().optional(), disable_api_key: z.boolean().optional(), api_key_verification_level: z.enum(["none", "transition_email", "required_email"]).optional(), api_key_verification_transition_start_at: z.string().optional(), required_roles: z.array(z.string()).optional(), required_roles_override: z.boolean().optional(), allowed_ips: z.array(z.string()).optional(), allowed_referers: z.array(z.string()).optional(), rate_limit_mode: z.enum(["unlimited", "custom"]).optional(), rate_limits: z.array(apiSettingsRateLimit).optional(), anonymous_rate_limit_behavior: z.enum(["ip_fallback", "ip_only"]).optional(), authenticated_rate_limit_behavior: z.enum(["all", "api_key_only"]).optional(), pass_api_key_header: z.boolean().optional(), pass_api_key_query_param: z.boolean().optional(), error_templates: z.object({}).optional(), error_data: z.object({}).optional(), error_data_yaml_strings: z.object({}).optional()}); export const apiSubSettings = z.object({id: z.string().optional(), http_method: z.enum(["any", "GET", "POST", "PUT", "DELETE", "HEAD", "TRACE", "OPTIONS", "CONNECT", "PATCH"]).optional(), regex: z.string().optional(), settings: apiSettings.optional()}); export const apiRewrite = z.object({id: z.string().optional(), matcher_type: z.enum(["route", "regex"]).optional(), http_method: z.enum(["any", "GET", "POST", "PUT", "DELETE", "HEAD", "TRACE", "OPTIONS", "CONNECT", "PATCH"]).optional(), frontend_matcher: z.string().optional(), backend_replacement: z.string().optional()}); export const createdAt = z.string(); export const adminCreator = z.object({username: z.string().optional()}); export const updatedAt = z.string(); export const adminUpdater = z.object({username: z.string().optional()}); export const api = z.object({id: z.string().optional(), name: z.string(), sort_order: z.number().int().optional(), backend_protocol: z.enum(["http", "https"]), frontend_host: z.string(), backend_host: z.string(), servers: z.array(apiServer), url_matches: z.array(apiUrlMatch), balance_algorithm: z.enum(["least_conn", "round_robin", "ip_hash"]), settings: apiSettings.optional(), sub_settings: z.array(apiSubSettings).optional(), rewrites: z.array(apiRewrite).optional(), created_at: createdAt.optional(), creator: adminCreator.optional(), updated_at: updatedAt.optional(), updater: adminUpdater.optional()}); export const websiteBackend = z.object({id: z.string().optional(), frontend_host: z.string().optional(), backend_protocol: z.enum(["http", "https"]).optional(), server_host: z.string().optional(), server_port: z.number().int().optional(), created_at: createdAt.optional(), creator: adminCreator.optional(), updated_at: updatedAt.optional(), updater: adminUpdater.optional()}); export const configVersion = z.object({id: z.string().optional(), verison: z.string().optional(), config: z.object({apis: api.optional(), website_backends: websiteBackend.optional()}).optional(), created_at: createdAt.optional(), updated_at: updatedAt.optional()}); export const createApiApiUmbrellaV1ConfigPublishResponse = z.object({config_version: configVersion.optional()}); 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 }; /** * Publish API backend or website backend changes. * * POST /api-umbrella/v1/config/publish * * Also accepts auth: admin_auth_token */ export const createApiApiUmbrellaV1ConfigPublish = async (args: CreateApiApiUmbrellaV1ConfigPublishArgs, options: CreateApiApiUmbrellaV1ConfigPublishOptions) => { const {baseUrl, fetch: fetchFn = fetch, apiKey} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (apiKey !== undefined) headers.set("X-Api-Key", apiKey) const url = `${baseUrl.replace(/\/+$/, '')}/api-umbrella/v1/config/publish${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(createApiApiUmbrellaV1ConfigPublishResponse, await res.json()) };