import { get_space_hardware, hardware_types, set_space_timeout } from "../helpers/spaces"; import type { DuplicateOptions } from "../types"; import { Client } from "../client"; import { SPACE_METADATA_ERROR_MSG } from "../constants"; import { get_cookie_header, parse_and_set_cookies } from "../helpers/init_helpers"; import { process_endpoint } from "../helpers/api_info"; export async function duplicate( app_reference: string, options: DuplicateOptions ): Promise { const { hf_token, private: _private, hardware, timeout, auth } = options; if (hardware && !hardware_types.includes(hardware)) { throw new Error( `Invalid hardware type provided. Valid types are: ${hardware_types .map((v) => `"${v}"`) .join(",")}.` ); } const { http_protocol, host } = await process_endpoint( app_reference, hf_token ); let cookies: string[] | null = null; if (auth) { const cookie_header = await get_cookie_header( http_protocol, host, auth, fetch ); if (cookie_header) cookies = parse_and_set_cookies(cookie_header); } const headers = { Authorization: `Bearer ${hf_token}`, "Content-Type": "application/json", ...(cookies ? { Cookie: cookies.join("; ") } : {}) }; const user = ( await ( await fetch(`https://huggingface.co/api/whoami-v2`, { headers }) ).json() ).name; const space_name = app_reference.split("/")[1]; const body: { repository: string; private?: boolean; hardware?: string; } = { repository: `${user}/${space_name}` }; if (_private) { body.private = true; } let original_hardware; try { if (!hardware) { original_hardware = await get_space_hardware(app_reference, hf_token); } } catch (e) { throw Error(SPACE_METADATA_ERROR_MSG + (e as Error).message); } const requested_hardware = hardware || original_hardware || "cpu-basic"; body.hardware = requested_hardware; try { const response = await fetch( `https://huggingface.co/api/spaces/${app_reference}/duplicate`, { method: "POST", headers, body: JSON.stringify(body) } ); if (response.status === 409) { try { const client = await Client.connect(`${user}/${space_name}`, options); return client; } catch (error) { console.error("Failed to connect Client instance:", error); throw error; } } else if (response.status !== 200) { throw new Error(response.statusText); } const duplicated_space = await response.json(); await set_space_timeout(`${user}/${space_name}`, timeout || 300, hf_token); return await Client.connect( get_space_reference(duplicated_space.url), options ); } catch (e: any) { throw new Error(e); } } function get_space_reference(url: string): any { const regex = /https:\/\/huggingface.co\/spaces\/([^/]+\/[^/]+)/; const match = url.match(regex); if (match) { return match[1]; } }