Merge pull request from GHSA-xmj6-g32r-fc5q

* remove support for import export anythingllm data

* remove unused imports
remove unused dep
update lockfile

---------

Co-authored-by: timothycarambat <rambat1010@gmail.com>
This commit is contained in:
Sean Hatfield 2024-01-18 13:57:23 -08:00 committed by GitHub
parent 56fa17caf2
commit 08d33cfd8f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 3 additions and 584 deletions

View File

@ -34,9 +34,6 @@ const GeneralEmbeddingPreference = lazy(
const GeneralVectorDatabase = lazy(
() => import("@/pages/GeneralSettings/VectorDatabase")
);
const GeneralExportImport = lazy(
() => import("@/pages/GeneralSettings/ExportImport")
);
const GeneralSecurity = lazy(() => import("@/pages/GeneralSettings/Security"));
const DataConnectors = lazy(
() => import("@/pages/GeneralSettings/DataConnectors")
@ -74,10 +71,6 @@ export default function App() {
element={<AdminRoute Component={GeneralVectorDatabase} />}
/>
{/* Manager */}
<Route
path="/settings/export-import"
element={<ManagerRoute Component={GeneralExportImport} />}
/>
<Route
path="/settings/security"
element={<ManagerRoute Component={GeneralSecurity} />}

View File

@ -1,6 +1,4 @@
import React, { useEffect, useRef, useState } from "react";
// import IndexCount from "../Sidebar/IndexCount";
// import LLMStatus from "../Sidebar/LLMStatus";
import paths from "@/utils/paths";
import useLogo from "@/hooks/useLogo";
import {
@ -14,10 +12,8 @@ import {
Key,
ChatText,
Database,
DownloadSimple,
Lock,
GithubLogo,
DotsThree,
House,
X,
List,
@ -135,12 +131,6 @@ export default function SettingsSidebar() {
/>
</>
)}
<Option
href={paths.settings.exportImport()}
btnText="Export or Import"
icon={<DownloadSimple className="h-5 w-5 flex-shrink-0" />}
/>
<Option
href={paths.settings.security()}
btnText="Security"
@ -328,11 +318,6 @@ export function SidebarMobileHeader() {
/>
</>
)}
<Option
href={paths.settings.exportImport()}
btnText="Export or Import"
icon={<DownloadSimple className="h-5 w-5 flex-shrink-0" />}
/>
<Option
href={paths.settings.security()}
btnText="Security"

View File

@ -160,31 +160,6 @@ const System = {
return false;
});
},
dataExport: async () => {
return await fetch(`${API_BASE}/system/data-export`, {
method: "GET",
headers: baseHeaders(),
})
.then((res) => res.json())
.then((res) => res)
.catch((e) => {
console.error(e);
return { filename: null, error: e.message };
});
},
importData: async (formData) => {
return await fetch(`${API_BASE}/system/data-import`, {
method: "POST",
body: formData,
headers: baseHeaders(),
})
.then((res) => res.json())
.then((res) => res)
.catch((e) => {
console.error(e);
return { success: false, error: e.message };
});
},
uploadPfp: async function (formData) {
return await fetch(`${API_BASE}/system/upload-pfp`, {
method: "POST",

View File

@ -1,226 +0,0 @@
import { useRef, useState } from "react";
import Sidebar, { SidebarMobileHeader } from "@/components/SettingsSidebar";
import { isMobile } from "react-device-detect";
import showToast from "@/utils/toast";
import { CloudArrowUp, DownloadSimple } from "@phosphor-icons/react";
import System from "@/models/system";
import { API_BASE } from "@/utils/constants";
import paths from "@/utils/paths";
export default function GeneralExportImport() {
const hostname = window?.location?.hostname;
const isHosted = hostname.includes(".useanything.com");
if (isHosted) {
return (
<div className="w-screen h-screen overflow-hidden bg-sidebar flex">
{!isMobile && <Sidebar />}
<div
style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }}
className="transition-all duration-500 relative md:ml-[2px] md:mr-[16px] md:my-[16px] md:rounded-[26px] bg-main-gradient w-full h-full overflow-y-scroll border-4 border-accent"
>
{isMobile && <SidebarMobileHeader />}
<div className="flex flex-col w-full px-1 md:px-20 md:py-12 py-16">
<div className="w-full flex flex-col gap-y-1 pb-6 border-white border-b-2 border-opacity-10">
<div className="items-center flex gap-x-4">
<p className="text-2xl font-semibold text-white">
Export or Import
</p>
</div>
</div>
</div>
<div className="w-full items-center justify-center flex flex-col gap-y-4">
<p className="text-lg font-base text-white text-opacity-60">
This feature is temporarily disabled for hosted AnythingLLM
instances.
</p>
<a
href={`${paths.mailToMintplex()}?Subject=Import/Export disabled on hosted AnythingLLM.`}
className="text-blue-300 hover:underline"
>
Contact Mintplex Labs Inc.
</a>
</div>
</div>
</div>
);
}
return (
<div className="w-screen h-screen overflow-hidden bg-sidebar flex">
{!isMobile && <Sidebar />}
<div
style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }}
className="transition-all duration-500 relative md:ml-[2px] md:mr-[16px] md:my-[16px] md:rounded-[26px] bg-main-gradient w-full h-full overflow-y-scroll border-4 border-accent"
>
{isMobile && <SidebarMobileHeader />}
<div className="flex flex-col w-full px-1 md:px-20 md:py-12 py-16">
<div className="w-full flex flex-col gap-y-1 pb-6 border-white border-b-2 border-opacity-10">
<div className="items-center flex gap-x-4">
<p className="text-2xl font-semibold text-white">
Export or Import
</p>
</div>
<p className="text-sm font-base text-white text-opacity-60">
Have multiple AnythingLLM instances or simply want to backup or
re-import data from another instance? You can do so here.
</p>
</div>
<div className="text-white text-sm font-medium py-4">
This will not automatically sync your vector database embeddings.
</div>
<ImportData />
<ExportData />
</div>
</div>
</div>
);
}
function ImportData() {
const inputRef = useRef(null);
const [loading, setLoading] = useState(false);
const [file, setFile] = useState(null);
const [result, setResult] = useState(null);
const startInput = () => inputRef?.current?.click();
const handleUpload = async (e) => {
setLoading(true);
e.preventDefault();
setFile(null);
setResult(null);
const file = e.target.files?.[0];
if (!file) {
showToast("Invalid file upload", "error");
return false;
}
setFile(file);
setLoading(true);
const formData = new FormData();
formData.append("file", file, file.name);
const { success, error } = await System.importData(formData);
if (!success) {
showToast(`Failed to import data: ${error}`, "error");
} else {
setResult(true);
showToast(`Successfully imported ${file.name}`, "success");
}
setLoading(false);
setFile(null);
};
return (
<div
onClick={startInput}
className="max-w-[600px] py-4 bg-zinc-900/50 rounded-2xl border-2 border-dashed border-white border-opacity-60 justify-center items-center inline-flex transition-all duration-300 hover:opacity-60 cursor-pointer"
>
<div className="flex flex-col items-center justify-center">
{loading ? (
<div className="flex items-center justify-center gap-2 animate-pulse">
<div className="text-white text-opacity-80 text-sm font-semibold py-1">
Importing
</div>
<div className="h-4 w-4 animate-spin rounded-full border-2 border-solid border-white border-t-transparent " />
</div>
) : !!result ? (
<div className="flex items-center justify-center gap-2">
<CloudArrowUp className="w-8 h-8 text-green-400" />
<div className="text-green-400 text-opacity-80 text-sm font-semibold py-1">
Import Successful
</div>
</div>
) : (
<>
<input
ref={inputRef}
onChange={handleUpload}
name="import"
type="file"
multiple="false"
accept=".zip"
hidden={true}
/>
<div className="flex flex-col items-center justify-center">
<CloudArrowUp className="w-8 h-8 text-white/80" />
<div className="text-white text-opacity-80 text-sm font-semibold py-1">
Import AnythingLLM Data
</div>
<div className="text-white text-opacity-60 text-xs font-medium py-1">
This must be an export from an AnythingLLM instance.
</div>
</div>
</>
)}
</div>
</div>
);
}
function ExportData() {
const [loading, setLoading] = useState(false);
const [result, setResult] = useState(null);
const exportData = async function () {
setLoading(true);
const { filename, error } = await System.dataExport();
setLoading(false);
if (!filename) {
showToast(`Failed to export data: ${error}`, "error");
} else {
setResult(filename);
const link = document.createElement("a");
link.href = `${API_BASE}/system/data-exports/${filename}`;
link.target = "_blank";
document.body.appendChild(link);
}
};
if (loading) {
return (
<button
onClick={exportData}
className="transition-all max-w-[600px] bg-white rounded-lg justify-center items-center my-8 text-zinc-900 border-transparent border-2 cursor-not-allowed animate-pulse"
>
<div className="flex items-center justify-center gap-2">
<div className="duration-300 text-center text-sm font-bold py-3">
Exporting
</div>
<div className="h-4 w-4 animate-spin rounded-full border-2 border-solid border-zinc-900 border-t-transparent " />
</div>
</button>
);
}
if (!!result) {
return (
<a
target="_blank"
href={`${API_BASE}/system/data-exports/${result}`}
className="transition-all max-w-[600px] bg-green-100 hover:bg-zinc-900/50 hover:text-white hover:border-white rounded-lg justify-center items-center my-8 text-zinc-900 border-transparent border-2 cursor-pointer"
>
<div className="flex items-center justify-center gap-2">
<div className="duration-300 text-center text-sm font-bold py-3">
Download Data Export
</div>
<DownloadSimple className="w-6 h-6" />
</div>
</a>
);
}
return (
<button
onClick={exportData}
className="transition-all max-w-[600px] bg-white rounded-lg justify-center items-center my-8 cursor-pointer text-zinc-900 border-transparent border-2 hover:bg-zinc-900/50 hover:text-white hover:border-white"
>
<div className="duration-300 text-center text-sm font-bold py-3">
Export AnythingLLM Data
</div>
</button>
);
}

