UNPKG

@xmcl/user

Version:

Minecraft user related functions, including Yggdrasil authenticator, player skin fetcher, and Mojang security API

813 lines (805 loc) 27.5 kB
var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; // offline.ts import { v4 } from "uuid"; // ../user-offline-uuid/index.browser.ts var md5 = (s) => { function md5cycle(x, k) { let a = x[0]; let b = x[1]; let c = x[2]; let d = x[3]; a = ff(a, b, c, d, k[0], 7, -680876936); d = ff(d, a, b, c, k[1], 12, -389564586); c = ff(c, d, a, b, k[2], 17, 606105819); b = ff(b, c, d, a, k[3], 22, -1044525330); a = ff(a, b, c, d, k[4], 7, -176418897); d = ff(d, a, b, c, k[5], 12, 1200080426); c = ff(c, d, a, b, k[6], 17, -1473231341); b = ff(b, c, d, a, k[7], 22, -45705983); a = ff(a, b, c, d, k[8], 7, 1770035416); d = ff(d, a, b, c, k[9], 12, -1958414417); c = ff(c, d, a, b, k[10], 17, -42063); b = ff(b, c, d, a, k[11], 22, -1990404162); a = ff(a, b, c, d, k[12], 7, 1804603682); d = ff(d, a, b, c, k[13], 12, -40341101); c = ff(c, d, a, b, k[14], 17, -1502002290); b = ff(b, c, d, a, k[15], 22, 1236535329); a = gg(a, b, c, d, k[1], 5, -165796510); d = gg(d, a, b, c, k[6], 9, -1069501632); c = gg(c, d, a, b, k[11], 14, 643717713); b = gg(b, c, d, a, k[0], 20, -373897302); a = gg(a, b, c, d, k[5], 5, -701558691); d = gg(d, a, b, c, k[10], 9, 38016083); c = gg(c, d, a, b, k[15], 14, -660478335); b = gg(b, c, d, a, k[4], 20, -405537848); a = gg(a, b, c, d, k[9], 5, 568446438); d = gg(d, a, b, c, k[14], 9, -1019803690); c = gg(c, d, a, b, k[3], 14, -187363961); b = gg(b, c, d, a, k[8], 20, 1163531501); a = gg(a, b, c, d, k[13], 5, -1444681467); d = gg(d, a, b, c, k[2], 9, -51403784); c = gg(c, d, a, b, k[7], 14, 1735328473); b = gg(b, c, d, a, k[12], 20, -1926607734); a = hh(a, b, c, d, k[5], 4, -378558); d = hh(d, a, b, c, k[8], 11, -2022574463); c = hh(c, d, a, b, k[11], 16, 1839030562); b = hh(b, c, d, a, k[14], 23, -35309556); a = hh(a, b, c, d, k[1], 4, -1530992060); d = hh(d, a, b, c, k[4], 11, 1272893353); c = hh(c, d, a, b, k[7], 16, -155497632); b = hh(b, c, d, a, k[10], 23, -1094730640); a = hh(a, b, c, d, k[13], 4, 681279174); d = hh(d, a, b, c, k[0], 11, -358537222); c = hh(c, d, a, b, k[3], 16, -722521979); b = hh(b, c, d, a, k[6], 23, 76029189); a = hh(a, b, c, d, k[9], 4, -640364487); d = hh(d, a, b, c, k[12], 11, -421815835); c = hh(c, d, a, b, k[15], 16, 530742520); b = hh(b, c, d, a, k[2], 23, -995338651); a = ii(a, b, c, d, k[0], 6, -198630844); d = ii(d, a, b, c, k[7], 10, 1126891415); c = ii(c, d, a, b, k[14], 15, -1416354905); b = ii(b, c, d, a, k[5], 21, -57434055); a = ii(a, b, c, d, k[12], 6, 1700485571); d = ii(d, a, b, c, k[3], 10, -1894986606); c = ii(c, d, a, b, k[10], 15, -1051523); b = ii(b, c, d, a, k[1], 21, -2054922799); a = ii(a, b, c, d, k[8], 6, 1873313359); d = ii(d, a, b, c, k[15], 10, -30611744); c = ii(c, d, a, b, k[6], 15, -1560198380); b = ii(b, c, d, a, k[13], 21, 1309151649); a = ii(a, b, c, d, k[4], 6, -145523070); d = ii(d, a, b, c, k[11], 10, -1120210379); c = ii(c, d, a, b, k[2], 15, 718787259); b = ii(b, c, d, a, k[9], 21, -343485551); x[0] = add32(a, x[0]); x[1] = add32(b, x[1]); x[2] = add32(c, x[2]); x[3] = add32(d, x[3]); } function cmn(q, a, b, x, s2, t) { a = add32(add32(a, q), add32(x, t)); return add32(a << s2 | a >>> 32 - s2, b); } function ff(a, b, c, d, x, s2, t) { return cmn(b & c | ~b & d, a, b, x, s2, t); } function gg(a, b, c, d, x, s2, t) { return cmn(b & d | c & ~d, a, b, x, s2, t); } function hh(a, b, c, d, x, s2, t) { return cmn(b ^ c ^ d, a, b, x, s2, t); } function ii(a, b, c, d, x, s2, t) { return cmn(c ^ (b | ~d), a, b, x, s2, t); } function md51(s2) { const n = s2.length; const state = new Int32Array([1732584193, -271733879, -1732584194, 271733878]); let i; for (i = 64; i <= s2.length; i += 64) { md5cycle(state, md5blk(s2.substring(i - 64, i))); } s2 = s2.substring(i - 64); const tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; for (i = 0; i < s2.length; i++) { tail[i >> 2] |= s2.charCodeAt(i) << (i % 4 << 3); } tail[i >> 2] |= 128 << (i % 4 << 3); if (i > 55) { md5cycle(state, tail); for (i = 0; i < 16; i++) tail[i] = 0; } tail[14] = n * 8; md5cycle(state, tail); return state; } function md5blk(s2) { const md5blks = []; let i; for (i = 0; i < 64; i += 4) { md5blks[i >> 2] = s2.charCodeAt(i) + (s2.charCodeAt(i + 1) << 8) + (s2.charCodeAt(i + 2) << 16) + (s2.charCodeAt(i + 3) << 24); } return md5blks; } function add32(a, b) { return a + b & 4294967295; } return md51(s); }; function getOfflineUUID(username) { const md5Bytes = md5(`OfflinePlayer:${username}`); md5Bytes[6] &= 15; md5Bytes[6] |= 48; md5Bytes[8] &= 63; md5Bytes[8] |= 128; const hex_chr = "0123456789abcdef".split(""); function rhex(n) { let s = ""; let j = 0; for (; j < 4; j++) { s += hex_chr[n >> j * 8 + 4 & 15] + hex_chr[n >> j * 8 & 15]; } return s; } function hex(x) { const reuslt = new Array(4); for (let i = 0; i < x.length; i++) { reuslt[i] = rhex(x[i]); } return reuslt.join(""); } return hex(md5Bytes).replace(/(\w{8})(\w{4})(\w{4})(\w{4})(\w{12})/, "$1-$2-$3-$4-$5"); } // offline.ts function newToken() { return v4().replace(/-/g, ""); } function offline(username, uuid) { const id = uuid || getOfflineUUID(username); const prof = { id, name: username }; return { accessToken: newToken(), clientToken: newToken(), selectedProfile: prof, availableProfiles: [prof], user: { id, username } }; } // ../undici-shim/index.ts var fetch2 = globalThis.fetch; var File2 = globalThis.File; var FormData2 = globalThis.FormData; // mojang.ts var NameAvailability = /* @__PURE__ */ ((NameAvailability2) => { NameAvailability2["DUPLICATE"] = "DUPLICATE"; NameAvailability2["AVAILABLE"] = "AVAILABLE"; NameAvailability2["NOT_ALLOWED"] = "NOT_ALLOWED"; return NameAvailability2; })(NameAvailability || {}); var SetNameError = class extends Error { constructor(message, err) { super(message); __publicField(this, "path"); __publicField(this, "errorType"); __publicField(this, "error"); __publicField(this, "details"); __publicField(this, "errorMessage"); __publicField(this, "developerMessage"); this.name = "SetNameError"; this.path = err.path; this.errorType = err.errorType; this.error = err.error; this.details = err.details; this.errorMessage = err.errorMessage; this.developerMessage = err.developerMessage; } }; var SetSkinError = class extends Error { constructor(message, err) { super(message); __publicField(this, "path"); __publicField(this, "errorType"); __publicField(this, "error"); __publicField(this, "details"); __publicField(this, "errorMessage"); __publicField(this, "developerMessage"); this.name = "SetSkinError"; this.path = err.path; this.errorType = err.errorType; this.error = err.error; this.details = err.details; this.errorMessage = err.errorMessage; this.developerMessage = err.developerMessage; } }; var MojangError = class extends Error { constructor(err) { super(err.errorMessage); __publicField(this, "path"); __publicField(this, "errorMessage"); __publicField(this, "developerMessage"); this.path = err.path; this.errorMessage = err.errorMessage; this.developerMessage = err.developerMessage; Object.assign(this, err); } }; var UnauthorizedError = class extends MojangError { constructor(err) { super(err); __publicField(this, "name", "UnauthorizedError"); } }; var ProfileNotFoundError = class extends MojangError { constructor(err) { super(err); __publicField(this, "name", "ProfileNotFoundError"); } }; var MojangClient = class { constructor(options) { __publicField(this, "fetch"); this.fetch = options?.fetch || fetch2; } async setName(name, token, signal) { const resp = await this.fetch(`https://api.minecraftservices.com/minecraft/profile/name/${name}`, { method: "PUT", headers: { Authorization: `Bearer ${token}` }, signal }); switch (resp.status) { case 200: return await resp.json(); case 400: throw new SetNameError("Name is unavailable (Either taken or has not become available)", await resp.json()); case 403: throw new SetNameError("Name is unavailable (Either taken or has not become available)", await resp.json()); case 401: throw new SetNameError("Unauthorized (Bearer token expired or is not correct)", await resp.json()); case 429: throw new SetNameError("Too many requests sent", await resp.json()); case 500: throw new SetNameError("Timed out (API lagged out and could not respond)", await resp.json()); } throw new SetNameError("Unknown error", await resp.json()); } async getNameChangeInformation(token) { const resp = await this.fetch("https://api.minecraftservices.com/minecraft/profile/namechange", { method: "GET", headers: { Authorization: `Bearer ${token}` } }); return await resp.json(); } async checkNameAvailability(name, token, signal) { const resp = await this.fetch(`https://api.minecraftservices.com/minecraft/profile/name/${name}/available`, { method: "GET", headers: { Authorization: `Bearer ${token}` }, signal }); const result = await resp.json(); return result.status; } async getProfile(token, signal) { const resp = await this.fetch("https://api.minecraftservices.com/minecraft/profile", { method: "GET", headers: { Authorization: `Bearer ${token}` }, signal }); if (resp.headers.get("content-type")?.toLocaleLowerCase() !== "application/json") { throw new Error(await resp.text()); } const json = await resp.json(); if (resp.ok) { return json; } else if (json.error === "NOT_FOUND") { throw new ProfileNotFoundError(json); } else if (resp.status === 401) { throw new UnauthorizedError(json); } throw Object.assign(new Error("Unknown Error"), json); } async setSkin(fileName, skin, variant, token, signal) { const body = typeof skin === "string" ? JSON.stringify({ url: skin, variant }) : getSkinFormData(skin, fileName, variant); const headers = { Authorization: `Bearer ${token}` }; if (typeof body === "string") { headers["Content-Type"] = "application/json"; } const resp = await this.fetch("https://api.minecraftservices.com/minecraft/profile/skins", { method: "POST", headers, body, signal }); const profileResponse = await resp.json(); if (resp.status === 401) { throw new UnauthorizedError(await resp.json()); } if ("error" in profileResponse || "errorMessage" in profileResponse) { throw new SetSkinError(`Fail to set skin ${profileResponse.errorMessage}`, profileResponse); } return profileResponse; } async resetSkin(token, signal) { const resp = await this.fetch("https://api.minecraftservices.com/minecraft/profile/skins/active", { method: "DELETE", headers: { Authorization: `Bearer ${token}` }, signal }); if (resp.status === 401) { throw new UnauthorizedError(await resp.json()); } } async hideCape(token, signal) { const resp = await this.fetch("https://api.minecraftservices.com/minecraft/profile/capes/active", { method: "DELETE", headers: { Authorization: `Bearer ${token}` }, signal }); if (resp.status === 401) { throw new UnauthorizedError(await resp.json()); } } async showCape(capeId, token, signal) { const resp = await this.fetch("https://api.minecraftservices.com/minecraft/profile/capes/active", { method: "PUT", headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" }, body: JSON.stringify({ capeId }), signal }); if (resp.status === 401) { throw new UnauthorizedError(await resp.json()); } if (resp.status === 400) { throw new Error(); } const profile = await resp.json(); return profile; } async verifySecurityLocation(token, signal) { const resp = await this.fetch("https://api.mojang.com/user/security/location", { method: "GET", headers: { Authorization: `Bearer ${token}` }, signal }); if (resp.status === 204) { return true; } return false; } async getSecurityChallenges(token) { const resp = await this.fetch("https://api.mojang.com/user/security/challenges", { method: "GET", headers: { Authorization: `Bearer ${token}` } }); if (resp.status === 401) { throw new UnauthorizedError(await resp.json()); } return await resp.json(); } async submitSecurityChallenges(answers, token) { const resp = await this.fetch("https://api.mojang.com/user/security/location", { method: "POST", headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" }, body: JSON.stringify(answers) }); if (resp.status === 204) { return; } if (resp.status === 401) { throw new UnauthorizedError(await resp.json()); } throw new Error(); } /** * Return the owner ship list of the player with those token. */ async checkGameOwnership(token, signal) { const mcResponse = await this.fetch("https://api.minecraftservices.com/entitlements/mcstore", { headers: { Authorization: `Bearer ${token}` }, signal }); if (mcResponse.status === 401) { throw new UnauthorizedError(await mcResponse.text()); } if (!mcResponse.ok || mcResponse.headers.get("content-type")?.toLocaleLowerCase() !== "application/json") { throw new Error(await mcResponse.text()); } const result = await mcResponse.json(); return result; } }; function getSkinFormData(buf, fileName, variant) { const form = new FormData2(); form.append("variant", variant); const file = new File([buf], fileName, { type: "image/png" }); form.append("file", file); return form; } // yggdrasil.ts var YggdrasilError = class extends Error { constructor(statusCode, message, o) { super(message); this.statusCode = statusCode; __publicField(this, "error"); __publicField(this, "errorMessage"); __publicField(this, "cause"); this.name = "YggdrasilError"; this.error = o?.error; this.errorMessage = o?.errorMessage; this.cause = o?.cause; } }; var YggdrasilClient = class { /** * Create client for official-like api endpoint * @param api The official-like api endpoint */ constructor(api, options) { this.api = api; __publicField(this, "headers"); __publicField(this, "fetch"); __publicField(this, "FormData"); __publicField(this, "File"); this.headers = options?.headers ?? {}; this.fetch = options?.fetch || fetch; this.FormData = options?.FormData || FormData; this.File = options?.File || File; } async validate(accessToken, clientToken, signal) { const response = await this.fetch(this.api + "/validate", { method: "POST", body: JSON.stringify({ accessToken, clientToken }), headers: { ...this.headers, "content-type": "application/json; charset=utf-8" }, signal }); return response.ok; } async invalidate(accessToken, clientToken, signal) { return await this.fetch(this.api + "/invalidate", { method: "POST", body: JSON.stringify({ accessToken, clientToken }), headers: { ...this.headers, "content-type": "application/json; charset=utf-8" }, signal }).then((s) => s.ok); } async login({ username, password, clientToken, requestUser }, signal) { const response = await this.fetch(this.api + "/authenticate", { method: "POST", body: JSON.stringify({ agent: { name: "Minecraft", version: 1 }, requestUser: typeof requestUser === "boolean" ? requestUser : false, username, password, clientToken }), headers: { ...this.headers, "content-type": "application/json; charset=utf-8" }, signal }); if (response.status >= 400) { const body = await response.text(); throw new YggdrasilError(response.status, response.status + ":" + body, response.headers.get("content-type")?.startsWith("application/json") ? JSON.parse(body) : void 0); } const authentication = await response.json(); return authentication; } async refresh({ accessToken, requestUser, clientToken }, signal) { const response = await this.fetch(this.api + "/refresh", { method: "POST", body: JSON.stringify({ accessToken, clientToken, requestUser: typeof requestUser === "boolean" ? requestUser : false }), headers: { ...this.headers, "content-type": "application/json; charset=utf-8" }, signal }); if (response.status >= 400) { const body = await response.text(); throw new YggdrasilError(response.status, response.status + ":" + body, response.headers.get("content-type")?.startsWith("application/json") ? JSON.parse(body) : void 0); } const authentication = await response.json(); return authentication; } }; function isTextureSlim(o) { return o.metadata ? o.metadata.model === "slim" : false; } function getTextureType(o) { return isTextureSlim(o) ? "slim" : "steve"; } var YggdrasilThirdPartyClient = class extends YggdrasilClient { /** * Create thirdparty (authlib-injector) style client * @param api The api url following https://github.com/yushijinhun/authlib-injector/wiki/Yggdrasil-%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%8A%80%E6%9C%AF%E8%A7%84%E8%8C%83 * @param clientToken * @param dispatcher */ constructor(api, options) { super(api + "/authserver", options); __publicField(this, "profileApi"); __publicField(this, "textureApi"); this.profileApi = api + "/sessionserver/session/minecraft/profile/${uuid}"; this.textureApi = api + "/api/user/profile/${uuid}/${type}"; } async lookup(uuid, unsigned = true, signal) { const url = new URL(this.profileApi.replace("${uuid}", uuid)); url.searchParams.append("unsigned", unsigned ? "true" : "false"); const response = await this.fetch(url.toString(), { method: "GET", headers: this.headers, signal }); if (response.status !== 200) { const body = await response.text(); throw new YggdrasilError(response.status, response.status + ":" + body, response.headers.get("content-type")?.startsWith("application/json") ? JSON.parse(body) : void 0); } const o = await response.json(); if (o.properties && o.properties instanceof Array) { const properties = o.properties; const to = {}; for (const prop of properties) { to[prop.name] = prop.value; } o.properties = to; } return o; } async setTexture(options, signal) { const url = new URL(this.textureApi.replace("${uuid}", options.uuid).replace("${type}", options.type)); const requestOptions = { headers: { ...this.headers, Authorization: `Bearer ${options.accessToken}` }, signal }; if (!options.texture) { requestOptions.method = "DELETE"; } else if ("data" in options.texture) { requestOptions.method = "PUT"; const form = new this.FormData(); form.append("model", options.texture.metadata?.model || "steve"); form.append("file", new this.File([options.texture.data], "Steve.png", { type: "image/png" })); requestOptions.body = form; } else if ("url" in options.texture) { requestOptions.method = "POST"; url.searchParams.append("model", options.texture.metadata?.model || ""); url.searchParams.append("url", options.texture.url); } else { throw new TypeError("Illegal Option Format!"); } const response = await this.fetch(url.toString(), requestOptions); if (response.status === 401) { if (response.headers.get("content-type") === "application/json") { const body = await response.json(); throw new YggdrasilError(response.status, response.status.toString(), { error: body.error ?? "Unauthorized", errorMessage: body.errorMessage ?? "Unauthorized" }); } else { const body = await response.text(); throw new YggdrasilError(response.status, response.status + ":" + body, { error: "Unauthorized", errorMessage: "Unauthorized: " + body }); } } if (response.status >= 400) { const body = await response.text(); throw new YggdrasilError(response.status, response.status + ":" + body, { error: "SetSkinFailed", errorMessage: "Fail to set skin " + body }); } } }; // microsoft.ts var MicrosoftAuthenticator = class { constructor(options) { __publicField(this, "fetch"); this.fetch = options.fetch || fetch; } /** * Authenticate with xbox live by ms oauth access token * @param oauthAccessToken The oauth access token */ async authenticateXboxLive(oauthAccessToken, signal) { const xblResponse = await this.fetch("https://user.auth.xboxlive.com/user/authenticate", { method: "POST", body: JSON.stringify({ Properties: { AuthMethod: "RPS", SiteName: "user.auth.xboxlive.com", RpsTicket: `d=${oauthAccessToken}` }, RelyingParty: "http://auth.xboxlive.com", TokenType: "JWT" }), headers: { "Content-Type": "application/json" }, signal }); if (xblResponse.status !== 200) { throw new Error(`Failed to authenticate with xbox live, status code: ${xblResponse.status}: ${await xblResponse.text()}}`); } const result = await xblResponse.json(); return result; } /** * Authorize the xbox live. It will get the xsts token in response. * @param xblResponseToken The {@link XBoxResponse.Token} */ async authorizeXboxLive(xblResponseToken, relyingParty = "rp://api.minecraftservices.com/", signal) { const xstsResponse = await this.fetch("https://xsts.auth.xboxlive.com/xsts/authorize", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ Properties: { SandboxId: "RETAIL", UserTokens: [xblResponseToken] }, RelyingParty: relyingParty, TokenType: "JWT" }), signal }); if (xstsResponse.status !== 200) { const errText = await xstsResponse.text(); let errObj = {}; try { errObj = JSON.parse(errText); } catch (e) { } throw Object.assign(new Error(`Failed to authorize with xbox live, status code: ${xstsResponse.status}: ${errText}}`), errObj); } const result = await xstsResponse.json(); return result; } /** * Get xbox user profile, including **username** and **avatar**. * * You can find the parameters from the {@link XBoxResponse}. * * @param xuid The `xuid` in a {@link XBoxResponse.DisplayClaims} * @param uhs The `uhs` in a {@link XBoxResponse.DisplayClaims} * @param xstsToken The {@link XBoxResponse.Token} * @returns The user game profile. */ async getXboxGameProfile(xuid, uhs, xstsToken, signal) { const url = new URL(`https://profile.xboxlive.com/users/xuid(${xuid})/profile/settings`); url.searchParams.append("settings", ["PublicGamerpic", "Gamertag"].join(",")); const response = await this.fetch(url.toString(), { headers: { "x-xbl-contract-version": "2", "content-type": "application/json", Authorization: `XBL3.0 x=${uhs};${xstsToken}` }, signal }); if (response.status !== 200) { throw new Error(`Failed to get xbox game profile, status code: ${response.status}: ${await response.text()}}`); } const result = await response.json(); return result; } /** * Acquire both Minecraft and xbox token and xbox game profile. * You can use the xbox token to login Minecraft by {@link loginMinecraftWithXBox}. * * This method is the composition of calling * - {@link authenticateXboxLive} * - {@link authorizeXboxLive} to `rp://api.minecraftservices.com/` * - {@link authorizeXboxLive} to `http://xboxlive.com` * - {@link getXboxGameProfile} * * You can call them individually if you want a more detailed control. * * @param oauthAccessToken The microsoft access token * @param signal The abort signal * @returns The object contain xstsResponse (minecraft xbox token) and xbox game profile */ async acquireXBoxToken(oauthAccessToken, signal) { const xblResponse = await this.authenticateXboxLive(oauthAccessToken, signal); const minecraftXstsResponse = await this.authorizeXboxLive(xblResponse.Token, "rp://api.minecraftservices.com/", signal); const xstsResponse = await this.authorizeXboxLive(xblResponse.Token, "http://xboxlive.com", signal); return { minecraftXstsResponse, liveXstsResponse: xstsResponse }; } /** * This will return the response with Minecraft access token! * * This access token allows us to launch the game, but, we haven't actually checked if the account owns the game. Everything until here works with a normal Microsoft account! * * @param uhs uhs from {@link XBoxResponse} of {@link acquireXBoxToken} * @param xstsToken You need to get this token from {@link acquireXBoxToken} */ async loginMinecraftWithXBox(uhs, xstsToken, signal) { const mcResponse = await this.fetch("https://api.minecraftservices.com/authentication/login_with_xbox", { method: "POST", body: JSON.stringify({ identityToken: `XBL3.0 x=${uhs};${xstsToken}` }), headers: { "content-type": "application/json" }, signal }); if (mcResponse.status !== 200) { throw new Error(`Failed to login minecraft with xbox, status code: ${mcResponse.status}: ${await mcResponse.text()}}`); } const result = await mcResponse.json(); return result; } }; export { MicrosoftAuthenticator, MojangClient, MojangError, NameAvailability, ProfileNotFoundError, SetNameError, SetSkinError, UnauthorizedError, YggdrasilClient, YggdrasilError, YggdrasilThirdPartyClient, getOfflineUUID, getTextureType, isTextureSlim, newToken, offline }; //# sourceMappingURL=index.browser.mjs.map