import z from "zod"; /** Per-environment configuration block — narrow projection of Altair's. */ export interface AltairEnvironment { readonly url?: string; readonly subscriptionsEndpoint?: string; readonly headers?: Readonly>; readonly variables?: Readonly>; } const environmentSchema = z .object({ url: z.string().optional(), subscriptionsEndpoint: z.string().optional(), headers: z.record(z.string(), z.string()).optional(), variables: z.record(z.string(), z.string()).optional(), }) .strict(); /** * Zod schema for {@link AltairUiOptions}. The schema is intentionally * permissive on header/environment values — operators can plug arbitrary * string values into the embedded shell — and strict on the four * structural fields (endpoints + theme). */ export const altairUiOptionsSchema = z .object({ uiEndpoint: z .string() .min(1) .startsWith("/", { message: "uiEndpoint must start with '/'", }) .default("/graphql/ui"), graphqlEndpoint: z .string() .min(1) .startsWith("/", { message: "graphqlEndpoint must start with '/'", }) .default("/graphql"), subscriptionEndpoint: z .string() .min(1) .startsWith("/", { message: "subscriptionEndpoint must start with '/'", }) .default("/graphql/ws"), theme: z.enum(["light", "dark", "system"]).default("system"), initialQuery: z.string().default(""), initialHeaders: z.record(z.string(), z.string()).default({}), initialEnvironments: z .record(z.string(), environmentSchema) .default({}), }) .strict(); /** Parsed, defaulted options consumed by `createAltairUi`. */ export type AltairUiOptions = z.infer; /** Caller-facing input — every field optional, defaults applied by Zod. */ export type AltairUiOptionsInput = z.input; /** * Validate caller-supplied options. Throws on shape violations; returns * a fully-defaulted, immutable `AltairUiOptions` on success. */ export function parseAltairUiOptions( input: AltairUiOptionsInput | undefined ): AltairUiOptions { return altairUiOptionsSchema.parse(input ?? {}); }