View File

@ -56,9 +56,6 @@ export default {
return `/workspace/${slug}`;
},
},
exports: () => {
return `${API_BASE.replace("/api", "")}/system/data-exports`;
},
apiDocs: () => {
return `${API_BASE}/docs`;
},
@ -87,9 +84,6 @@ export default {
vectorDatabase: () => {
return "/settings/vector-database";
},
exportImport: () => {
return "/settings/export-import";
},
security: () => {
return "/settings/security";
},

View File

@ -2,7 +2,6 @@ process.env.NODE_ENV === "development"
? require("dotenv").config({ path: `.env.${process.env.NODE_ENV}` })
: require("dotenv").config();
const { viewLocalFiles, normalizePath } = require("../utils/files");
const { exportData, unpackAndOverwriteImport } = require("../utils/files/data");
const {
checkProcessorAlive,
acceptedFileTypes,
@ -389,55 +388,6 @@ function systemEndpoints(app) {
}
});
app.get(
"/system/data-export",
[validatedRequest, flexUserRoleValid],
async (_, response) => {
try {
const { filename, error } = await exportData();
response.status(200).json({ filename, error });
} catch (e) {
console.log(e.message, e);
response.sendStatus(500).end();
}
}
);
app.get("/system/data-exports/:filename", (request, response) => {
const exportLocation = __dirname + "/../storage/exports/";
const sanitized = normalizePath(request.params.filename);
const finalDestination = path.join(exportLocation, sanitized);
if (!fs.existsSync(finalDestination)) {
response.status(404).json({
error: 404,
msg: `File ${request.params.filename} does not exist in exports.`,
});
return;
}
response.download(finalDestination, request.params.filename, (err) => {
if (err) {
response.send({
error: err,
msg: "Problem downloading the file",
});
}
// delete on download because endpoint is not authenticated.
fs.rmSync(finalDestination);
});
});
app.post(
"/system/data-import",
handleImports.single("file"),
async function (request, response) {
const { originalname } = request.file;
const { success, error } = await unpackAndOverwriteImport(originalname);
response.status(200).json({ success, error });
}
);
app.get("/system/logo", async function (request, response) {
try {
const defaultFilename = getDefaultFilename();

View File

@ -4,7 +4,6 @@ process.env.NODE_ENV === "development"
const express = require("express");
const bodyParser = require("body-parser");
const serveIndex = require("serve-index");
const cors = require("cors");
const path = require("path");
const { reqBody } = require("./utils/http");
@ -85,11 +84,6 @@ if (process.env.NODE_ENV !== "development") {
});
}
app.use(
"/system/data-exports",
serveIndex(__dirname + "/storage/exports", { icons: true })
);
app.all("*", function (_, response) {
response.sendStatus(404);
});

View File

@ -52,7 +52,6 @@
"pinecone-client": "^1.1.0",
"posthog-node": "^3.1.1",
"prisma": "^5.3.1",
"serve-index": "^1.9.1",
"slugify": "^1.6.6",
"sqlite": "^4.2.1",
"sqlite3": "^5.1.6",

View File

@ -1,197 +0,0 @@
const fs = require("fs");
const path = require("path");
const { v4 } = require("uuid");
async function exportData() {
const uid = `anythingllm-export-${new Date()
.toJSON()
.slice(0, 10)}-${new Date().toJSON().slice(11, 19)}`;
const folder =
process.env.NODE_ENV === "development"
? path.resolve(__dirname, `../../storage/exports/${uid}`)
: path.resolve(process.env.STORAGE_DIR, `exports/${uid}`);
const storageBase =
process.env.NODE_ENV === "development"
? path.resolve(__dirname, `../../storage`)
: path.resolve(process.env.STORAGE_DIR);
try {
fs.mkdirSync(folder, { recursive: true });
if (fs.existsSync(path.resolve(storageBase, `documents`))) {
console.log("\x1b[34m[EXPORTING DATA]\x1b[0m Copying documents!");
fs.cpSync(
path.resolve(storageBase, `documents`),
path.resolve(folder, "documents"),
{ recursive: true }
);
}
if (fs.existsSync(path.resolve(storageBase, `lancedb`))) {
console.log("\x1b[34m[EXPORTING DATA]\x1b[0m Copying LanceDB data!");
fs.cpSync(
path.resolve(storageBase, `lancedb`),
path.resolve(folder, "lancedb"),
{ recursive: true }
);
}
if (fs.existsSync(path.resolve(storageBase, `vector-cache`))) {
console.log("\x1b[34m[EXPORTING DATA]\x1b[0m Copying vector cache!");
fs.cpSync(
path.resolve(storageBase, `vector-cache`),
path.resolve(folder, "vector-cache"),
{ recursive: true }
);
}
if (fs.existsSync(path.resolve(storageBase, `anythingllm.db`))) {
console.log(
"\x1b[34m[EXPORTING DATA]\x1b[0m Copying anythingllm database!"
);
fs.cpSync(
path.resolve(storageBase, `anythingllm.db`),
path.resolve(folder, "anythingllm.db")
);
}
await zipDirectory(folder, path.resolve(folder, `../${uid}.zip`));
fs.rmSync(folder, { recursive: true, force: true });
return { filename: `${uid}.zip`, error: null };
} catch (e) {
// If anything goes wrong - abort and clean up
console.error(e);
if (fs.existsSync(folder))
fs.rmSync(folder, { recursive: true, force: true });
return { filename: null, error: e.message };
}
}
async function unpackAndOverwriteImport(importFilename) {
const importFilepath =
process.env.NODE_ENV === "development"
? path.resolve(__dirname, `../../storage/imports/${importFilename}`)
: path.resolve(process.env.STORAGE_DIR, `imports/${importFilename}`);
if (!fs.existsSync(importFilepath))
return { success: false, error: "Import file does not exist." };
const uid = v4();
const outDir =
process.env.NODE_ENV === "development"
? path.resolve(__dirname, `../../storage/imports/${uid}`)
: path.resolve(process.env.STORAGE_DIR, `imports/${uid}`);
const storageBase =
process.env.NODE_ENV === "development"
? path.resolve(__dirname, `../../storage`)
: path.resolve(process.env.STORAGE_DIR);
try {
console.log(
"\x1b[34m[EXTRACTING DATA]\x1b[0m Extracting data from zip into storage!"
);
const unzipProc = await unzipDirectory(importFilepath, outDir);
if (!unzipProc.success) return unzipProc;
if (fs.existsSync(path.resolve(outDir, `documents`))) {
console.log(
"\x1b[34m[OVERWRITE & IMPORT DATA]\x1b[0m Importing documents!"
);
if (fs.existsSync(path.resolve(storageBase, `documents`)))
fs.rmSync(path.resolve(storageBase, `documents`), {
recursive: true,
force: true,
});
fs.cpSync(
path.resolve(outDir, `documents`),
path.resolve(storageBase, "documents"),
{ recursive: true }
);
}
if (fs.existsSync(path.resolve(outDir, `lancedb`))) {
console.log(
"\x1b[34m[OVERWRITE & IMPORT DATA]\x1b[0m Importing LanceDb!"
);
if (fs.existsSync(path.resolve(storageBase, `lancedb`)))
fs.rmSync(path.resolve(storageBase, `lancedb`), {
recursive: true,
force: true,
});
fs.cpSync(
path.resolve(outDir, `lancedb`),
path.resolve(storageBase, "lancedb"),
{ recursive: true }
);
}
if (fs.existsSync(path.resolve(outDir, `vector-cache`))) {
console.log(
"\x1b[34m[OVERWRITE & IMPORT DATA]\x1b[0m Importing Vector Cache!"
);
if (fs.existsSync(path.resolve(storageBase, `vector-cache`)))
fs.rmSync(path.resolve(storageBase, `vector-cache`), {
recursive: true,
force: true,
});
fs.cpSync(
path.resolve(outDir, `vector-cache`),
path.resolve(storageBase, "vector-cache"),
{ recursive: true }
);
}
if (fs.existsSync(path.resolve(outDir, `anythingllm.db`))) {
console.log(
"\x1b[34m[OVERWRITE & IMPORT DATA]\x1b[0m Importing AnythingLLM DB!"
);
if (fs.existsSync(path.resolve(storageBase, `anythingllm.db`)))
fs.rmSync(path.resolve(storageBase, `anythingllm.db`), { force: true });
fs.cpSync(
path.resolve(outDir, `anythingllm.db`),
path.resolve(storageBase, "anythingllm.db")
);
}
fs.rmSync(outDir, { recursive: true, force: true });
fs.rmSync(importFilepath, { force: true });
return { success: true, error: null };
} catch (e) {
console.error(e);
if (fs.existsSync(outDir))
fs.rmSync(outDir, { recursive: true, force: true });
if (fs.existsSync(importFilepath)) fs.rmSync(importFilepath);
return { success: false, error: e.message };
}
}
function zipDirectory(sourceDir, outPath) {
const archiver = require("archiver");
const archive = archiver("zip", { zlib: { level: 9 } });
const stream = fs.createWriteStream(outPath);
return new Promise((resolve, reject) => {
archive
.directory(sourceDir, false)
.on("error", (err) => reject(err))
.pipe(stream);
stream.on("close", () => resolve());
archive.finalize();
});
}
async function unzipDirectory(sourcePath, outDir) {
const extract = require("extract-zip");
try {
await extract(sourcePath, { dir: outDir });
return { success: true, error: null };
} catch (e) {
console.error("unzipToDirectory", e);
return { success: false, error: e.message };
}
}
module.exports = {
exportData,
unpackAndOverwriteImport,
};

View File

@ -891,7 +891,7 @@ abort-controller@^3.0.0:
dependencies:
event-target-shim "^5.0.0"
accepts@~1.3.4, accepts@~1.3.8:
accepts@~1.3.8:
version "1.3.8"
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
@ -1226,11 +1226,6 @@ base64-js@^1.3.0, base64-js@^1.3.1, base64-js@^1.5.1:
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
batch@0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16"
integrity sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==
bcrypt@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-5.1.0.tgz#bbb27665dbc400480a524d8991ac7434e8529e17"
@ -1855,11 +1850,6 @@ depd@2.0.0, depd@^2.0.0:
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
depd@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==
deprecation@^2.0.0, deprecation@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919"
@ -2895,16 +2885,6 @@ http-errors@2.0.0:
statuses "2.0.1"
toidentifier "1.0.1"
http-errors@~1.6.2:
version "1.6.3"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==
dependencies:
depd "~1.1.2"
inherits "2.0.3"
setprototypeof "1.1.0"
statuses ">= 1.4.0 < 2"
http-proxy-agent@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a"
@ -3003,11 +2983,6 @@ inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
inherits@2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==
ini@~1.3.0:
version "1.3.8"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
@ -3725,7 +3700,7 @@ mime-db@1.52.0:
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34:
mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34:
version "2.1.35"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
@ -4341,7 +4316,7 @@ parent-module@^1.0.0:
dependencies:
callsites "^3.0.0"
parseurl@~1.3.2, parseurl@~1.3.3:
parseurl@~1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
@ -4835,19 +4810,6 @@ send@0.18.0:
range-parser "~1.2.1"
statuses "2.0.1"
serve-index@^1.9.1:
version "1.9.1"
resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239"
integrity sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==
dependencies:
accepts "~1.3.4"
batch "0.6.1"
debug "2.6.9"
escape-html "~1.0.3"
http-errors "~1.6.2"
mime-types "~2.1.17"
parseurl "~1.3.2"
serve-static@1.15.0:
version "1.15.0"
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540"
@ -4882,11 +4844,6 @@ set-function-name@^2.0.0, set-function-name@^2.0.1:
functions-have-names "^1.2.3"
has-property-descriptors "^1.0.0"
setprototypeof@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
setprototypeof@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
@ -5029,11 +4986,6 @@ statuses@2.0.1:
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
"statuses@>= 1.4.0 < 2":
version "1.5.0"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==
stdin-discarder@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/stdin-discarder/-/stdin-discarder-0.1.0.tgz#22b3e400393a8e28ebf53f9958f3880622efde21"