Spaces:
Runtime error
Runtime error
// node_modules/@huggingface/hub/dist/index.mjs | |
var HUB_URL = "https://huggingface.co"; | |
async function createApiError(response, opts) { | |
const error = new HubApiError(response.url, response.status, response.headers.get("X-Request-Id") ?? opts?.requestId); | |
error.message = `Api error with status ${error.statusCode}${opts?.message ? `. ${opts.message}` : ""}`; | |
const trailer = [`URL: ${error.url}`, error.requestId ? `Request ID: ${error.requestId}` : void 0].filter(Boolean).join(". "); | |
if (response.headers.get("Content-Type")?.startsWith("application/json")) { | |
const json = await response.json(); | |
error.message = json.error || json.message || error.message; | |
if (json.error_description) { | |
error.message = error.message ? error.message + `: ${json.error_description}` : json.error_description; | |
} | |
error.data = json; | |
} else { | |
error.data = { message: await response.text() }; | |
} | |
error.message += `. ${trailer}`; | |
throw error; | |
} | |
var HubApiError = class extends Error { | |
statusCode; | |
url; | |
requestId; | |
data; | |
constructor(url, statusCode, requestId, message) { | |
super(message); | |
this.statusCode = statusCode; | |
this.requestId = requestId; | |
this.url = url; | |
} | |
}; | |
var isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined"; | |
var isWebWorker = typeof self === "object" && self.constructor && self.constructor.name === "DedicatedWorkerGlobalScope"; | |
var resolve; | |
var waitPromise = new Promise((r) => { | |
resolve = r; | |
}); | |
function base64FromBytes(arr) { | |
if (globalThis.Buffer) { | |
return globalThis.Buffer.from(arr).toString("base64"); | |
} else { | |
const bin = []; | |
arr.forEach((byte) => { | |
bin.push(String.fromCharCode(byte)); | |
}); | |
return globalThis.btoa(bin.join("")); | |
} | |
} | |
var REGEX_COMMIT_HASH = new RegExp("^[0-9a-f]{40}$"); | |
async function oauthHandleRedirect(opts) { | |
if (typeof window === "undefined" && !opts?.redirectedUrl) { | |
throw new Error("oauthHandleRedirect is only available in the browser, unless you provide redirectedUrl"); | |
} | |
if (typeof localStorage === "undefined" && (!opts?.nonce || !opts?.codeVerifier)) { | |
throw new Error( | |
"oauthHandleRedirect requires localStorage to be available, unless you provide nonce and codeVerifier" | |
); | |
} | |
const redirectedUrl = opts?.redirectedUrl ?? window.location.href; | |
const searchParams = (() => { | |
try { | |
return new URL(redirectedUrl).searchParams; | |
} catch (err) { | |
throw new Error("Failed to parse redirected URL: " + redirectedUrl); | |
} | |
})(); | |
const [error, errorDescription] = [searchParams.get("error"), searchParams.get("error_description")]; | |
if (error) { | |
throw new Error(`${error}: ${errorDescription}`); | |
} | |
const code = searchParams.get("code"); | |
const nonce = opts?.nonce ?? localStorage.getItem("huggingface.co:oauth:nonce"); | |
if (!code) { | |
throw new Error("Missing oauth code from query parameters in redirected URL: " + redirectedUrl); | |
} | |
if (!nonce) { | |
throw new Error("Missing oauth nonce from localStorage"); | |
} | |
const codeVerifier = opts?.codeVerifier ?? localStorage.getItem("huggingface.co:oauth:code_verifier"); | |
if (!codeVerifier) { | |
throw new Error("Missing oauth code_verifier from localStorage"); | |
} | |
const state = searchParams.get("state"); | |
if (!state) { | |
throw new Error("Missing oauth state from query parameters in redirected URL"); | |
} | |
let parsedState; | |
try { | |
parsedState = JSON.parse(state); | |
} catch { | |
throw new Error("Invalid oauth state in redirected URL, unable to parse JSON: " + state); | |
} | |
if (parsedState.nonce !== nonce) { | |
throw new Error("Invalid oauth state in redirected URL"); | |
} | |
const hubUrl = opts?.hubUrl || HUB_URL; | |
const openidConfigUrl = `${new URL(hubUrl).origin}/.well-known/openid-configuration`; | |
const openidConfigRes = await fetch(openidConfigUrl, { | |
headers: { | |
Accept: "application/json" | |
} | |
}); | |
if (!openidConfigRes.ok) { | |
throw await createApiError(openidConfigRes); | |
} | |
const openidConfig = await openidConfigRes.json(); | |
const tokenRes = await fetch(openidConfig.token_endpoint, { | |
method: "POST", | |
headers: { | |
"Content-Type": "application/x-www-form-urlencoded" | |
}, | |
body: new URLSearchParams({ | |
grant_type: "authorization_code", | |
code, | |
redirect_uri: parsedState.redirectUri, | |
code_verifier: codeVerifier | |
}).toString() | |
}); | |
if (!opts?.codeVerifier) { | |
localStorage.removeItem("huggingface.co:oauth:code_verifier"); | |
} | |
if (!opts?.nonce) { | |
localStorage.removeItem("huggingface.co:oauth:nonce"); | |
} | |
if (!tokenRes.ok) { | |
throw await createApiError(tokenRes); | |
} | |
const token = await tokenRes.json(); | |
const accessTokenExpiresAt = new Date(Date.now() + token.expires_in * 1e3); | |
const userInfoRes = await fetch(openidConfig.userinfo_endpoint, { | |
headers: { | |
Authorization: `Bearer ${token.access_token}` | |
} | |
}); | |
if (!userInfoRes.ok) { | |
throw await createApiError(userInfoRes); | |
} | |
const userInfo = await userInfoRes.json(); | |
return { | |
accessToken: token.access_token, | |
accessTokenExpiresAt, | |
userInfo, | |
state: parsedState.state, | |
scope: token.scope | |
}; | |
} | |
async function oauthHandleRedirectIfPresent(opts) { | |
if (typeof window === "undefined" && !opts?.redirectedUrl) { | |
throw new Error("oauthHandleRedirect is only available in the browser, unless you provide redirectedUrl"); | |
} | |
if (typeof localStorage === "undefined" && (!opts?.nonce || !opts?.codeVerifier)) { | |
throw new Error( | |
"oauthHandleRedirect requires localStorage to be available, unless you provide nonce and codeVerifier" | |
); | |
} | |
const searchParams = new URLSearchParams(opts?.redirectedUrl ?? window.location.search); | |
if (searchParams.has("error")) { | |
return oauthHandleRedirect(opts); | |
} | |
if (searchParams.has("code")) { | |
if (!localStorage.getItem("huggingface.co:oauth:nonce")) { | |
console.warn( | |
"Missing oauth nonce from localStorage. This can happen when the user refreshes the page after logging in, without changing the URL." | |
); | |
return false; | |
} | |
return oauthHandleRedirect(opts); | |
} | |
return false; | |
} | |
async function oauthLoginUrl(opts) { | |
if (typeof window === "undefined" && (!opts?.redirectUrl || !opts?.clientId)) { | |
throw new Error("oauthLogin is only available in the browser, unless you provide clientId and redirectUrl"); | |
} | |
if (typeof localStorage === "undefined" && !opts?.localStorage) { | |
throw new Error( | |
"oauthLogin requires localStorage to be available in the context, unless you provide a localStorage empty object as argument" | |
); | |
} | |
const hubUrl = opts?.hubUrl || HUB_URL; | |
const openidConfigUrl = `${new URL(hubUrl).origin}/.well-known/openid-configuration`; | |
const openidConfigRes = await fetch(openidConfigUrl, { | |
headers: { | |
Accept: "application/json" | |
} | |
}); | |
if (!openidConfigRes.ok) { | |
throw await createApiError(openidConfigRes); | |
} | |
const opendidConfig = await openidConfigRes.json(); | |
const newNonce = globalThis.crypto.randomUUID(); | |
const newCodeVerifier = globalThis.crypto.randomUUID() + globalThis.crypto.randomUUID(); | |
if (opts?.localStorage) { | |
if (opts.localStorage.codeVerifier !== void 0 && opts.localStorage.codeVerifier !== null) { | |
throw new Error( | |
"localStorage.codeVerifier must be a initially set to null or undefined, and will be filled by oauthLoginUrl" | |
); | |
} | |
if (opts.localStorage.nonce !== void 0 && opts.localStorage.nonce !== null) { | |
throw new Error( | |
"localStorage.nonce must be a initially set to null or undefined, and will be filled by oauthLoginUrl" | |
); | |
} | |
opts.localStorage.codeVerifier = newCodeVerifier; | |
opts.localStorage.nonce = newNonce; | |
} else { | |
localStorage.setItem("huggingface.co:oauth:nonce", newNonce); | |
localStorage.setItem("huggingface.co:oauth:code_verifier", newCodeVerifier); | |
} | |
const redirectUri = opts?.redirectUrl || (typeof window !== "undefined" ? window.location.href : void 0); | |
if (!redirectUri) { | |
throw new Error("Missing redirectUrl"); | |
} | |
const state = JSON.stringify({ | |
nonce: newNonce, | |
redirectUri, | |
state: opts?.state | |
}); | |
const variables = ( | |
// @ts-expect-error window.huggingface is defined inside static Spaces. | |
typeof window !== "undefined" ? window.huggingface?.variables ?? null : null | |
); | |
const clientId = opts?.clientId || variables?.OAUTH_CLIENT_ID; | |
if (!clientId) { | |
if (variables) { | |
throw new Error("Missing clientId, please add hf_oauth: true to the README.md's metadata in your static Space"); | |
} | |
throw new Error("Missing clientId"); | |
} | |
const challenge = base64FromBytes( | |
new Uint8Array(await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(newCodeVerifier))) | |
).replace(/[+]/g, "-").replace(/[/]/g, "_").replace(/=/g, ""); | |
return `${opendidConfig.authorization_endpoint}?${new URLSearchParams({ | |
client_id: clientId, | |
scope: opts?.scopes || variables?.OAUTH_SCOPES || "openid profile", | |
response_type: "code", | |
redirect_uri: redirectUri, | |
state, | |
code_challenge: challenge, | |
code_challenge_method: "S256" | |
}).toString()}`; | |
} | |
// src/main.ts | |
console.log("huggingface env", window.huggingface); | |
var oauthResult = null; | |
var storedOAuth = localStorage.getItem("oauth"); | |
if (storedOAuth) { | |
try { | |
oauthResult = JSON.parse(storedOAuth); | |
} catch { | |
oauthResult = null; | |
} | |
} | |
var init = async () => { | |
oauthResult ||= await oauthHandleRedirectIfPresent(); | |
if (oauthResult !== null && oauthResult !== false) { | |
const preElement = document.querySelector("pre"); | |
if (preElement) { | |
preElement.textContent = JSON.stringify(oauthResult, null, 2); | |
} | |
localStorage.setItem("oauth", JSON.stringify(oauthResult)); | |
const signoutButton = document.getElementById("signout"); | |
if (signoutButton) { | |
signoutButton.style.removeProperty("display"); | |
signoutButton.onclick = async function() { | |
localStorage.removeItem("oauth"); | |
window.location.href = window.location.href.replace(/\?.*$/, ""); | |
window.location.reload(); | |
}; | |
} | |
} else { | |
const signinButton = document.getElementById("signin"); | |
if (signinButton) { | |
signinButton.style.removeProperty("display"); | |
signinButton.onclick = async function() { | |
const loginUrl = await oauthLoginUrl({ | |
scopes: window.huggingface?.variables?.OAUTH_SCOPES ?? "" | |
}); | |
window.location.href = `${loginUrl}&prompt=consent`; | |
}; | |
} | |
} | |
}; | |
init().catch(console.error); | |