release: 1.3.2

This commit is contained in:
dvelo 2024-10-04 21:06:02 -05:00
parent 07ec6cb89b
commit 6aff5751c6
15 changed files with 519 additions and 787 deletions

@ -30,17 +30,17 @@ The primary stack for MHSF is Next.js, a React framework, which you can start by
## Clerk
If you want to test out accounts, [you must create an Clerk key from their website.](https://clerk.com)
Set the following variables in the .env.local file:
```env
```dotenv
# Clerk
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=<the token you saw>
CLERK_SECRET_KEY=<the token you saw>
IS_AUTH=true
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="pk_..."
CLERK_SECRET_KEY="sk_..."
IS_AUTH="true"
```
## MongoDB
We use [Atlas](https://www.mongodb.com/atlas) to host our MongoDB database, but you do need one. Add the following to your .env.local with your database:
```env
MONGO_DB=
```dotenv
MONGO_DB="mongodb+srv://..."
```
## Smaller things (for production-ready servers)
@ -63,6 +63,18 @@ yarn run build
> You must have a `.env.local` with a MongoDB database (same `MONGO_DB` key) in the previous directory (for monorepo like management) running without Docker, and
> the same `.env.local` *but in the same directory when* using Docker.
### Reporting
Reporting inside MHSF uses [Linear](https://linear.app). Create an API key inside a team, and add it to the `LINEAR`
key inside of `.env.local`
```dotenv
LINEAR="ln_api_..."
```
MHSF will start adding issues automatically, displaying all information
about a server & the user reporting.
For more information about Linear's authentication, refer to the [API
documentation](https://developers.linear.app/docs/graphql/working-with-the-graphql-api#personal-api-keys).
### Inngest
Inngest also runs periodic tasks like Cron, but has less important tasks that may occur. Create an account on Inngest, or just use the dev server.
Do the following tasks and set the endpoint to `<server url>/api/inngest`

@ -4,6 +4,10 @@
"rules": {
"style": {
"useTemplate": "off"
},
"suspicious": {
"noExplicitAny": "off",
"noDoubleEquals": "warn"
}
}
}

@ -7,33 +7,32 @@ console.log(chalk.yellow(chalk.bold("MHSF crontab scripts")));
console.log(chalk.yellow(chalk.bold("by dvelo - licensed under MIT license")));
console.log();
import { MongoClient, WithId } from "mongodb";
import { MongoClient, type WithId } from "mongodb";
import { config } from "dotenv";
import {
import type {
OnlineServer,
OnlineServerExtended,
ServerResponse,
} from "./types/mh-server.js";
import { CronJob } from "cron";
import { Achievement } from "./types/achievement.js";
import type { Achievement } from "./types/achievement.js";
// set-up config
config({
path: process.env.MHC_DOCKER != "true" ? "../.env.local" : "./.env.local",
});
let mongo = new MongoClient(process.env.MONGO_DB as string);
const mongo = new MongoClient(process.env.MONGO_DB as string);
const SUCCESS = chalk.green("SUCCESS");
const ERROR = chalk.red("ERROR");
const WARN = chalk.red("WARN");
const INFO = chalk.blueBright("INFO");
console.log(INFO, "Starting cron job #1");
CronJob.from({
cronTime: "*/30 * * * *",
onTick: function () {
onTick: () => {
periodicCronJob().catch((e) => {
console.log(chalk.red("[CRON] " + ERROR + " Error while running: "));
console.error(e);
@ -46,7 +45,7 @@ CronJob.from({
console.log(INFO, "Starting cron job #2");
CronJob.from({
cronTime: "0 */12 * * *",
onTick: function () {
onTick: () => {
achievementTask().catch((e) => {
console.log(chalk.red("[CRON] " + ERROR + " Error while running: "));
console.error(e);

@ -12,7 +12,6 @@ const nextConfig = {
},
async redirects() {
return [
// Basic redirect
{
source: '/docs',
destination: '/docs/getting-started',

@ -17,6 +17,7 @@
"@biomejs/biome": "^1.8.3",
"@clerk/nextjs": "^5.1.3",
"@emotion/is-prop-valid": "^1.3.0",
"@linear/sdk": "^31.0.0",
"@monaco-editor/react": "^4.6.0",
"@radix-ui/react-hover-card": "^1.1.1",
"@radix-ui/react-icons": "^1.3.0",

@ -20,7 +20,7 @@ export default function ColorProvider({
getCustomization(server).then((v) =>
setColor(v != null ? v.colorScheme : "zinc")
);
else setColor(fetch != null ? fetch.colorScheme : "zinc");
else setColor(fetch.colorScheme);
}, []);
return <div className={`theme-${color}`}>{children}</div>;

@ -2,7 +2,7 @@
import { useState } from "react";
import { Spinner } from "./ui/spinner";
import { Card, CardHeader, CardTitle } from "./ui/card";
import { ServerResponse } from "@/lib/types/mh-server";
import type { ServerResponse } from "@/lib/types/mh-server";
import { useEffectOnce } from "@/lib/useEffectOnce";
import { Button } from "./ui/button";
import { Copy, Layers, XIcon } from "lucide-react";
@ -26,16 +26,16 @@ export default function FavoritesView() {
(b) =>
b.json().then((c) => {
num++;
var apiClone = apiFavorites;
const apiClone = apiFavorites;
apiClone.push(c.server);
setApiFavorites(apiClone);
if (num == d.length) {
if (num === d.length) {
setLoading(false);
}
})
);
});
if (d.length == 0) setLoading(false);
if (d.length === 0) setLoading(false);
});
});
@ -62,7 +62,7 @@ export default function FavoritesView() {
return (
<>
{apiFavorites.length == 0 && (
{apiFavorites.length === 0 && (
<div className="flex items-center justify-center">
<XIcon />
Your favorites are empty. Maybe favorite a server!

@ -7,7 +7,7 @@ import { ChevronRight } from "lucide-react";
import { useRouter } from "@/lib/useRouter";
import { AnimatePresence, motion } from "framer-motion";
export function Sidebar() {
export function sSidebar() {
return (
<>
{allFolders.map((docs) => (

@ -126,6 +126,20 @@ export const Changelog = () => {
See more information about MHSF and how to use it
</Marquee>
</Button>
</div>
<br/>
<div>
<strong className="flex items-center">
Version 1.3.2 (October 4th 2024)
</strong>
<ul>
<li>
Minor backend changes
</li>
<li>
<A alt="Please check on GitHub for statuses about this project.">Special:GitHub/releases/tag/1.3.2</A>
</li>
</ul>
</div>
<br/>
<div>
@ -362,7 +376,8 @@ const Github = (props: SVGProps<SVGSVGElement>) => (
preserveAspectRatio="xMidYMid"
{...props}
>
<path d="M128.001 0C57.317 0 0 57.307 0 128.001c0 56.554 36.676 104.535 87.535 121.46 6.397 1.185 8.746-2.777 8.746-6.158 0-3.052-.12-13.135-.174-23.83-35.61 7.742-43.124-15.103-43.124-15.103-5.823-14.795-14.213-18.73-14.213-18.73-11.613-7.944.876-7.78.876-7.78 12.853.902 19.621 13.19 19.621 13.19 11.417 19.568 29.945 13.911 37.249 10.64 1.149-8.272 4.466-13.92 8.127-17.116-28.431-3.236-58.318-14.212-58.318-63.258 0-13.975 5-25.394 13.188-34.358-1.329-3.224-5.71-16.242 1.24-33.874 0 0 10.749-3.44 35.21 13.121 10.21-2.836 21.16-4.258 32.038-4.307 10.878.049 21.837 1.47 32.066 4.307 24.431-16.56 35.165-13.12 35.165-13.12 6.967 17.63 2.584 30.65 1.255 33.873 8.207 8.964 13.173 20.383 13.173 34.358 0 49.163-29.944 59.988-58.447 63.157 4.591 3.972 8.682 11.762 8.682 23.704 0 17.126-.148 30.91-.148 35.126 0 3.407 2.304 7.398 8.792 6.14C219.37 232.5 256 184.537 256 128.002 256 57.307 198.691 0 128.001 0Zm-80.06 182.34c-.282.636-1.283.827-2.194.39-.929-.417-1.45-1.284-1.15-1.922.276-.655 1.279-.838 2.205-.399.93.418 1.46 1.293 1.139 1.931Zm6.296 5.618c-.61.566-1.804.303-2.614-.591-.837-.892-.994-2.086-.375-2.66.63-.566 1.787-.301 2.626.591.838.903 1 2.088.363 2.66Zm4.32 7.188c-.785.545-2.067.034-2.86-1.104-.784-1.138-.784-2.503.017-3.05.795-.547 2.058-.055 2.861 1.075.782 1.157.782 2.522-.019 3.08Zm7.304 8.325c-.701.774-2.196.566-3.29-.49-1.119-1.032-1.43-2.496-.726-3.27.71-.776 2.213-.558 3.315.49 1.11 1.03 1.45 2.505.701 3.27Zm9.442 2.81c-.31 1.003-1.75 1.459-3.199 1.033-1.448-.439-2.395-1.613-2.103-2.626.301-1.01 1.747-1.484 3.207-1.028 1.446.436 2.396 1.602 2.095 2.622Zm10.744 1.193c.036 1.055-1.193 1.93-2.715 1.95-1.53.034-2.769-.82-2.786-1.86 0-1.065 1.202-1.932 2.733-1.958 1.522-.03 2.768.818 2.768 1.868Zm10.555-.405c.182 1.03-.875 2.088-2.387 2.37-1.485.271-2.861-.365-3.05-1.386-.184-1.056.893-2.114 2.376-2.387 1.514-.263 2.868.356 3.061 1.403Z" />
<path
d="M128.001 0C57.317 0 0 57.307 0 128.001c0 56.554 36.676 104.535 87.535 121.46 6.397 1.185 8.746-2.777 8.746-6.158 0-3.052-.12-13.135-.174-23.83-35.61 7.742-43.124-15.103-43.124-15.103-5.823-14.795-14.213-18.73-14.213-18.73-11.613-7.944.876-7.78.876-7.78 12.853.902 19.621 13.19 19.621 13.19 11.417 19.568 29.945 13.911 37.249 10.64 1.149-8.272 4.466-13.92 8.127-17.116-28.431-3.236-58.318-14.212-58.318-63.258 0-13.975 5-25.394 13.188-34.358-1.329-3.224-5.71-16.242 1.24-33.874 0 0 10.749-3.44 35.21 13.121 10.21-2.836 21.16-4.258 32.038-4.307 10.878.049 21.837 1.47 32.066 4.307 24.431-16.56 35.165-13.12 35.165-13.12 6.967 17.63 2.584 30.65 1.255 33.873 8.207 8.964 13.173 20.383 13.173 34.358 0 49.163-29.944 59.988-58.447 63.157 4.591 3.972 8.682 11.762 8.682 23.704 0 17.126-.148 30.91-.148 35.126 0 3.407 2.304 7.398 8.792 6.14C219.37 232.5 256 184.537 256 128.002 256 57.307 198.691 0 128.001 0Zm-80.06 182.34c-.282.636-1.283.827-2.194.39-.929-.417-1.45-1.284-1.15-1.922.276-.655 1.279-.838 2.205-.399.93.418 1.46 1.293 1.139 1.931Zm6.296 5.618c-.61.566-1.804.303-2.614-.591-.837-.892-.994-2.086-.375-2.66.63-.566 1.787-.301 2.626.591.838.903 1 2.088.363 2.66Zm4.32 7.188c-.785.545-2.067.034-2.86-1.104-.784-1.138-.784-2.503.017-3.05.795-.547 2.058-.055 2.861 1.075.782 1.157.782 2.522-.019 3.08Zm7.304 8.325c-.701.774-2.196.566-3.29-.49-1.119-1.032-1.43-2.496-.726-3.27.71-.776 2.213-.558 3.315.49 1.11 1.03 1.45 2.505.701 3.27Zm9.442 2.81c-.31 1.003-1.75 1.459-3.199 1.033-1.448-.439-2.395-1.613-2.103-2.626.301-1.01 1.747-1.484 3.207-1.028 1.446.436 2.396 1.602 2.095 2.622Zm10.744 1.193c.036 1.055-1.193 1.93-2.715 1.95-1.53.034-2.769-.82-2.786-1.86 0-1.065 1.202-1.932 2.733-1.958 1.522-.03 2.768.818 2.768 1.868Zm10.555-.405c.182 1.03-.875 2.088-2.387 2.37-1.485.271-2.861-.365-3.05-1.386-.184-1.056.893-2.114 2.376-2.387 1.514-.263 2.868.356 3.061 1.403Z" />
</svg>
);

29
src/lib/linear.ts Normal file

@ -0,0 +1,29 @@
import { LinearClient, LinearFetch, User } from "@linear/sdk";
export async function createReportIssue(server: string, reportDescription: string, userId: string) {
const linearClient = new LinearClient({
apiKey: process.env.LINEAR
})
const allTeams = await linearClient.teams();
// Always grabs the first issue category.
const team = allTeams.nodes[0];
// Ensure there *actually* is a team there
if (team.id) {
await linearClient.createIssue({teamId: team.id, title: `Issue against server \`${server}\``, description: desc(userId, server, reportDescription), assigneeId: (await team.members()).nodes[0].id })
}
}
const desc = (user: string, server: string, reason: string) => `There was a report against the server, submitted by a user.
Every issue must be [considered with care](https://list.mlnehut.com/docs/legal/external-content-agreement) before evaluating its outcome.
**User**: \`${user}\`
**Server**: \`${server}\`
**For reason**:
${reason}
*This was an automatically added issue by the report bot. Add the canceled status to remove the issue from the active issues, along with the labels Not Controllable & Spam for their respective values.*
`

@ -1,119 +1,9 @@
import { OnlineServer } from "@/lib/types/mh-server";
import type { OnlineServer } from "@/lib/types/mh-server";
import { Inngest } from "inngest";
import { serve } from "inngest/next";
import { Document, MongoClient, ObjectId, WithId } from "mongodb";
import {
ActionRowBuilder,
ButtonBuilder,
ButtonStyle,
Client,
EmbedBuilder,
GatewayIntentBits,
ModalBuilder,
REST,
Routes,
SlashCommandBuilder,
SlashCommandStringOption,
TextChannel,
TextInputBuilder,
TextInputStyle,
} from "discord.js";
import {createReportIssue} from "@/lib/linear";
let reporting = true;
let initalizedYet = false;
const commands = [
new SlashCommandBuilder()
.setName("realive")
.setDescription("Re-alive an existing report that was glitched")
.addStringOption(
new SlashCommandStringOption()
.setName("id")
.setRequired(true)
.setDescription("Report ID")
),
];
let client: Client;
// this isn't entirely necessary, to run each time the server starts
async function init() {
try {
const rest = new REST({ version: "10" }).setToken(
process.env.DISCORD_TOKEN as string
);
try {
console.log("[REPORTING] Started refreshing application (/) commands.");
await rest.put(
Routes.applicationCommands(process.env.DISCORD_APP_ID as string),
{ body: commands }
);
console.log(
"[REPORTING] Successfully reloaded application (/) commands."
);
} catch (error) {
console.error(error);
}
} catch {
console.log(
"[REPORTING] Discord API token not found, skipping reporting..."
);
reporting = false;
}
client = new Client({
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages],
});
client.on("interactionCreate", async (interaction) => {
if (!interaction.isChatInputCommand()) return;
if (interaction.commandName === "realive") {
await interaction.reply({
embeds: [
new EmbedBuilder()
.setTitle("Re-creating report")
.setColor("Blurple")
.setDescription("This may take a few seconds.."),
],
ephemeral: true,
});
const mongo = new MongoClient(process.env.MONGO_DB as string);
const db = mongo.db("mhsf");
const collection = db.collection("reports");
let reportDoc: WithId<Document> | null;
try {
reportDoc = await collection.findOne({
_id: new ObjectId(interaction.options.getString("id") as string),
});
} catch {
await interaction.editReply({
embeds: [
new EmbedBuilder()
.setTitle("Report ID not valid")
.setColor("Red")
.setDescription("This report could not be found."),
],
});
return;
}
if (reportDoc === null) {
await interaction.editReply({
embeds: [
new EmbedBuilder()
.setTitle("Report not found")
.setColor("Red")
.setDescription("This report could not be found."),
],
});
return;
}
report({ data: { ...reportDoc, id: reportDoc._id.toString() } });
}
});
return;
}
// Create a client to send and receive events
export const inngest = new Inngest({ id: "mhsf" });
@ -125,28 +15,11 @@ export default serve({
{ id: "report" },
{ event: "report-server" },
async ({ event, step }) => {
if (!reporting) {
throw new Error("Cannot report server: Discord API token not found");
}
// by the way, I bombed the Discord stuff
await createReportIssue(event.data.server, event.data.reason, event.data.userId);
if (!initalizedYet) {
await init();
initalizedYet = true;
await client.login(process.env.DISCORD_TOKEN);
console.log(`[REPORTING] Waiting for bot to be ready`);
client.on("ready", () => {
console.log(
`[REPORTING] Bot logged in as ${client.user?.displayName}`
);
report(event);
});
return;
}
report(event);
}
return { event, body: "Done" }
},
),
inngest.createFunction(
{ id: "short-term-data" },
@ -214,242 +87,9 @@ export default serve({
return { event, body: "Cloudflare.. aborting " + e };
}
}
},
),
],
});
async function report(event: any) {
const isTextBased = client.channels.cache.get(
process.env.REPORTS_CHANNEL as string
)?.isTextBased;
if (!isTextBased) {
throw new Error(
"Cannot report server: Report channel not found or not a text channel."
);
}
const channel = client.channels.cache.get(
process.env.REPORTS_CHANNEL as string
) as TextChannel;
const goToServer = new ButtonBuilder()
.setLabel("Go to server")
.setStyle(ButtonStyle.Link)
.setURL("https://list.mlnehut.com/server/" + event.data.server);
const confirm = new ButtonBuilder()
.setCustomId("resolve")
.setLabel("Resolve")
.setStyle(ButtonStyle.Primary);
const typed = (name: string) =>
new ButtonBuilder()
.setCustomId("typed")
.setLabel(name + " is typing")
.setStyle(ButtonStyle.Secondary)
.setDisabled(true);
const cancel = new ButtonBuilder()
.setCustomId("cancel")
.setLabel("Cancel")
.setStyle(ButtonStyle.Secondary);
const undo = new ButtonBuilder()
.setCustomId("undo")
.setLabel("Undo")
.setStyle(ButtonStyle.Danger);
const undor = new ActionRowBuilder<ButtonBuilder>().addComponents(
undo,
goToServer
);
const rowN = new ActionRowBuilder<ButtonBuilder>().addComponents(
confirm,
cancel,
goToServer
);
const message = await channel.send({
embeds: [
new EmbedBuilder()
.setColor("Orange")
.setTitle("New report to server")
.setTimestamp()
.setDescription(
"A server has been reported by a player. \n Reason: " +
event.data.reason +
(event.data.reason == "" ? "*<empty>*" : "")
)
.setFields([
{ name: "User ID", value: `\`${event.data.userId}\`` },
{ name: "Server", value: `${event.data.server}` },
])
.setFooter({
text:
"Is this report glitched? Use the command /realive id:" +
event.data._id +
" to do actions on this report.",
}),
],
components: [rowN],
});
setTimeout(async () => {
await messageLoop();
async function messageLoop() {
const confirmation = await message.awaitMessageComponent({});
if (confirmation.customId == "undo") {
(await confirmation.reply({ content: "Done!" })).delete();
await message.edit({
embeds: [
new EmbedBuilder()
.setColor("Orange")
.setTitle("New report to server")
.setTimestamp()
.setDescription(
"A server has been reported by a player. \n Reason: " +
event.data.reason +
(event.data.reason == "" ? "*<empty>*" : "")
)
.setFields([
{ name: "User ID", value: `\`${event.data.userId}\`` },
{ name: "Server", value: `${event.data.server}` },
])
.setFooter({
text:
"Is this report glitched? Use the command /realive id:" +
event.data._id +
" to do actions on this report.",
}),
],
components: [rowN],
});
}
if (confirmation.customId == "resolve") {
await message.edit({
embeds: [
new EmbedBuilder()
.setColor("Green")
.setTitle("Server report resolved")
.setTimestamp()
.setDescription(
"The server report has been resolved by <@" +
confirmation.user.id +
"> \n Reason: " +
event.data.reason +
(event.data.reason == "" ? "*<empty>*" : "")
)
.setFields([
{ name: "User ID", value: `\`${event.data.userId}\`` },
{ name: "Server", value: `${event.data.server}` },
])
.setFooter({
text:
"Is this report glitched? Use the command /realive id:" +
event.data._id +
" to do actions on this report.",
}),
],
components: [undor],
});
(
await confirmation.reply({ content: "Done!", ephemeral: true })
).delete();
}
if (confirmation.customId == "cancel") {
const modal = new ModalBuilder().setCustomId("why").setTitle("MHSF");
const favoriteColorInput = new TextInputBuilder()
.setCustomId("whyToCancel")
.setLabel("Cancelation reason")
.setStyle(TextInputStyle.Short);
const row = new ActionRowBuilder<TextInputBuilder>().addComponents(
favoriteColorInput
);
modal.addComponents(row);
confirmation.showModal(modal);
try {
let reportedYet = false;
await message.edit({
components: [
new ActionRowBuilder<ButtonBuilder>().addComponents(
typed(
confirmation.user.globalName || confirmation.user.username
)
),
],
});
setTimeout(async () => {
if (reportedYet == false) {
await message.edit({
components: [rowN],
});
await messageLoop();
}
return;
}, 60_000);
const submission = await confirmation.awaitModalSubmit({
time: 60_000,
});
const text = submission.fields.getTextInputValue("whyToCancel");
if (text == "") {
await submission.reply({ content: "Done!", ephemeral: true });
await messageLoop();
}
reportedYet = true;
await message.edit({
embeds: [
new EmbedBuilder()
.setColor("Red")
.setTitle("Server report cancelled")
.setTimestamp()
.setDescription(
"The server report has been cancelled by <@" +
confirmation.user.id +
"> \n Reason of cancelation: " +
text +
"\nReason of report: " +
event.data.reason +
(event.data.reason == "" ? "*<empty>*" : "")
)
.setFields([
{ name: "User ID", value: `\`${event.data.userId}\`` },
{ name: "Server", value: `${event.data.server}` },
])
.setFooter({
text:
"Is this report glitched? Use the command /realive id:" +
event.data._id +
" to do actions on this report.",
}),
],
components: [undor],
});
await submission.reply({ content: "Done!", ephemeral: true });
} catch (e) {
await message.edit({
components: [rowN],
});
await confirmation.reply({
embeds: [
new EmbedBuilder()
.setTitle("You took too long!")
.setDescription("Please try again.")
.setColor("Red"),
],
ephemeral: true,
});
}
}
await messageLoop();
}
}, 0);
}

@ -45,3 +45,4 @@ export default async function handler(
});
res.status(200).send({ message: "Success" });
}

@ -3,7 +3,7 @@ import { NextApiRequest, NextApiResponse } from "next";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
res: NextApiResponse,
) {
const { server } = req.query;
if (!server) return res.status(400).send({ error: "No server was provided" });

@ -3,7 +3,7 @@ import { MongoClient } from "mongodb";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
res: NextApiResponse,
) {
if (req.headers.Authentication != process.env.WEBHOOK_AUTH) {
return res.status(401).json({ error: "Unauthorized" });

@ -649,6 +649,11 @@
resolved "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz"
integrity sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==
"@graphql-typed-document-node/core@^3.1.0":
version "3.2.0"
resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861"
integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==
"@grpc/grpc-js@^1.7.1":
version "1.11.1"
resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.11.1.tgz#a92f33e98f1959feffcd1b25a33b113d2c977b70"
@ -753,6 +758,15 @@
jsbi "^4.3.0"
tslib "^2.4.1"
"@linear/sdk@^31.0.0":
version "31.0.0"
resolved "https://registry.yarnpkg.com/@linear/sdk/-/sdk-31.0.0.tgz#05faac8bbb9ebd7b530760e9535f5bd7fe2f3618"
integrity sha512-51mKO/R5JBnQERDfg5uMryHGRyavUAkveIiHxxshItvEIwFVACJi8S7N2oabhSlqqNZf2rL0YlVokeRxd72s6A==
dependencies:
"@graphql-typed-document-node/core" "^3.1.0"
graphql "^15.4.0"
isomorphic-unfetch "^3.1.0"
"@mdx-js/esbuild@^2.0.0":
version "2.3.0"
resolved "https://registry.yarnpkg.com/@mdx-js/esbuild/-/esbuild-2.3.0.tgz#97f2f1b854d904c50bcd0a219b3664657f4fe8c3"
@ -4145,6 +4159,11 @@ graphemer@^1.4.0:
resolved "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz"
integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
graphql@^15.4.0:
version "15.9.0"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.9.0.tgz#4e8ca830cfd30b03d44d3edd9cac2b0690304b53"
integrity sha512-GCOQdvm7XxV1S4U4CGrsdlEN37245eC8P9zaYCMr6K1BG0IPGy5lUwmJsEOGyl1GD6HXjOtl2keCP9asRBwNvA==
gray-matter@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/gray-matter/-/gray-matter-4.0.3.tgz#e893c064825de73ea1f5f7d88c7a9f7274288798"
@ -4735,6 +4754,14 @@ isexe@^2.0.0:
resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz"
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
isomorphic-unfetch@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz#87341d5f4f7b63843d468438128cb087b7c3e98f"
integrity sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==
dependencies:
node-fetch "^2.6.1"
unfetch "^4.2.0"
iterator.prototype@^1.1.2:
version "1.1.2"
resolved "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz"
@ -6165,7 +6192,7 @@ node-fetch-native@^1.6.3:
resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.4.tgz#679fc8fd8111266d47d7e72c379f1bed9acff06e"
integrity sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==
node-fetch@^2.6.12:
node-fetch@^2.6.1, node-fetch@^2.6.12:
version "2.7.0"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
@ -7794,6 +7821,11 @@ undici@6.13.0:
resolved "https://registry.yarnpkg.com/undici/-/undici-6.13.0.tgz#7edbf4b7f3aac5f8a681d515151bf55cb3589d72"
integrity sha512-Q2rtqmZWrbP8nePMq7mOJIN98M0fYvSgV89vwl/BQRT4mDOeY2GXZngfGpcBBhtky3woM7G24wZV3Q304Bv6cw==
unfetch@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be"
integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==
unified@^10.0.0, unified@^10.1.2:
version "10.1.2"
resolved "https://registry.yarnpkg.com/unified/-/unified-10.1.2.tgz#b1d64e55dafe1f0b98bb6c719881103ecf6c86df"