import { resolve } from "node:path"; import { z } from "zod"; const schema = z.object({ NODE_ENV: z.enum(["development", "test", "production"]).default("production"), PORT: z.coerce.number().int().min(1).max(65535).default(7860), HARBOR_HF_NAMESPACE: z.string().min(1).max(160), HARBOR_HF_BUCKET_ID: z.string().min(3).max(320), HARBOR_HF_BUCKET_ROOT: z.string().min(1).default("/data"), HARBOR_HF_STORE_MODE: z.enum(["bucket", "filesystem"]).optional(), HARBOR_HF_PROJECTION_PATH: z.string().min(1).default("/tmp/harbor-hf/control.sqlite"), HARBOR_HF_AUTH_PATH: z.string().min(1).default("/tmp/harbor-hf/auth.sqlite"), HARBOR_HF_PROFILES_ROOT: z.string().min(1).default("./profiles"), HARBOR_HF_CAPACITY_PROFILE_ALIAS: z.string().min(2).max(160).optional(), HARBOR_HF_MAX_ACTIVE_JOBS: z.coerce.number().int().min(1).max(1024).default(16), HARBOR_HF_TASK_IMAGE_MIRROR_REPOSITORY: z .string() .regex( /^[a-z0-9]+(?:[.-][a-z0-9]+)*(?::[0-9]{1,5})?\/[a-z0-9]+(?:[._-][a-z0-9]+)*(?:\/[a-z0-9]+(?:[._-][a-z0-9]+)*)*$/, ) .default("ghcr.io/huggingface/harbor-hf-trial-worker"), HARBOR_HF_WEB_ROOT: z.string().min(1).default("./apps/control-web/dist"), HARBOR_HF_AUTH_MODE: z.enum(["oauth", "development"]).default("oauth"), HARBOR_HF_WRITE_MODE: z.enum(["disabled", "enabled"]).default("disabled"), HARBOR_HF_PUBLIC_ORIGIN: z.string().url().optional(), SPACE_HOST: z.string().min(1).optional(), OAUTH_CLIENT_ID: z.string().min(1).optional(), OAUTH_CLIENT_SECRET: z.string().min(1).optional(), OAUTH_SCOPES: z.string().min(1).default("openid profile"), OPENID_PROVIDER_URL: z.string().url().optional(), HF_TOKEN: z.string().min(8).optional(), HF_INFERENCE_TOKEN: z.string().min(8).optional(), HARBOR_HF_RECONCILE_INTERVAL_MS: z.coerce .number() .int() .min(100) .max(60000) .default(2000), HARBOR_HF_SYNC_INTERVAL_MS: z.coerce .number() .int() .min(1000) .max(300000) .default(30000), HARBOR_HF_OBSERVE_INTERVAL_MS: z.coerce .number() .int() .min(100) .max(300000) .default(5000), HARBOR_HF_WORKER_RECEIPT_GRACE_MS: z.coerce .number() .int() .min(0) .max(300000) .default(60000), HARBOR_HF_SOURCE_REVISION: z.string().min(7).max(160).default("development"), HARBOR_HF_BOOTSTRAP_OPERATOR_SUBJECTS: z.string().default(""), }); export interface AppConfig { node_env: "development" | "test" | "production"; port: number; namespace: string; bucket_id: string; bucket_root: string; store_mode: "bucket" | "filesystem"; projection_path: string; auth_path: string; profiles_root: string; capacity_profile_alias: string | null; max_active_jobs: number; task_image_mirror_repository: string; web_root: string; auth_mode: "oauth" | "development"; write_mode: "disabled" | "enabled"; public_origin: string; oauth: { issuer: string; client_id: string; client_secret: string; scopes: string; callback_url: string; session_ttl_seconds: number; } | null; hf_token: string | null; hf_inference_token: string | null; reconcile_interval_ms: number; sync_interval_ms: number; observe_interval_ms: number; worker_receipt_grace_ms: number; source_revision: string; bootstrap_operator_subjects: string[]; } function normalizePublicOrigin(value: string): string { const url = new URL(value); if ( !["http:", "https:"].includes(url.protocol) || url.username || url.password || url.pathname !== "/" || url.search || url.hash ) throw new Error("public origin must contain only an HTTP or HTTPS origin"); return url.origin; } export function loadConfig(environment: NodeJS.ProcessEnv = process.env): AppConfig { const parsed = schema.parse(environment); if (parsed.NODE_ENV === "production" && parsed.HARBOR_HF_AUTH_MODE !== "oauth") { throw new Error("production requires OAuth authentication"); } const storeMode = parsed.HARBOR_HF_STORE_MODE ?? (parsed.NODE_ENV === "production" ? "bucket" : "filesystem"); if (storeMode === "bucket" && !parsed.HF_TOKEN) { throw new Error("Bucket-backed service requires HF_TOKEN"); } if (parsed.HARBOR_HF_WRITE_MODE !== "disabled" && !parsed.HF_TOKEN) { throw new Error("write-enabled service requires HF_TOKEN"); } if ( parsed.HF_TOKEN && parsed.HF_INFERENCE_TOKEN && parsed.HF_TOKEN === parsed.HF_INFERENCE_TOKEN ) { throw new Error("control and inference credentials must be distinct"); } const publicOrigin = normalizePublicOrigin( parsed.HARBOR_HF_PUBLIC_ORIGIN ?? (parsed.SPACE_HOST ? `https://${parsed.SPACE_HOST}` : `http://127.0.0.1:${parsed.PORT}`), ); let oauth: AppConfig["oauth"] = null; if (parsed.HARBOR_HF_AUTH_MODE === "oauth") { if ( !parsed.OAUTH_CLIENT_ID || !parsed.OAUTH_CLIENT_SECRET || !parsed.OPENID_PROVIDER_URL ) { throw new Error("OAuth mode requires the Hugging Face OIDC environment"); } oauth = { issuer: parsed.OPENID_PROVIDER_URL, client_id: parsed.OAUTH_CLIENT_ID, client_secret: parsed.OAUTH_CLIENT_SECRET, scopes: parsed.OAUTH_SCOPES, callback_url: `${publicOrigin}/auth/callback`, session_ttl_seconds: 12 * 60 * 60, }; } return { node_env: parsed.NODE_ENV, port: parsed.PORT, namespace: parsed.HARBOR_HF_NAMESPACE, bucket_id: parsed.HARBOR_HF_BUCKET_ID, bucket_root: resolve(parsed.HARBOR_HF_BUCKET_ROOT), store_mode: storeMode, projection_path: resolve(parsed.HARBOR_HF_PROJECTION_PATH), auth_path: resolve(parsed.HARBOR_HF_AUTH_PATH), profiles_root: resolve(parsed.HARBOR_HF_PROFILES_ROOT), capacity_profile_alias: parsed.HARBOR_HF_CAPACITY_PROFILE_ALIAS ?? null, max_active_jobs: parsed.HARBOR_HF_MAX_ACTIVE_JOBS, task_image_mirror_repository: parsed.HARBOR_HF_TASK_IMAGE_MIRROR_REPOSITORY, web_root: resolve(parsed.HARBOR_HF_WEB_ROOT), auth_mode: parsed.HARBOR_HF_AUTH_MODE, write_mode: parsed.HARBOR_HF_WRITE_MODE, public_origin: publicOrigin, oauth, hf_token: parsed.HF_TOKEN ?? null, hf_inference_token: parsed.HF_INFERENCE_TOKEN ?? null, reconcile_interval_ms: parsed.HARBOR_HF_RECONCILE_INTERVAL_MS, sync_interval_ms: parsed.HARBOR_HF_SYNC_INTERVAL_MS, observe_interval_ms: parsed.HARBOR_HF_OBSERVE_INTERVAL_MS, worker_receipt_grace_ms: parsed.HARBOR_HF_WORKER_RECEIPT_GRACE_MS, source_revision: parsed.HARBOR_HF_SOURCE_REVISION, bootstrap_operator_subjects: parsed.HARBOR_HF_BOOTSTRAP_OPERATOR_SUBJECTS.split(",") .map((item) => item.trim()) .filter(Boolean), }; }