From 22ca67e0fe18c54f228808d8415a50847da16cc6 Mon Sep 17 00:00:00 2001 From: Antogamer Date: Mon, 5 Feb 2024 00:24:53 +0100 Subject: [PATCH] FUCK AXIOS --- Server/Source/Modules/FNUtil.ts | 33 +++-- Server/Source/Routes/Authentication.ts | 164 +++++++++++++++---------- Server/Source/Routes/Pages.ts | 7 +- Server/package-lock.json | 88 ++----------- Server/package.json | 3 +- package-lock.json | 10 ++ package.json | 1 + 7 files changed, 149 insertions(+), 157 deletions(-) diff --git a/Server/Source/Modules/FNUtil.ts b/Server/Source/Modules/FNUtil.ts index ab9011f..a971fac 100644 --- a/Server/Source/Modules/FNUtil.ts +++ b/Server/Source/Modules/FNUtil.ts @@ -1,26 +1,41 @@ -import axios from "axios"; import { Err } from "./Logger"; import { red } from "colorette"; import { FULL_SERVER_ROOT } from "./Constants"; import { User } from "../Schemas/User"; import { Song } from "../Schemas/Song"; -export let FullFortnitePages: {[key: string]: any} | null = null; +export let FullFortnitePages: { [key: string]: any } | null = null; export let OriginalSparks: {[key: string]: any} | null = null; let LastContentDownloadDate: Date = new Date(0); // set it to 1970 as default cuz im not boutta check if its null GenerateFortnitePages(null); export async function GenerateFortnitePages(ForUser: User | null): Promise<{ Success: boolean, FNPages: { [key: string]: unknown } | null }> { - const { status, data } = // check if 30 minutes have passed since last content update. if so, get a new copy of pages, if not, fuck off + let status; + let data; + if (FullFortnitePages === null || Date.now() > LastContentDownloadDate.getTime() + 30 * 60 * 1000) { + const response = await fetch("https://fortnitecontent-website-prod07.ol.epicgames.com/content/api/pages/fortnite-game"); + status = response.status; + data = await response.json(); + } else { + status = 200; + data = FullFortnitePages; + } + /*const { status, data } = // check if 30 minutes have passed since last content update. if so, get a new copy of pages, if not, fuck off FullFortnitePages === null || Date.now() > LastContentDownloadDate.getTime() + 30 * 60 * 1000 ? - await axios.get("https://fortnitecontent-website-prod07.ol.epicgames.com/content/api/pages/fortnite-game") : - { status: 200, data: FullFortnitePages }; + await fetch("https://fortnitecontent-website-prod07.ol.epicgames.com/content/api/pages/fortnite-game") : + FullFortnitePages;*/ + + let OGSparks; + + if (OriginalSparks === null || Date.now() > LastContentDownloadDate.getTime() + 30 * 60 * 1000) { + const response = await fetch("https://fortnitecontent-website-prod07.ol.epicgames.com/content/api/pages/fortnite-game/spark-tracks"); + OGSparks = {status: 200, data: await response.json()} + } else { + OGSparks = OriginalSparks + } + - const OGSparks = - OriginalSparks === null || Date.now() > LastContentDownloadDate.getTime() + 30 * 60 * 1000 ? - await axios.get("https://fortnitecontent-website-prod07.ol.epicgames.com/content/api/pages/fortnite-game/spark-tracks") : - { status: 200, data: OriginalSparks }; FullFortnitePages = { ...data, diff --git a/Server/Source/Routes/Authentication.ts b/Server/Source/Routes/Authentication.ts index 8adc041..a018bd5 100644 --- a/Server/Source/Routes/Authentication.ts +++ b/Server/Source/Routes/Authentication.ts @@ -1,4 +1,3 @@ -import axios from "axios"; import jwt from "jsonwebtoken"; import qs from "querystring"; import j from "joi"; @@ -16,88 +15,121 @@ const App = Router(); // ? hacky, if you want, make it less hacky async function QuickRevokeToken(res: Response, Token: string) { - await axios.post("https://discord.com/api/oauth2/token/revoke", qs.stringify({ token: Token, token_type_hint: "access_token" }), { auth: { username: DISCORD_CLIENT_ID!, password: DISCORD_CLIENT_SECRET! } }) + + await fetch("https://discord.com/api/oauth2/token/revoke", { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + "Authorization": `Basic ${Buffer.from(`${DISCORD_CLIENT_ID}:${DISCORD_CLIENT_SECRET}`).toString("base64")}` + }, + body: qs.stringify({ token: Token, token_type_hint: "access_token" }) + + }) return res; } -App.get("/discord/url", (_ ,res) => res.send(`https://discord.com/api/oauth2/authorize?client_id=${qs.escape(DISCORD_CLIENT_ID!)}&response_type=code&redirect_uri=${qs.escape(`${FULL_SERVER_ROOT}/api/discord`)}&scope=identify`)) +App.get("/discord/url", (_, res) => res.send(`https://discord.com/api/oauth2/authorize?client_id=${qs.escape(DISCORD_CLIENT_ID!)}&response_type=code&redirect_uri=${qs.escape(`${FULL_SERVER_ROOT}/api/discord`)}&scope=identify`)) App.get("/discord", -ValidateQuery(j.object({ - code: j.string().pattern(/^(\w|\d)+$/i).required(), - state: j.string() -})), -async (req, res) => { - const Discord = await axios.post(`https://discord.com/api/oauth2/token`, qs.stringify({ grant_type: "authorization_code", code: req.query.code as string, redirect_uri: `${FULL_SERVER_ROOT}/api/discord` }), { auth: { username: DISCORD_CLIENT_ID!, password: DISCORD_CLIENT_SECRET! } }); - - if (Discord.status !== 200) - return res.status(500).send("Failed to request OAuth token from Discord's services."); + ValidateQuery(j.object({ + code: j.string().pattern(/^(\w|\d)+$/i).required(), + state: j.string() + })), + async (req, res) => { - if (!Discord.data.scope.includes("identify")) - return (await QuickRevokeToken(res, Discord.data.access_token)).status(400).send("Missing identify scope. Please check if your OAuth link is correctly set up!"); + //const Discord = await axios.post(`https://discord.com/api/oauth2/token`, qs.stringify({ grant_type: "authorization_code", code: req.query.code as string, redirect_uri: `${FULL_SERVER_ROOT}/api/discord` }), { auth: { username: DISCORD_CLIENT_ID!, password: DISCORD_CLIENT_SECRET! } }); - const UserData = await axios.get(`https://discord.com/api/users/@me`, { headers: { Authorization: `${Discord.data.token_type} ${Discord.data.access_token}` } }); - if (UserData.status !== 200) - return (await QuickRevokeToken(res, Discord.data.access_token)).status(500).send("Failed to request user data from Discord's services."); + const Discord = await fetch( + "https://discord.com/api/oauth2/token", + { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + "Authorization": `Basic ${Buffer.from(`${DISCORD_CLIENT_ID}:${DISCORD_CLIENT_SECRET}`).toString("base64")}` + }, + body: qs.stringify({ grant_type: "authorization_code", code: req.query.code as string, redirect_uri: `${FULL_SERVER_ROOT}/api/discord` }) + } + ) - await QuickRevokeToken(res, Discord.data.access_token); + if (Discord.status !== 200) + return res.status(500).send("Failed to request OAuth token from Discord's services."); - const AnyUserExists = await User.exists(); // automatically grant the first user on the database administrator permissions - let UserPermissionLevel = !AnyUserExists ? UserPermissions.Administrator : UserPermissions.User; + const DiscordData = await Discord.json() as any; // :waaaaa: - if (AnyUserExists && Bot.isReady()) { - Debug("Using Discord roles to determine user permission level since the Discord bot exists and is ready."); + if (!DiscordData.scope.includes("identify")) + return (await QuickRevokeToken(res, DiscordData.access_token)).status(400).send("Missing identify scope. Please check if your OAuth link is correctly set up!"); - const Sewer = Bot.guilds.cache.get(DISCORD_SERVER_ID as string); - const Membuh = await Sewer?.members.fetch(UserData.data.id); - if (Membuh) { - const RoulInDeightabaise = await DiscordRole.find({ where: { ID: In(Membuh.roles.cache.map(x => x.id)) }, order: { GrantedPermissions: "DESC" } }); - if (RoulInDeightabaise.length > 0) - UserPermissionLevel = RoulInDeightabaise[0].GrantedPermissions; + const UserData = await fetch("https://discord.com/api/v10/users/@me", { + method: "GET", + headers: { + "Authorization": `${DiscordData.token_type} ${DiscordData.access_token}` + } + + }) - Debug(`Detected ${magenta(RoulInDeightabaise.length)} roles that override Database permissions for user ${magenta(`@${UserData.data.username}`)}. Giving permission level ${magenta(UserPermissionLevel)}.`) + const UserDataBody = await UserData.json() as any; + + if (UserData.status !== 200) + return (await QuickRevokeToken(res, DiscordData.access_token)).status(500).send("Failed to request user data from Discord's services."); + + await QuickRevokeToken(res, DiscordData.access_token); + + const AnyUserExists = await User.exists(); // automatically grant the first user on the database administrator permissions + let UserPermissionLevel = !AnyUserExists ? UserPermissions.Administrator : UserPermissions.User; + + if (AnyUserExists && Bot.isReady()) { + Debug("Using Discord roles to determine user permission level since the Discord bot exists and is ready."); + + const Sewer = Bot.guilds.cache.get(DISCORD_SERVER_ID as string); + const Membuh = await Sewer?.members.fetch(UserDataBody.id); + + if (Membuh) { + const RoulInDeightabaise = await DiscordRole.find({ where: { ID: In(Membuh.roles.cache.map(x => x.id)) }, order: { GrantedPermissions: "DESC" } }); + if (RoulInDeightabaise.length > 0) + UserPermissionLevel = RoulInDeightabaise[0].GrantedPermissions; + + Debug(`Detected ${magenta(RoulInDeightabaise.length)} roles that override Database permissions for user ${magenta(`@${UserDataBody.username}`)}. Giving permission level ${magenta(UserPermissionLevel)}.`) + } } - } - let DBUser = await User.findOne({ where: { ID: UserData.data.id } }); - if (!DBUser) - DBUser = await User.create({ - ID: UserData.data.id, - Username: UserData.data.username, - DisplayName: UserData.data.global_name ?? UserData.data.username, - ProfilePictureURL: `https://cdn.discordapp.com/avatars/${UserData.data.id}/${UserData.data.avatar}.webp`, - Library: [], - PermissionLevel: UserPermissionLevel - }).save(); - else - { - DBUser.Username = UserData.data.username; - DBUser.DisplayName = UserData.data.global_name ?? UserData.data.username; - DBUser.ProfilePictureURL = `https://cdn.discordapp.com/avatars/${UserData.data.id}/${UserData.data.avatar}.webp`; - DBUser.PermissionLevel = UserPermissionLevel; - await DBUser.save(); - } - - const JWT = jwt.sign({ ID: UserData.data.id }, JWT_KEY!, { algorithm: "HS256" }); - const UserDetails = Buffer.from(JSON.stringify({ ID: UserData.data.id, Username: UserData.data.username, GlobalName: UserData.data.global_name, Avatar: `https://cdn.discordapp.com/avatars/${UserData.data.id}/${UserData.data.avatar}.webp`, IsAdmin: DBUser.PermissionLevel >= UserPermissions.Administrator, Role: DBUser.PermissionLevel })).toString("hex") - if (req.query.state) { - try { - const Decoded = JSON.parse(Buffer.from(decodeURI(req.query.state as string), "base64").toString("utf-8")); - if (Decoded.Client === "PartypackerDesktop") - return res.redirect(`http://localhost:14968/?token=${encodeURI(JWT)}&user=${encodeURI(UserDetails)}`) - else - return res.status(400).send("Unsupported API client."); // idk maybe in the future we will maek more clients - } catch { - return res.status(400).send("Invalid state."); + let DBUser = await User.findOne({ where: { ID: UserDataBody.id } }); + if (!DBUser) + DBUser = await User.create({ + ID: UserDataBody.id, + Username: UserDataBody.username, + DisplayName: UserDataBody.global_name ?? UserDataBody.username, + ProfilePictureURL: `https://cdn.discordapp.com/avatars/${UserDataBody.id}/${UserDataBody.avatar}.webp`, + Library: [], + PermissionLevel: UserPermissionLevel + }).save(); + else { + DBUser.Username = UserDataBody.username; + DBUser.DisplayName = UserDataBody.global_name ?? UserDataBody.username; + DBUser.ProfilePictureURL = `https://cdn.discordapp.com/avatars/${UserDataBody.id}/${UserDataBody.avatar}.webp`; + DBUser.PermissionLevel = UserPermissionLevel; + await DBUser.save(); } - } - res - .cookie("Token", JWT) - .cookie("UserDetails", UserDetails) - .redirect(`${DASHBOARD_ROOT}/profile`); -}) + const JWT = jwt.sign({ ID: UserDataBody.id }, JWT_KEY!, { algorithm: "HS256" }); + const UserDetails = Buffer.from(JSON.stringify({ ID: UserDataBody.id, Username: UserDataBody.username, GlobalName: UserDataBody.global_name, Avatar: `https://cdn.discordapp.com/avatars/${UserDataBody.id}/${UserDataBody.avatar}.webp`, IsAdmin: DBUser.PermissionLevel >= UserPermissions.Administrator, Role: DBUser.PermissionLevel })).toString("hex") + if (req.query.state) { + try { + const Decoded = JSON.parse(Buffer.from(decodeURI(req.query.state as string), "base64").toString("utf-8")); + if (Decoded.Client === "PartypackerDesktop") + return res.redirect(`http://localhost:14968/?token=${encodeURI(JWT)}&user=${encodeURI(UserDetails)}`) + else + return res.status(400).send("Unsupported API client."); // idk maybe in the future we will maek more clients + } catch { + return res.status(400).send("Invalid state."); + } + } + + res + .cookie("Token", JWT) + .cookie("UserDetails", UserDetails) + .redirect(`${DASHBOARD_ROOT}/profile`); + }) export default { App, diff --git a/Server/Source/Routes/Pages.ts b/Server/Source/Routes/Pages.ts index 140339c..8379846 100644 --- a/Server/Source/Routes/Pages.ts +++ b/Server/Source/Routes/Pages.ts @@ -1,6 +1,5 @@ import { Router } from "express"; import { FullFortnitePages, GenerateFortnitePages } from "../Modules/FNUtil"; -import axios from "axios"; import { IS_DEBUG } from "../Modules/Constants"; import { RequireAuthentication } from "../Modules/Middleware"; @@ -42,11 +41,11 @@ App.get("/content/api/pages/fortnite-game/:Section", RequireAuthentication(), as if (!CachedSection) return res.status(404).send("funny section not found haha kill me"); - const ContentFromServer = await axios.get(`https://fortnitecontent-website-prod07.ol.epicgames.com/content/api/pages/fortnite-game/${CachedSection._title}`); + const ContentFromServer = await fetch(`https://fortnitecontent-website-prod07.ol.epicgames.com/content/api/pages/fortnite-game/${CachedSection._title}`) if (ContentFromServer.status !== 200) - return res.status(404).json({ error: IS_DEBUG ? ContentFromServer.data : "Fortnite server returned an error." }); + return res.status(404).json({ error: IS_DEBUG ? await ContentFromServer.text() : "Fortnite server returned an error." }); - res.json(ContentFromServer.data); + res.json(await ContentFromServer.json()); }) export default { diff --git a/Server/package-lock.json b/Server/package-lock.json index 106e791..f063e0d 100644 --- a/Server/package-lock.json +++ b/Server/package-lock.json @@ -10,7 +10,6 @@ "license": "ISC", "dependencies": { "@types/node-cron": "^3.0.11", - "axios": "^1.6.5", "better-sqlite3": "^9.3.0", "colorette": "^2.0.20", "cookie-parser": "^1.4.6", @@ -34,7 +33,7 @@ "@types/express": "^4.17.18", "@types/fluent-ffmpeg": "^2.1.24", "@types/jsonwebtoken": "^9.0.5", - "@types/node": "^20.6.3", + "@types/node": "^20.11.16", "@types/underscore": "^1.11.15", "@types/uuid": "^9.0.7", "tslib": "^2.6.2", @@ -335,9 +334,12 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.8.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz", - "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==" + "version": "20.11.16", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.16.tgz", + "integrity": "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ==", + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/node-cron": { "version": "3.0.11", @@ -466,21 +468,6 @@ "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/axios": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz", - "integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==", - "dependencies": { - "follow-redirects": "^1.15.4", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -850,17 +837,6 @@ "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -973,14 +949,6 @@ "node": ">=4.0.0" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -1221,25 +1189,6 @@ "which": "bin/which" } }, - "node_modules/follow-redirects": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", - "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, "node_modules/foreground-child": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", @@ -1255,19 +1204,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1928,11 +1864,6 @@ "node": ">= 0.10" } }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -2620,6 +2551,11 @@ "node": ">=14.0" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", diff --git a/Server/package.json b/Server/package.json index 2f096f4..d92f4bd 100644 --- a/Server/package.json +++ b/Server/package.json @@ -34,7 +34,7 @@ "@types/express": "^4.17.18", "@types/fluent-ffmpeg": "^2.1.24", "@types/jsonwebtoken": "^9.0.5", - "@types/node": "^20.6.3", + "@types/node": "^20.11.16", "@types/underscore": "^1.11.15", "@types/uuid": "^9.0.7", "tslib": "^2.6.2", @@ -42,7 +42,6 @@ }, "dependencies": { "@types/node-cron": "^3.0.11", - "axios": "^1.6.5", "better-sqlite3": "^9.3.0", "colorette": "^2.0.20", "cookie-parser": "^1.4.6", diff --git a/package-lock.json b/package-lock.json index c823518..3611a76 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@esbuild-plugins/node-globals-polyfill": "^0.2.3", "@esbuild-plugins/node-modules-polyfill": "^0.2.2", "@primer/react": "^36.5.0", + "@types/axios": "^0.14.0", "axios": "^1.6.5", "buffer": "^6.0.3", "deepmerge": "^4.3.1", @@ -1501,6 +1502,15 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/axios": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.0.tgz", + "integrity": "sha512-KqQnQbdYE54D7oa/UmYVMZKq7CO4l8DEENzOKc4aBRwxCXSlJXGz83flFx5L7AWrOQnmuN3kVsRdt+GZPPjiVQ==", + "deprecated": "This is a stub types definition for axios (https://github.com/mzabriskie/axios). axios provides its own type definitions, so you don't need @types/axios installed!", + "dependencies": { + "axios": "*" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", diff --git a/package.json b/package.json index 5819e58..a8ac64f 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "@esbuild-plugins/node-globals-polyfill": "^0.2.3", "@esbuild-plugins/node-modules-polyfill": "^0.2.2", "@primer/react": "^36.5.0", + "@types/axios": "^0.14.0", "axios": "^1.6.5", "buffer": "^6.0.3", "deepmerge": "^4.3.1",